Lean  $LEAN_TAG$
MonthlyReturnsReportElement.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
19 using Deedle;
20 using Python.Runtime;
21 using QuantConnect.Packets;
22 
24 {
25  internal sealed class MonthlyReturnsReportElement : ChartReportElement
26  {
27  private LiveResult _live;
28  private BacktestResult _backtest;
29 
30  /// <summary>
31  /// Create a monthly returns plot
32  /// </summary>
33  /// <param name="name">Name of the widget</param>
34  /// <param name="key">Location of injection</param>
35  /// <param name="backtest">Backtest result object</param>
36  /// <param name="live">Live result object</param>
37  public MonthlyReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
38  {
39  _live = live;
40  _backtest = backtest;
41  Name = name;
42  Key = key;
43  }
44 
45  /// <summary>
46  /// Generate the monthly returns plot using the python libraries.
47  /// </summary>
48  public override string Render()
49  {
50  var backtestPoints = ResultsUtil.EquityPoints(_backtest);
51  var livePoints = ResultsUtil.EquityPoints(_live);
52 
53  var backtestSeries = new Series<DateTime, double>(backtestPoints.Keys, backtestPoints.Values);
54  var liveSeries = new Series<DateTime, double>(livePoints.Keys, livePoints.Values);
55 
56  // Equivalent to python pandas line: `backtestSeries.resample('M').apply(lambda x: x.pct_change().sum())`
57  var backtestMonthlyReturns = backtestSeries.ResampleEquivalence(date => new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1))
58  .Select(kvp => kvp.Value.TotalReturns());
59 
60  var liveMonthlyReturns = liveSeries.ResampleEquivalence(date => new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1))
61  .Select(kvp => kvp.Value.TotalReturns());
62 
63  var base64 = "";
64  using (Py.GIL())
65  {
66  var backtestResults = new PyDict();
67  foreach (var kvp in backtestMonthlyReturns.GroupBy(kvp => kvp.Key.Year).GetObservations())
68  {
69  var key = kvp.Key.ToStringInvariant();
70  var monthlyReturns = kvp.Value * 100;
71 
72  var values = new List<double>();
73  for (var i = 1; i <= 12; i++)
74  {
75  var returns = monthlyReturns.Where(row => row.Key.Month == i);
76  if (!returns.IsEmpty)
77  {
78  values.Add(returns.FirstValue());
79  continue;
80  }
81 
82  values.Add(double.NaN);
83  }
84 
85  backtestResults.SetItem(key.ToPython(), values.ToPython());
86  }
87 
88  var liveResults = new PyDict();
89  foreach (var kvp in liveMonthlyReturns.GroupBy(kvp => kvp.Key.Year).GetObservations())
90  {
91  var key = kvp.Key.ToStringInvariant();
92  var monthlyReturns = kvp.Value * 100;
93 
94  var values = new List<double>();
95  for (var i = 1; i <= 12; i++)
96  {
97  var returns = monthlyReturns.Where(row => row.Key.Month == i);
98  if (!returns.IsEmpty)
99  {
100  values.Add(returns.FirstValue());
101  continue;
102  }
103 
104  values.Add(double.NaN);
105  }
106 
107  liveResults.SetItem(key.ToPython(), values.ToPython());
108  }
109 
110  base64 = Charting.GetMonthlyReturns(backtestResults, liveResults);
111  }
112 
113  return base64;
114  }
115  }
116 }