chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class AnnualReturnsReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of annual returns
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public AnnualReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the annual returns plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestReturns = ResultsUtil.EquityPoints(_backtest);
|
||||
var liveReturns = ResultsUtil.EquityPoints(_live);
|
||||
|
||||
var backtestTime = backtestReturns.Keys.ToList();
|
||||
var backtestStrategy = backtestReturns.Values.ToList();
|
||||
|
||||
var liveTime = liveReturns.Keys.ToList();
|
||||
var liveStrategy = liveReturns.Values.ToList();
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
var liveList = new PyList();
|
||||
|
||||
// We need to set the datetime index first before we resample
|
||||
//var backtestSeries = Pandas.Series(backtestStrategy.ToPython());
|
||||
var backtestSeries = new Series<DateTime, double>(backtestTime, backtestStrategy);
|
||||
|
||||
// Get the annual returns for the strategy
|
||||
// ResampleEquivalence works similarly to Pandas' DataFrame.resample(...) method
|
||||
// Here we transform the series to resample to the year's start, then we get the aggregate return from the year.
|
||||
// Pandas equivalent:
|
||||
//
|
||||
// df.pct_change().resample('AS').sum().mul(100)
|
||||
var backtestAnnualReturns = backtestSeries.ResampleEquivalence(date => new DateTime(date.Year, 1, 1), agg => agg.TotalReturns() * 100).DropMissing();
|
||||
|
||||
// We need to set the datetime index first before we resample
|
||||
var liveSeries = new Series<DateTime, double>(liveTime, liveStrategy);
|
||||
|
||||
// Get the annual returns for the live strategy.
|
||||
// Same as above, this is equivalent to:
|
||||
//
|
||||
// df.pct_change().resample('AS').sum().mul(100)
|
||||
var liveAnnualReturns = liveSeries.ResampleEquivalence(date => new DateTime(date.Year, 1, 1), agg => agg.TotalReturns() * 100).DropMissing();
|
||||
|
||||
// Select only the year number and pass it to the plotting library
|
||||
backtestList.Append(backtestAnnualReturns.Keys.Select(x => x.Year).ToList().ToPython());
|
||||
backtestList.Append(backtestAnnualReturns.Values.ToList().ToPython());
|
||||
liveList.Append(liveAnnualReturns.Keys.Select(x => x.Year).ToList().ToPython());
|
||||
liveList.Append(liveAnnualReturns.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetAnnualReturns(backtestList, liveList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class AssetAllocationReportElement : ChartReportElement
|
||||
{
|
||||
private BacktestResult _backtest;
|
||||
private List<PointInTimePortfolio> _backtestPortfolios;
|
||||
private LiveResult _live;
|
||||
private List<PointInTimePortfolio> _livePortfolios;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the asset allocation over time
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="backtestPortfolios">Backtest point in time portfolios</param>
|
||||
/// <param name="livePortfolios">Live point in time portfolios</param>
|
||||
public AssetAllocationReportElement(
|
||||
string name,
|
||||
string key,
|
||||
BacktestResult backtest,
|
||||
LiveResult live,
|
||||
List<PointInTimePortfolio> backtestPortfolios,
|
||||
List<PointInTimePortfolio> livePortfolios)
|
||||
{
|
||||
_backtest = backtest;
|
||||
_backtestPortfolios = backtestPortfolios;
|
||||
_live = live;
|
||||
_livePortfolios = livePortfolios;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the asset allocation pie chart using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestSeries = Metrics.AssetAllocations(_backtestPortfolios);
|
||||
var liveSeries = Metrics.AssetAllocations(_livePortfolios);
|
||||
|
||||
PyObject result;
|
||||
|
||||
using (Py.GIL())
|
||||
{
|
||||
var data = new PyList();
|
||||
var liveData = new PyList();
|
||||
|
||||
data.Append(backtestSeries.SortBy(x => -x).Where(x => x.Value != 0).Keys.Select(x => x.Value).ToList().ToPython());
|
||||
data.Append(backtestSeries.SortBy(x => -x).Where(x => x.Value != 0).Values.ToList().ToPython());
|
||||
|
||||
liveData.Append(liveSeries.SortBy(x => -x).Where(x => x.Value != 0).Keys.Select(x => x.Value).ToList().ToPython());
|
||||
liveData.Append(liveSeries.SortBy(x => -x).Where(x => x.Value != 0).Values.ToList().ToPython());
|
||||
|
||||
result = Charting.GetAssetAllocation(data, liveData);
|
||||
}
|
||||
|
||||
var base64 = result.ConvertToDictionary<string, string>();
|
||||
if (base64.ContainsKey("Live Asset Allocation"))
|
||||
{
|
||||
return base64["Live Asset Allocation"];
|
||||
}
|
||||
|
||||
return base64["Backtest Asset Allocation"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Deedle;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class CAGRReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the CAGR of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public CAGRReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var equityCurve = _live == null
|
||||
? new Series<DateTime, double>(ResultsUtil.EquityPoints(_backtest))
|
||||
: DrawdownCollection.NormalizeResults(_backtest, _live);
|
||||
|
||||
if (equityCurve.IsEmpty)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var years = (decimal)(equityCurve.LastKey() - equityCurve.FirstKey()).TotalDays / 365m;
|
||||
|
||||
Result = Statistics.Statistics.CompoundingAnnualPerformance(
|
||||
equityCurve.FirstValue().SafeDecimalCast(),
|
||||
equityCurve.LastValue().SafeDecimalCast(),
|
||||
years);
|
||||
|
||||
return ((decimal?)Result)?.ToString("P1") ?? "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Python;
|
||||
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal abstract class ChartReportElement : ReportElement
|
||||
{
|
||||
internal static dynamic Charting;
|
||||
|
||||
/// <summary>
|
||||
/// Charting base class report element
|
||||
/// </summary>
|
||||
protected ChartReportElement()
|
||||
{
|
||||
PythonInitializer.Initialize();
|
||||
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic module = Py.Import("ReportCharts");
|
||||
var classObj = module.ReportCharts;
|
||||
|
||||
Charting = classObj.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Deedle;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
using System;
|
||||
using QuantConnect.Util;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class CumulativeReturnsReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new array of cumulative percentage return of strategy and benchmark
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public CumulativeReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the cumulative return of the backtest, benchmark, and live
|
||||
/// strategy using the ReportCharts.py python library
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestReturns = ResultsUtil.EquityPoints(_backtest);
|
||||
var benchmark = ResultsUtil.BenchmarkPoints(_backtest);
|
||||
var liveReturns = ResultsUtil.EquityPoints(_live);
|
||||
var liveBenchmark = ResultsUtil.BenchmarkPoints(_live);
|
||||
|
||||
var backtestTime = backtestReturns.Keys.ToList();
|
||||
var backtestStrategy = backtestReturns.Values.ToList();
|
||||
var benchmarkTime = benchmark.Keys.ToList();
|
||||
var benchmarkPoints = benchmark.Values.ToList();
|
||||
|
||||
var liveTime = liveReturns.Keys.ToList();
|
||||
var liveStrategy = liveReturns.Values.ToList();
|
||||
var liveBenchmarkTime = liveBenchmark.Keys.ToList();
|
||||
var liveBenchmarkStrategy = liveBenchmark.Values.ToList();
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
var liveList = new PyList();
|
||||
|
||||
var backtestSeries = new Series<DateTime, double>(backtestTime, backtestStrategy);
|
||||
var liveSeries = new Series<DateTime, double>(liveTime, liveStrategy);
|
||||
var backtestBenchmarkSeries = new Series<DateTime, double>(benchmarkTime, benchmarkPoints);
|
||||
var liveBenchmarkSeries = new Series<DateTime, double>(liveBenchmarkTime, liveBenchmarkStrategy);
|
||||
|
||||
// Equivalent in python using pandas for the following operations is:
|
||||
// --------------------------------------------------
|
||||
// >>> # note: [...] denotes the data we're passing in
|
||||
// >>> df = pd.Series([...], index=time)
|
||||
// >>> df_live = pd.Series([...], index=live_time)
|
||||
// >>> df_live = df_live.mul(df.iloc[-1] / df_live.iloc[0]).fillna(method='ffill').dropna()
|
||||
// >>> df_final = pd.concat([df, df_live], axis=0)
|
||||
// >>> df_cumulative_returns = ((df_final.pct_change().dropna() + 1).cumprod() - 1)
|
||||
// --------------------------------------------------
|
||||
//
|
||||
// We multiply the final value of the backtest and benchmark to have a continuous graph showing the performance out of sample
|
||||
// as a continuation of the cumulative returns graph. Otherwise, we start plotting from 0% and not the last value of the backtest data
|
||||
|
||||
var backtestLastValue = backtestSeries.ValueCount == 0 ? 0 : backtestSeries.LastValue();
|
||||
var backtestBenchmarkLastValue = backtestBenchmarkSeries.ValueCount == 0 ? 0 : backtestBenchmarkSeries.LastValue();
|
||||
|
||||
var liveContinuousEquity = liveSeries;
|
||||
var liveBenchContinuousEquity = liveBenchmarkSeries;
|
||||
|
||||
if (liveSeries.ValueCount != 0)
|
||||
{
|
||||
liveContinuousEquity = (liveSeries * (backtestLastValue / liveSeries.FirstValue()))
|
||||
.FillMissing(Direction.Forward)
|
||||
.DropMissing();
|
||||
}
|
||||
if (liveBenchmarkSeries.ValueCount != 0)
|
||||
{
|
||||
liveBenchContinuousEquity = (liveBenchmarkSeries * (backtestBenchmarkLastValue / liveBenchmarkSeries.FirstValue()))
|
||||
.FillMissing(Direction.Forward)
|
||||
.DropMissing();
|
||||
}
|
||||
|
||||
var liveStart = liveContinuousEquity.ValueCount == 0 ? DateTime.MaxValue : liveContinuousEquity.DropMissing().FirstKey();
|
||||
var liveBenchStart = liveBenchContinuousEquity.ValueCount == 0 ? DateTime.MaxValue : liveBenchContinuousEquity.DropMissing().FirstKey();
|
||||
|
||||
var finalEquity = backtestSeries.Where(kvp => kvp.Key < liveStart).Observations.ToList();
|
||||
var finalBenchEquity = backtestBenchmarkSeries.Where(kvp => kvp.Key < liveBenchStart).Observations.ToList();
|
||||
|
||||
finalEquity.AddRange(liveContinuousEquity.Observations);
|
||||
finalBenchEquity.AddRange(liveBenchContinuousEquity.Observations);
|
||||
|
||||
var finalSeries = (new Series<DateTime, double>(finalEquity).CumulativeReturns() * 100)
|
||||
.FillMissing(Direction.Forward)
|
||||
.DropMissing();
|
||||
|
||||
var finalBenchSeries = (new Series<DateTime, double>(finalBenchEquity).CumulativeReturns() * 100)
|
||||
.FillMissing(Direction.Forward)
|
||||
.DropMissing();
|
||||
|
||||
var backtestCumulativePercent = finalSeries.Where(kvp => kvp.Key < liveStart);
|
||||
var backtestBenchmarkCumulativePercent = finalBenchSeries.Where(kvp => kvp.Key < liveBenchStart);
|
||||
|
||||
var liveCumulativePercent = finalSeries.Where(kvp => kvp.Key >= liveStart);
|
||||
var liveBenchmarkCumulativePercent = finalBenchSeries.Where(kvp => kvp.Key >= liveBenchStart);
|
||||
|
||||
backtestList.Append(backtestCumulativePercent.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestCumulativePercent.Values.ToList().ToPython());
|
||||
backtestList.Append(backtestBenchmarkCumulativePercent.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestBenchmarkCumulativePercent.Values.ToList().ToPython());
|
||||
|
||||
liveList.Append(liveCumulativePercent.Keys.ToList().ToPython());
|
||||
liveList.Append(liveCumulativePercent.Values.ToList().ToPython());
|
||||
liveList.Append(liveBenchmarkCumulativePercent.Keys.ToList().ToPython());
|
||||
liveList.Append(liveBenchmarkCumulativePercent.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetCumulativeReturns(backtestList, liveList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class DailyReturnsReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the daily returns in bar chart format
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public DailyReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the daily returns plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestReturns = ResultsUtil.EquityPoints(_backtest);
|
||||
var liveReturns = ResultsUtil.EquityPoints(_live);
|
||||
|
||||
var backtestSeries = new Series<DateTime, double>(backtestReturns.Keys, backtestReturns.Values);
|
||||
var liveSeries = new Series<DateTime, double>(liveReturns.Keys, liveReturns.Values);
|
||||
|
||||
// The following two operations are equivalent to the Pandas `DataFrame.resample(...)` method
|
||||
var backtestResampled = backtestSeries.ResampleEquivalence(date => date.Date, s => s.LastValue()).PercentChange().DropMissing() * 100;
|
||||
var liveResampled = liveSeries.ResampleEquivalence(date => date.Date, s => s.LastValue()).PercentChange().DropMissing() * 100;
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
backtestList.Append(backtestResampled.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestResampled.Values.ToList().ToPython());
|
||||
|
||||
var liveList = new PyList();
|
||||
liveList.Append(liveResampled.Keys.ToList().ToPython());
|
||||
liveList.Append(liveResampled.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetDailyReturns(backtestList, liveList);
|
||||
|
||||
backtestList.Dispose();
|
||||
liveList.Dispose();
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class DrawdownReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the top N worst drawdown durations
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public DrawdownReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the top N drawdown plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestPoints = ResultsUtil.EquityPoints(_backtest);
|
||||
var livePoints = ResultsUtil.EquityPoints(_live);
|
||||
|
||||
var liveSeries = new Series<DateTime, double>(livePoints.Keys, livePoints.Values);
|
||||
var strategySeries = DrawdownCollection.NormalizeResults(_backtest, _live);
|
||||
|
||||
var seriesUnderwaterPlot = DrawdownCollection.GetUnderwater(strategySeries).DropMissing();
|
||||
var liveUnderwaterPlot = backtestPoints.Count == 0 ? seriesUnderwaterPlot : seriesUnderwaterPlot.After(backtestPoints.Last().Key);
|
||||
var drawdownCollection = DrawdownCollection.FromResult(_backtest, _live, periods: 5);
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
|
||||
if (liveUnderwaterPlot.IsEmpty)
|
||||
{
|
||||
backtestList.Append(seriesUnderwaterPlot.Keys.ToList().ToPython());
|
||||
backtestList.Append(seriesUnderwaterPlot.Values.ToList().ToPython());
|
||||
}
|
||||
else
|
||||
{
|
||||
backtestList.Append(seriesUnderwaterPlot.Before(liveUnderwaterPlot.FirstKey()).Keys.ToList().ToPython());
|
||||
backtestList.Append(seriesUnderwaterPlot.Before(liveUnderwaterPlot.FirstKey()).Values.ToList().ToPython());
|
||||
}
|
||||
|
||||
var liveList = new PyList();
|
||||
liveList.Append(liveUnderwaterPlot.Keys.ToList().ToPython());
|
||||
liveList.Append(liveUnderwaterPlot.Values.ToList().ToPython());
|
||||
|
||||
var worstList = new PyList();
|
||||
var previousDrawdownPeriods = new List<KeyValuePair<DateTime, DateTime>>();
|
||||
|
||||
foreach (var group in drawdownCollection.Drawdowns)
|
||||
{
|
||||
// Skip drawdown periods that are overlapping
|
||||
if (previousDrawdownPeriods.Where(kvp => (group.Start >= kvp.Key && group.Start <= kvp.Value) || (group.End >= kvp.Key && group.End <= kvp.Value)).Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var worst = new PyDict();
|
||||
worst.SetItem("Begin", group.Start.ToPython());
|
||||
worst.SetItem("End", group.End.ToPython());
|
||||
worst.SetItem("Total", group.PeakToTrough.ToPython());
|
||||
|
||||
worstList.Append(worst);
|
||||
previousDrawdownPeriods.Add(new KeyValuePair<DateTime, DateTime>(group.Start, group.End));
|
||||
}
|
||||
|
||||
base64 = Charting.GetDrawdown(backtestList, liveList, worstList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Capacity Estimation Report Element
|
||||
/// </summary>
|
||||
public sealed class EstimatedCapacityReportElement : ReportElement
|
||||
{
|
||||
private readonly BacktestResult _backtest;
|
||||
private readonly LiveResult _live;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new capacity estimate
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public EstimatedCapacityReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render element
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var statistics = _backtest?.Statistics;
|
||||
string capacityWithCurrency;
|
||||
if (statistics == null || !statistics.TryGetValue("Estimated Strategy Capacity", out capacityWithCurrency))
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var capacity = Currencies.Parse(capacityWithCurrency).RoundToSignificantDigits(2);
|
||||
|
||||
Result = capacity;
|
||||
|
||||
if (capacity == 0m)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
return capacity.ToFinancialFigures();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class ExposureReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
private List<PointInTimePortfolio> _backtestPortfolios;
|
||||
private List<PointInTimePortfolio> _livePortfolios;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the exposure
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="backtestPortfolios">Backtest point in time portfolios</param>
|
||||
/// <param name="livePortfolios">Live point in time portfolios</param>
|
||||
public ExposureReportElement(
|
||||
string name,
|
||||
string key,
|
||||
BacktestResult backtest,
|
||||
LiveResult live,
|
||||
List<PointInTimePortfolio> backtestPortfolios,
|
||||
List<PointInTimePortfolio> livePortfolios)
|
||||
{
|
||||
_backtest = backtest;
|
||||
_backtestPortfolios = backtestPortfolios;
|
||||
_live = live;
|
||||
_livePortfolios = livePortfolios;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the exposure plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var longBacktestFrame = Metrics.Exposure(_backtestPortfolios, OrderDirection.Buy);
|
||||
var shortBacktestFrame = Metrics.Exposure(_backtestPortfolios, OrderDirection.Sell);
|
||||
var longLiveFrame = Metrics.Exposure(_livePortfolios, OrderDirection.Buy);
|
||||
var shortLiveFrame = Metrics.Exposure(_livePortfolios, OrderDirection.Sell);
|
||||
|
||||
var backtestFrame = longBacktestFrame.Join(shortBacktestFrame)
|
||||
.FillMissing(Direction.Forward)
|
||||
.FillMissing(0.0);
|
||||
|
||||
var liveFrame = longLiveFrame.Join(shortLiveFrame)
|
||||
.FillMissing(Direction.Forward)
|
||||
.FillMissing(0.0);
|
||||
|
||||
longBacktestFrame = Frame.CreateEmpty<DateTime, Tuple<SecurityType, OrderDirection>>();
|
||||
shortBacktestFrame = Frame.CreateEmpty<DateTime, Tuple<SecurityType, OrderDirection>>();
|
||||
longLiveFrame = Frame.CreateEmpty<DateTime, Tuple<SecurityType, OrderDirection>>();
|
||||
shortLiveFrame = Frame.CreateEmpty<DateTime, Tuple<SecurityType, OrderDirection>>();
|
||||
|
||||
foreach (var key in backtestFrame.ColumnKeys)
|
||||
{
|
||||
longBacktestFrame[key] = backtestFrame[key].SelectValues(x => x < 0 ? 0 : x);
|
||||
shortBacktestFrame[key] = backtestFrame[key].SelectValues(x => x > 0 ? 0 : x);
|
||||
}
|
||||
|
||||
foreach (var key in liveFrame.ColumnKeys)
|
||||
{
|
||||
longLiveFrame[key] = liveFrame[key].SelectValues(x => x < 0 ? 0 : x);
|
||||
shortLiveFrame[key] = liveFrame[key].SelectValues(x => x > 0 ? 0 : x);
|
||||
}
|
||||
|
||||
longBacktestFrame = longBacktestFrame.DropSparseColumnsAll();
|
||||
shortBacktestFrame = shortBacktestFrame.DropSparseColumnsAll();
|
||||
longLiveFrame = longLiveFrame.DropSparseColumnsAll();
|
||||
shortLiveFrame = shortLiveFrame.DropSparseColumnsAll();
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var time = backtestFrame.RowKeys.ToList().ToPython();
|
||||
var longSecurities = longBacktestFrame.ColumnKeys.Select(x => x.Item1.ToStringInvariant()).ToList().ToPython();
|
||||
var shortSecurities = shortBacktestFrame.ColumnKeys.Select(x => x.Item1.ToStringInvariant()).ToList().ToPython();
|
||||
var longData = longBacktestFrame.ColumnKeys.Select(x => longBacktestFrame[x].Values.ToList().ToPython()).ToPython();
|
||||
var shortData = shortBacktestFrame.ColumnKeys.Select(x => shortBacktestFrame[x].Values.ToList().ToPython()).ToPython();
|
||||
var liveTime = liveFrame.RowKeys.ToList().ToPython();
|
||||
var liveLongSecurities = longLiveFrame.ColumnKeys.Select(x => x.Item1.ToStringInvariant()).ToList().ToPython();
|
||||
var liveShortSecurities = shortLiveFrame.ColumnKeys.Select(x => x.Item1.ToStringInvariant()).ToList().ToPython();
|
||||
var liveLongData = longLiveFrame.ColumnKeys.Select(x => longLiveFrame[x].Values.ToList().ToPython()).ToPython();
|
||||
var liveShortData = shortLiveFrame.ColumnKeys.Select(x => shortLiveFrame[x].Values.ToList().ToPython()).ToPython();
|
||||
|
||||
base64 = Charting.GetExposure(
|
||||
time,
|
||||
longSecurities,
|
||||
shortSecurities,
|
||||
longData,
|
||||
shortData,
|
||||
liveTime,
|
||||
liveLongSecurities,
|
||||
liveShortSecurities,
|
||||
liveLongData,
|
||||
liveShortData
|
||||
);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Common interface for template elements of the report
|
||||
/// </summary>
|
||||
internal interface IReportElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of this report element
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Template key code.
|
||||
/// </summary>
|
||||
string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
string Render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class InformationRatioReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the information ratio of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public InformationRatioReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var informationRatio = _backtest?.TotalPerformance?.PortfolioStatistics?.InformationRatio;
|
||||
Result = informationRatio;
|
||||
return informationRatio?.ToString("F1") ?? "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class LeverageUtilizationReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
private List<PointInTimePortfolio> _backtestPortfolios;
|
||||
private List<PointInTimePortfolio> _livePortfolios;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the leverage utilization
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="backtestPortfolios">Backtest point in time portfolios</param>
|
||||
/// <param name="livePortfolios">Live point in time portfolios</param>
|
||||
public LeverageUtilizationReportElement(
|
||||
string name,
|
||||
string key,
|
||||
BacktestResult backtest,
|
||||
LiveResult live,
|
||||
List<PointInTimePortfolio> backtestPortfolios,
|
||||
List<PointInTimePortfolio> livePortfolios)
|
||||
{
|
||||
_backtest = backtest;
|
||||
_backtestPortfolios = backtestPortfolios;
|
||||
_live = live;
|
||||
_livePortfolios = livePortfolios;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the leverage utilization plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestSeries = Metrics.LeverageUtilization(_backtestPortfolios).FillMissing(Direction.Forward);
|
||||
var liveSeries = Metrics.LeverageUtilization(_livePortfolios).FillMissing(Direction.Forward);
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
var liveList = new PyList();
|
||||
|
||||
backtestList.Append(backtestSeries.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestSeries.Values.ToList().ToPython());
|
||||
|
||||
liveList.Append(liveSeries.Keys.ToList().ToPython());
|
||||
liveList.Append(liveSeries.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetLeverage(backtestList, liveList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class MarketsReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Get the markets of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public MarketsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var liveOrders = _live?.Orders?.Values.ToList();
|
||||
if (liveOrders == null)
|
||||
{
|
||||
liveOrders = new List<Order>();
|
||||
}
|
||||
|
||||
var orders = new List<Order>();
|
||||
var backtestOrders = _backtest?.Orders?.Values;
|
||||
if (backtestOrders != null)
|
||||
{
|
||||
orders = backtestOrders.ToList();
|
||||
}
|
||||
|
||||
orders = orders.Union(liveOrders).ToList();
|
||||
|
||||
var securityTypes = orders.DistinctBy(o => o.SecurityType).Select(s => s.SecurityType.ToString()).ToList();
|
||||
Result = securityTypes;
|
||||
|
||||
return string.Join(",", securityTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class MaxDrawdownRecoveryReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _liveResult;
|
||||
private BacktestResult _backtestResult;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the max drawdown of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtestResult">Backtest result object</param>
|
||||
/// <param name="liveResult">Live result object</param>
|
||||
public MaxDrawdownRecoveryReportElement(string name, string key, BacktestResult backtestResult, LiveResult liveResult)
|
||||
{
|
||||
_liveResult = liveResult;
|
||||
_backtestResult = backtestResult;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
if (_liveResult == null)
|
||||
{
|
||||
var backtestDrawdownRecovery = _backtestResult?.TotalPerformance?.PortfolioStatistics?.DrawdownRecovery;
|
||||
Result = backtestDrawdownRecovery;
|
||||
return backtestDrawdownRecovery?.ToStringInvariant() ?? "-";
|
||||
}
|
||||
var equityCurve = new SortedDictionary<DateTime, decimal>(DrawdownCollection.NormalizeResults(_backtestResult, _liveResult)
|
||||
.Observations
|
||||
.ToDictionary(kvp => kvp.Key, kvp => (decimal)kvp.Value));
|
||||
|
||||
var maxDrawdownRecovery = Statistics.Statistics.CalculateDrawdownMetrics(equityCurve).DrawdownRecovery;
|
||||
Result = maxDrawdownRecovery;
|
||||
|
||||
return $"{maxDrawdownRecovery}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class MaxDrawdownReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the max drawdown of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public MaxDrawdownReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
if (_live == null)
|
||||
{
|
||||
var backtestDrawdown = _backtest?.TotalPerformance?.PortfolioStatistics?.Drawdown;
|
||||
Result = backtestDrawdown;
|
||||
return backtestDrawdown?.ToString("P1") ?? "-";
|
||||
}
|
||||
|
||||
var equityCurve = new SortedDictionary<DateTime, decimal>(DrawdownCollection.NormalizeResults(_backtest, _live)
|
||||
.Observations
|
||||
.ToDictionary(kvp => kvp.Key, kvp => (decimal)kvp.Value));
|
||||
|
||||
var maxDrawdown = Statistics.Statistics.CalculateDrawdownMetrics(equityCurve).Drawdown;
|
||||
Result = maxDrawdown;
|
||||
|
||||
return $"{maxDrawdown:P1}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class MonthlyReturnsReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a monthly returns plot
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public MonthlyReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the monthly returns plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestPoints = ResultsUtil.EquityPoints(_backtest);
|
||||
var livePoints = ResultsUtil.EquityPoints(_live);
|
||||
|
||||
var backtestSeries = new Series<DateTime, double>(backtestPoints.Keys, backtestPoints.Values);
|
||||
var liveSeries = new Series<DateTime, double>(livePoints.Keys, livePoints.Values);
|
||||
|
||||
// Equivalent to python pandas line: `backtestSeries.resample('M').apply(lambda x: x.pct_change().sum())`
|
||||
var backtestMonthlyReturns = backtestSeries.ResampleEquivalence(date => new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1))
|
||||
.Select(kvp => kvp.Value.TotalReturns());
|
||||
|
||||
var liveMonthlyReturns = liveSeries.ResampleEquivalence(date => new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1))
|
||||
.Select(kvp => kvp.Value.TotalReturns());
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestResults = new PyDict();
|
||||
foreach (var kvp in backtestMonthlyReturns.GroupBy(kvp => kvp.Key.Year).GetObservations())
|
||||
{
|
||||
var key = kvp.Key.ToStringInvariant();
|
||||
var monthlyReturns = kvp.Value * 100;
|
||||
|
||||
var values = new List<double>();
|
||||
for (var i = 1; i <= 12; i++)
|
||||
{
|
||||
var returns = monthlyReturns.Where(row => row.Key.Month == i);
|
||||
if (!returns.IsEmpty)
|
||||
{
|
||||
values.Add(returns.FirstValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
values.Add(double.NaN);
|
||||
}
|
||||
|
||||
backtestResults.SetItem(key.ToPython(), values.ToPython());
|
||||
}
|
||||
|
||||
var liveResults = new PyDict();
|
||||
foreach (var kvp in liveMonthlyReturns.GroupBy(kvp => kvp.Key.Year).GetObservations())
|
||||
{
|
||||
var key = kvp.Key.ToStringInvariant();
|
||||
var monthlyReturns = kvp.Value * 100;
|
||||
|
||||
var values = new List<double>();
|
||||
for (var i = 1; i <= 12; i++)
|
||||
{
|
||||
var returns = monthlyReturns.Where(row => row.Key.Month == i);
|
||||
if (!returns.IsEmpty)
|
||||
{
|
||||
values.Add(returns.FirstValue());
|
||||
continue;
|
||||
}
|
||||
|
||||
values.Add(double.NaN);
|
||||
}
|
||||
|
||||
liveResults.SetItem(key.ToPython(), values.ToPython());
|
||||
}
|
||||
|
||||
base64 = Charting.GetMonthlyReturns(backtestResults, liveResults);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class PSRReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// The number of trading days per year to get better result of statistics
|
||||
/// </summary>
|
||||
private int _tradingDaysPerYear;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the PSR of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
public PSRReportElement(string name, string key, BacktestResult backtest, LiveResult live, int tradingDaysPerYear)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
_tradingDaysPerYear = tradingDaysPerYear;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
decimal? psr;
|
||||
if (_live == null)
|
||||
{
|
||||
psr = _backtest?.TotalPerformance?.PortfolioStatistics?.ProbabilisticSharpeRatio;
|
||||
Result = psr;
|
||||
if (psr == null)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
return $"{psr:P0}";
|
||||
}
|
||||
|
||||
var equityCurvePerformance = DrawdownCollection.NormalizeResults(_backtest, _live)
|
||||
.ResampleEquivalence(date => date.Date, s => s.LastValue())
|
||||
.PercentChange();
|
||||
|
||||
if (equityCurvePerformance.IsEmpty || equityCurvePerformance.KeyCount < 180)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var sixMonthsBefore = equityCurvePerformance.LastKey() - TimeSpan.FromDays(180);
|
||||
// Skip weekends so we stay on a trading-day basis. The risk-free rate below is deannualized by
|
||||
// tradingDaysPerYear, so leaving calendar days in would deduct it over ~365 days a year and over-deduct the rate
|
||||
var lastSixMonthsPerformance = equityCurvePerformance.Where(kvp => kvp.Key >= sixMonthsBefore
|
||||
&& kvp.Key.DayOfWeek != DayOfWeek.Saturday
|
||||
&& kvp.Key.DayOfWeek != DayOfWeek.Sunday);
|
||||
|
||||
var benchmarkSharpeRatio = 1.0d / Math.Sqrt(_tradingDaysPerYear);
|
||||
// Use the same excess-return basis as the reported PSR by subtracting the deannualized risk-free rate
|
||||
var riskFreeRate = new InterestRateProvider().GetAverageRiskFreeRate(lastSixMonthsPerformance.Keys);
|
||||
psr = Statistics.Statistics.ProbabilisticSharpeRatio(
|
||||
lastSixMonthsPerformance
|
||||
.Values
|
||||
.ToList(),
|
||||
benchmarkSharpeRatio,
|
||||
(double)riskFreeRate / _tradingDaysPerYear)
|
||||
.SafeDecimalCast();
|
||||
|
||||
Result = psr;
|
||||
return $"{psr:P0}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for creating a two column table for the Algorithm's Parameters in a report
|
||||
/// </summary>
|
||||
public class ParametersReportElement : ReportElement
|
||||
{
|
||||
private IReadOnlyDictionary<string, string> _parameters;
|
||||
private readonly string _template;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a two column table for the Algorithm's Parameters
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtestConfiguration">The configuration of the backtest algorithm</param>
|
||||
/// <param name="liveConfiguration">The configuration of the live algorithm</param>
|
||||
/// <param name="template">HTML template to use</param>
|
||||
public ParametersReportElement(string name, string key, AlgorithmConfiguration backtestConfiguration, AlgorithmConfiguration liveConfiguration, string template)
|
||||
{
|
||||
Name = name;
|
||||
Key = key;
|
||||
_template = template;
|
||||
|
||||
if (liveConfiguration != null)
|
||||
{
|
||||
_parameters = liveConfiguration.Parameters;
|
||||
}
|
||||
else if (backtestConfiguration != null)
|
||||
{
|
||||
_parameters = backtestConfiguration.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This case only happens for the unit tests, then we just create an empty dictionary
|
||||
_parameters = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a HTML two column table for the Algorithm's Parameters
|
||||
/// </summary>
|
||||
/// <returns>Returns a string representing a HTML two column table</returns>
|
||||
public override string Render()
|
||||
{
|
||||
var items = new List<string>();
|
||||
int parameterIndex;
|
||||
var columns = (new Regex(@"{{\$KEY(\d+?)}}")).Matches(_template).Count;
|
||||
|
||||
for (parameterIndex = 0; parameterIndex < _parameters.Count;)
|
||||
{
|
||||
var template = _template;
|
||||
int column;
|
||||
for (column = 0; column < columns; column++)
|
||||
{
|
||||
var currTemplateKey = "{{$KEY" + column.ToString() + "}}";
|
||||
var currTemplateValue = "{{$VALUE" + column.ToString() + "}}";
|
||||
|
||||
if (parameterIndex < _parameters.Count)
|
||||
{
|
||||
var parameter = _parameters.ElementAt(parameterIndex);
|
||||
template = template.Replace(currTemplateKey, parameter.Key);
|
||||
template = template.Replace(currTemplateValue, parameter.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
template = template.Replace(currTemplateKey, string.Empty);
|
||||
template = template.Replace(currTemplateValue, string.Empty);
|
||||
}
|
||||
|
||||
parameterIndex++;
|
||||
}
|
||||
|
||||
if (column == 0)
|
||||
{
|
||||
parameterIndex++;
|
||||
}
|
||||
|
||||
items.Add(template);
|
||||
}
|
||||
|
||||
if (Key == ReportKey.ParametersPageStyle)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
{
|
||||
return "display: none;";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var parameters= string.Join("\n", items);
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Common interface for template elements of the report
|
||||
/// </summary>
|
||||
public abstract class ReportElement : IReportElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of this report element
|
||||
/// </summary>
|
||||
public virtual string Name { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Template key code.
|
||||
/// </summary>
|
||||
public virtual string Key { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes the key into a JSON-friendly key
|
||||
/// </summary>
|
||||
public string JsonKey => Key.Replace("KPI-", "").Replace("$", "").Replace("{", "").Replace("}", "") .ToLowerInvariant();
|
||||
|
||||
/// <summary>
|
||||
/// Result of the render as an object for serialization to JSON
|
||||
/// </summary>
|
||||
public virtual object Result { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public abstract string Render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Packets;
|
||||
using QuantConnect.Statistics;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class ReturnsPerTradeReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new distribution plot of returns per trade
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public ReturnsPerTradeReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the returns per trade plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestPercentagePerTrade = new List<double>();
|
||||
if (_backtest?.TotalPerformance?.ClosedTrades != null)
|
||||
{
|
||||
foreach (var trade in _backtest.TotalPerformance.ClosedTrades)
|
||||
{
|
||||
if (trade.EntryPrice == 0m)
|
||||
{
|
||||
Log.Error($"ReturnsPerTradeReportElement.Render(): Encountered entry price of 0 in trade with entry time: {trade.EntryTime:yyyy-MM-dd HH:mm:ss} - Exit time: {trade.ExitTime:yyyy-MM-dd HH::mm:ss}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var sideMultiplier = trade.Direction == TradeDirection.Long ? 1 : -1;
|
||||
backtestPercentagePerTrade.Add(sideMultiplier * (Convert.ToDouble(trade.ExitPrice) - Convert.ToDouble(trade.EntryPrice)) / Convert.ToDouble(trade.EntryPrice));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: LiveResult does not contain a TotalPerformance field, so skip live mode for now
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
// Charting library does not expect values to be in whole percentage values (i.e. not 1% == 1.0, but rather 1% == 0.01),
|
||||
base64 = Charting.GetReturnsPerTrade(backtestPercentagePerTrade.ToPython());
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Lean.Engine.Results;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class RollingPortfolioBetaReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// The number of trading days per year to get better result of statistics
|
||||
/// </summary>
|
||||
private int _tradingDaysPerYear;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the rolling portfolio beta to equities
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
public RollingPortfolioBetaReportElement(string name, string key, BacktestResult backtest, LiveResult live, int tradingDaysPerYear)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
_tradingDaysPerYear = tradingDaysPerYear;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the rolling portfolio beta to equities plot using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestPoints = GetReturnSeries(_backtest);
|
||||
var backtestBenchmarkPoints = ResultsUtil.BenchmarkPoints(_backtest);
|
||||
var livePoints = GetReturnSeries(_live);
|
||||
var liveBenchmarkPoints = ResultsUtil.BenchmarkPoints(_live);
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
var liveList = new PyList();
|
||||
|
||||
var backtestRollingBetaSixMonths = Rolling.Beta(backtestPoints, backtestBenchmarkPoints, windowSize: 22 * 6);
|
||||
var backtestRollingBetaTwelveMonths = Rolling.Beta(backtestPoints, backtestBenchmarkPoints, windowSize: _tradingDaysPerYear);
|
||||
|
||||
backtestList.Append(backtestRollingBetaSixMonths.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingBetaSixMonths.Values.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingBetaTwelveMonths.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingBetaTwelveMonths.Values.ToList().ToPython());
|
||||
|
||||
var liveRollingBetaSixMonths = Rolling.Beta(livePoints, liveBenchmarkPoints, windowSize: 22 * 6);
|
||||
var liveRollingBetaTwelveMonths = Rolling.Beta(livePoints, liveBenchmarkPoints, windowSize: _tradingDaysPerYear);
|
||||
|
||||
liveList.Append(liveRollingBetaSixMonths.Keys.ToList().ToPython());
|
||||
liveList.Append(liveRollingBetaSixMonths.Values.ToList().ToPython());
|
||||
liveList.Append(liveRollingBetaTwelveMonths.Keys.ToList().ToPython());
|
||||
liveList.Append(liveRollingBetaTwelveMonths.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetRollingBeta(backtestList, liveList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
private static SortedList<DateTime, double> GetReturnSeries(Result leanResult)
|
||||
{
|
||||
var returnSeries = ResultsUtil.EquityPoints(leanResult, BaseResultsHandler.ReturnKey);
|
||||
if (returnSeries == null || returnSeries.Count == 0)
|
||||
{
|
||||
// for backwards compatibility
|
||||
returnSeries = ResultsUtil.EquityPoints(leanResult, "Daily Performance");
|
||||
}
|
||||
return returnSeries;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Deedle;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class RollingSharpeReportElement : ChartReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// The number of trading days per year to get better result of statistics
|
||||
/// </summary>
|
||||
private int _tradingDaysPerYear;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new plot of the rolling sharpe ratio
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
public RollingSharpeReportElement(string name, string key, BacktestResult backtest, LiveResult live, int tradingDaysPerYear)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
_tradingDaysPerYear = tradingDaysPerYear;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the rolling sharpe using the python libraries.
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var backtestPoints = ResultsUtil.EquityPoints(_backtest);
|
||||
var livePoints = ResultsUtil.EquityPoints(_live);
|
||||
|
||||
var backtestSeries = new Series<DateTime, double>(backtestPoints);
|
||||
var liveSeries = new Series<DateTime, double>(livePoints);
|
||||
|
||||
var backtestRollingSharpeSixMonths = Rolling.Sharpe(backtestSeries, 6, _tradingDaysPerYear).DropMissing();
|
||||
var backtestRollingSharpeTwelveMonths = Rolling.Sharpe(backtestSeries, 12, _tradingDaysPerYear).DropMissing();
|
||||
var liveRollingSharpeSixMonths = Rolling.Sharpe(liveSeries, 6, _tradingDaysPerYear).DropMissing();
|
||||
var liveRollingSharpeTwelveMonths = Rolling.Sharpe(liveSeries, 12, _tradingDaysPerYear).DropMissing();
|
||||
|
||||
var base64 = "";
|
||||
using (Py.GIL())
|
||||
{
|
||||
var backtestList = new PyList();
|
||||
var liveList = new PyList();
|
||||
|
||||
backtestList.Append(backtestRollingSharpeSixMonths.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingSharpeSixMonths.Values.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingSharpeTwelveMonths.Keys.ToList().ToPython());
|
||||
backtestList.Append(backtestRollingSharpeTwelveMonths.Values.ToList().ToPython());
|
||||
|
||||
liveList.Append(liveRollingSharpeSixMonths.Keys.ToList().ToPython());
|
||||
liveList.Append(liveRollingSharpeSixMonths.Values.ToList().ToPython());
|
||||
liveList.Append(liveRollingSharpeTwelveMonths.Keys.ToList().ToPython());
|
||||
liveList.Append(liveRollingSharpeTwelveMonths.Values.ToList().ToPython());
|
||||
|
||||
base64 = Charting.GetRollingSharpeRatio(backtestList, liveList);
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal class RuntimeDaysReportElement : ReportElement
|
||||
{
|
||||
private BacktestResult _backtest;
|
||||
private LiveResult _live;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new metric describing the number of days an algorithm ran for.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public RuntimeDaysReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_backtest = backtest;
|
||||
_live = live;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var result = (Result) _live ?? _backtest;
|
||||
if (result == null)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var equityPoints = ResultsUtil.EquityPoints(result);
|
||||
if (equityPoints.Count == 0)
|
||||
{
|
||||
Result = 0;
|
||||
return "0";
|
||||
}
|
||||
|
||||
var days = (equityPoints.Last().Key - equityPoints.First().Key).Days;
|
||||
Result = days;
|
||||
|
||||
return days.ToStringInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Deedle;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for render the Sharpe Ratio statistic for a report
|
||||
/// </summary>
|
||||
public class SharpeRatioReportElement : ReportElement
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of trading days per year to get better result of statistics
|
||||
/// </summary>
|
||||
private double _tradingDaysPerYear;
|
||||
|
||||
/// <summary>
|
||||
/// Live result object
|
||||
/// </summary>
|
||||
protected LiveResult LiveResult { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Backtest result object
|
||||
/// </summary>
|
||||
protected BacktestResult BacktestResult { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sharpe Ratio from a backtest
|
||||
/// </summary>
|
||||
public virtual decimal? BacktestResultValue => BacktestResult?.TotalPerformance?.PortfolioStatistics?.SharpeRatio;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the sharpe ratio of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
public SharpeRatioReportElement(string name, string key, BacktestResult backtest, LiveResult live, int tradingDaysPerYear)
|
||||
{
|
||||
LiveResult = live;
|
||||
BacktestResult = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
_tradingDaysPerYear = Convert.ToDouble(tradingDaysPerYear, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
if (LiveResult == null)
|
||||
{
|
||||
Result = BacktestResultValue;
|
||||
return BacktestResultValue?.ToString("F1") ?? "-";
|
||||
}
|
||||
|
||||
var equityPoints = ResultsUtil.EquityPoints(LiveResult);
|
||||
var performance = DeedleUtil.PercentChange(new Series<DateTime, double>(equityPoints).ResampleEquivalence(date => date.Date, s => s.LastValue()));
|
||||
if (performance.ValueCount == 0)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var sixMonthsAgo = performance.LastKey().AddDays(-180);
|
||||
var trailingSeries = performance.Where(series => series.Key >= sixMonthsAgo && series.Key.DayOfWeek != DayOfWeek.Saturday && series.Key.DayOfWeek != DayOfWeek.Sunday);
|
||||
var trailingPerformance = trailingSeries
|
||||
.Values
|
||||
.ToList();
|
||||
|
||||
var annualStandardDeviation = trailingPerformance.Count < 7 ? 0 : GetAnnualStandardDeviation(trailingPerformance, _tradingDaysPerYear);
|
||||
if (annualStandardDeviation <= 0)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
// Use excess returns to stay consistent with the reported PSR and backtest Sharpe ratio
|
||||
var riskFreeRate = new InterestRateProvider().GetAverageRiskFreeRate(trailingSeries.Keys);
|
||||
var annualPerformance = Statistics.Statistics.AnnualPerformance(trailingPerformance, _tradingDaysPerYear);
|
||||
var liveResultValue = Statistics.Statistics.SharpeRatio(annualPerformance, annualStandardDeviation, (double)riskFreeRate);
|
||||
Result = liveResultValue;
|
||||
return liveResultValue.ToString("F2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get annual standard deviation
|
||||
/// </summary>
|
||||
/// <param name="trailingPerformance">The performance for the last period</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
/// <returns>Annual standard deviation.</returns>
|
||||
public virtual double GetAnnualStandardDeviation(List<double> trailingPerformance, double tradingDaysPerYear)
|
||||
{
|
||||
return Statistics.Statistics.AnnualStandardDeviation(trailingPerformance, tradingDaysPerYear);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using QuantConnect.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class SortinoRatioReportElement : SharpeRatioReportElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Sortino ratio from a backtest
|
||||
/// </summary>
|
||||
public override decimal? BacktestResultValue => BacktestResult?.TotalPerformance?.PortfolioStatistics?.SortinoRatio;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the Sortino ratio of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
public SortinoRatioReportElement(string name, string key, BacktestResult backtest, LiveResult live, int tradingDaysPerYear)
|
||||
: base(name, key, backtest, live, tradingDaysPerYear)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get annual standard deviation
|
||||
/// </summary>
|
||||
/// <param name="trailingPerformance">The performance for the last period</param>
|
||||
/// <param name="tradingDaysPerYear">The number of trading days per year to get better result of statistics</param>
|
||||
/// <returns>Annual downside standard deviation.</returns>
|
||||
public override double GetAnnualStandardDeviation(List<double> trailingPerformance, double tradingDaysPerYear)
|
||||
{
|
||||
return Statistics.Statistics.AnnualDownsideStandardDeviation(trailingPerformance, tradingDaysPerYear);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class TextReportElement : ReportElement
|
||||
{
|
||||
private readonly string _content;
|
||||
|
||||
/// <summary>
|
||||
/// Text place holder report element
|
||||
/// </summary>
|
||||
/// <param name="name">Name of this text field</param>
|
||||
/// <param name="key">Report injection point</param>
|
||||
/// <param name="content">Content for injection</param>
|
||||
public TextReportElement(string name, string key, string content)
|
||||
{
|
||||
Name = name;
|
||||
Key = key;
|
||||
_content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render the element contents
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string Render()
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class TradesPerDayReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the trades per day of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public TradesPerDayReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate trades per day
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var liveOrders = _live?.Orders?.Values.ToList();
|
||||
if (liveOrders == null)
|
||||
{
|
||||
liveOrders = new List<Order>();
|
||||
}
|
||||
|
||||
var orders = _backtest?.Orders?.Values.Concat(liveOrders).OrderBy(x => x.Time);
|
||||
if (orders == null)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
if (!orders.Any())
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var days = orders.Last().Time
|
||||
.Subtract(orders.First().Time)
|
||||
.TotalDays;
|
||||
|
||||
if (days == 0)
|
||||
{
|
||||
days = 1;
|
||||
}
|
||||
|
||||
var tradesPerDay = orders.Count() / days;
|
||||
Result = tradesPerDay;
|
||||
|
||||
if (tradesPerDay > 9)
|
||||
{
|
||||
return $"{tradesPerDay:F0}";
|
||||
}
|
||||
|
||||
return $"{tradesPerDay:F1}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using QuantConnect.Packets;
|
||||
|
||||
namespace QuantConnect.Report.ReportElements
|
||||
{
|
||||
internal sealed class TurnoverReportElement : ReportElement
|
||||
{
|
||||
private LiveResult _live;
|
||||
private BacktestResult _backtest;
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the turnover of the strategy.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the widget</param>
|
||||
/// <param name="key">Location of injection</param>
|
||||
/// <param name="backtest">Backtest result object</param>
|
||||
/// <param name="live">Live result object</param>
|
||||
public TurnoverReportElement(string name, string key, BacktestResult backtest, LiveResult live)
|
||||
{
|
||||
_live = live;
|
||||
_backtest = backtest;
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The generated output string to be injected
|
||||
/// </summary>
|
||||
public override string Render()
|
||||
{
|
||||
var turnover = _backtest?.TotalPerformance?.PortfolioStatistics?.PortfolioTurnover;
|
||||
Result = turnover;
|
||||
if (turnover == null)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
return $"{turnover:P0}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user