Backtests

Reading Results

Introduction

This page explains how to get backtest results into the Research Environment with the QuantConnect API.

Prerequisites

Working knowledge of C#.

Working knowledge of Python of working with pandas DataFrames and Series. If you are not familiar with pandas, refer to the pandas documentation.

Read Backtest Instance

To get the results of a backtest, call the ReadBacktest method with the project ID and backtest ID.

#load "../Initialize.csx"
#load "../QuantConnect.csx"

using QuantConnect;
using QuantConnect.Api;

var backtest = api.ReadBacktest(projectId, backtestId);
backtest = api.ReadBacktest(project_id, backtest_id)

Note that this method returns a snapshot of the backtest at the current moment. If the backtest is still executing, the result won't include all of the backtest data.

The ReadBacktest method returns a Backtest object, which have the following attributes:

Metadata

To view the metadata of a backtest, get the backtest result and then print out the metadata attributes.

Console.WriteLine($@"Backtest ID: {backtest.BacktestId}
Name: {backtest.Name}
Created Time: {backtest.Created}
Success?: {backtest.Success}
Completed?: {backtest.Completed}
Progress [0,1]: {backtest.Progress}
Note: {backtest.Note}")
print(f"""Backtest ID: {backtest.BacktestId}
Name: {backtest.Name}
Created Time: {backtest.Created.strftime("%Y/%m/%d %H:%M:%S")}
Success?: {backtest.Success}
Completed?: {backtest.Completed}
Progress [0,1]: {backtest.Progress}
Note: {backtest.Note}\n""")

Errors

To view the errors of a backtest, get the backtest result and then print the Error and StackTrace attributes.

Console.WriteLine($@"Error: {backtest.Error}
Stacktrace: {backtest.StackTrace}")
print(f"""Error: {backtest.Error}
Stacktrace: {backtest.StackTrace}""")

Statistics

Backtest statistics are available once the backtest completes. To view the statistics of a backtest, get the backtest result and then follow these steps:

  1. Print the Statistics attribute.
  2. foreach(var kvp in backtest.Statistics)
    { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); }
    for kvp in backtest.Statistics:
    print(f"{kvp.Key}: {kvp.Value}")
  3. Print the RuntimeStatistics attribute.
  4. foreach(var kvp in backtest.RuntimeStatistics)
    { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); }
    for kvp in backtest.RuntimeStatistics:
    print(f"{kvp.Key}: {kvp.Value}")
  5. Print the AlphaRuntimeStatistics attribute.
  6. foreach(var kvp in backtest.AlphaRuntimeStatistics.ToDictionary())
    { Console.WriteLine($"{kvp.Key}: {kvp.Value}"); }
    for kvp in backtest.AlphaRuntimeStatistics.ToDictionary():
    print(f"{kvp.Key}: {kvp.Value}")

Charts

To view the charts of a backtest, get the backtest result and then follow these steps:

  1. Save the Charts attribute of the backtest result.
  2. var charts = backtest.Charts;
    charts = backtest.Charts
  3. Index the chart object with the chart name.
  4. var equityChart = charts["Strategy Equity"];
    var drawdownChart = charts["Drawdown"];
    var exposureChart = charts["Exposure"];
    equity_chart = charts["Strategy Equity"]
    drawdown_chart = charts["Drawdown"]
    exposure_chart = charts["Exposure"]
  5. Index the Series attribute of the charts with the series name.
  6. var equitySeries = equityChart.Series["Equity"].Values;
    var drawdownSeries = drawdownChart.Series["Equity Drawdown"].Values;
    equity_series = equity_chart.Series["Equity"].Values
    drawdown_series = drawdown_chart.Series["Equity Drawdown"].Values
  7. Iterate each data point of each series and store them in Dictionary objects.
  8. var equityData = equitySeries
                     .Where(kvp => kvp != null)
                     .ToDictionary(kvp => kvp.x, kvp => kvp.y);
    var drawdownData = drawdownSeries
                       .Where(kvp => kvp != null)
                       .ToDictionary(kvp => kvp.x, kvp => kvp.y);
    var exposureData = new Dictionary<string, Dictionary<long, decimal>>();
    foreach(var col in exposureChart.Series.Keys)
    {
        exposureData[col] = new Dictionary<long, decimal>();
        foreach(var kvp in exposureChart.Series[col].Values)
        {
            if (kvp != null)
            {
                exposureData[col].Add(kvp.x, kvp.y);
            }
        }
    }
    equity_data = {kvp.x: kvp.y for kvp in equity_series if kvp}
    drawdown_data = {kvp.x: kvp.y for kvp in drawdown_series if kvp}
    exposure_data = {}
    for col in exposure_chart.Series.Keys:
        series = {}
        for kvp in exposure_chart.Series[col].Values:
            if not kvp: continue
            series[kvp.x] = kvp.y
        exposure_data[col] = series
  9. Display the data.
  10. Console.WriteLine("Equity Curve:");
    foreach(var kvp in equityData.Take(5))
    {
        var time = DateTimeOffset.FromUnixTimeSeconds(kvp.Key).DateTime;
        Console.WriteLine($"{time} : {kvp.Value}");
    }
    Console.WriteLine("Drawdown %:");
    foreach(var kvp in drawdownData.Take(5))
    {
        var time = DateTimeOffset.FromUnixTimeSeconds(kvp.Key).DateTime;
        Console.WriteLine($"{time} : {kvp.Value}");
    }
    foreach(var kvpExposure in exposureData)
    {
        Console.WriteLine($"{kvpExposure.Key} Exposure:");
        foreach(var kvp in kvpExposure.Value.Take(5))
        {
            var time = DateTimeOffset.FromUnixTimeSeconds(kvp.Key).DateTime;
            Console.WriteLine($"{time} : {kvp.Value}");
        }
    }
  11. Convert the dictionaries into Series and DataFrame objects.
  12. equity_data = pd.Series(equity_data)
    drawdown_data = pd.Series(drawdown_data)
    exposure_data = pd.DataFrame(exposure_data)
  13. Call the plot method on each pandas object.
  14. equity_data.plot(figsize=(10, 6), title="Equity Curve")
    plt.show()
    drawdown_data.plot(figsize=(10, 6), title="Underwater Plot")
    plt.show()
    exposure_data.plot(figsize=(10, 6), title="Exposure")
    plt.show()

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: