Lean  $LEAN_TAG$
Rolling.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 Deedle;
17 using MathNet.Numerics.Statistics;
18 using System;
20 using System.Collections.Generic;
21 using System.Linq;
22 using QuantConnect.Data;
23 
24 namespace QuantConnect.Report
25 {
26  /// <summary>
27  /// Rolling window functions
28  /// </summary>
29  public static class Rolling
30  {
31  private static readonly IRiskFreeInterestRateModel _interestRateProvider = new InterestRateProvider();
32 
33  /// <summary>
34  /// Calculate the rolling beta with the given window size (in days)
35  /// </summary>
36  /// <param name="performancePoints">The performance points you want to measure beta for</param>
37  /// <param name="benchmarkPoints">The benchmark/points you want to calculate beta with</param>
38  /// <param name="windowSize">Days/window to lookback</param>
39  /// <returns>Rolling beta</returns>
40  public static Series<DateTime, double> Beta(SortedList<DateTime, double> performancePoints, SortedList<DateTime, double> benchmarkPoints, int windowSize = 132)
41  {
42  var dailyDictionary = StatisticsBuilder.PreprocessPerformanceValues(performancePoints.Select(x => new KeyValuePair<DateTime, decimal>(x.Key, (decimal)x.Value)));
43  var dailyReturnsSeries = new Series<DateTime, double>(dailyDictionary);
44 
45  Series<DateTime, double> benchmarkReturns;
46  if (benchmarkPoints.Count != 0)
47  {
48  var benchmarkReturnsDictionary = StatisticsBuilder.CreateBenchmarkDifferences(benchmarkPoints.Select(x => new KeyValuePair<DateTime, decimal>(x.Key, (decimal)x.Value)), benchmarkPoints.Keys.First(), benchmarkPoints.Keys.Last());
49  benchmarkReturns = new Series<DateTime, double>(benchmarkReturnsDictionary);
50  }
51  else
52  {
53  benchmarkReturns = new Series<DateTime, double>(benchmarkPoints);
54  }
55 
56  var returns = Frame.CreateEmpty<DateTime, string>();
57  returns["strategy"] = dailyReturnsSeries;
58  returns = returns.Join("benchmark", benchmarkReturns)
59  .FillMissing(Direction.Forward)
60  .DropSparseRows();
61 
62  var correlation = returns
63  .Window(windowSize)
64  .SelectValues(x => Correlation.Pearson(x["strategy"].Values, x["benchmark"].Values));
65 
66  var portfolioStandardDeviation = dailyReturnsSeries.Window(windowSize).SelectValues(s => s.StdDev());
67  var benchmarkStandardDeviation = benchmarkReturns.Window(windowSize).SelectValues(s => s.StdDev());
68 
69  return (correlation * (portfolioStandardDeviation / benchmarkStandardDeviation))
70  .FillMissing(Direction.Forward)
71  .DropMissing();
72  }
73 
74  /// <summary>
75  /// Get the rolling sharpe of the given series with a lookback of <paramref name="months"/>. The risk free rate is adjustable
76  /// </summary>
77  /// <param name="equityCurve">Equity curve to calculate rolling sharpe for</param>
78  /// <param name="months">Number of months to calculate the rolling period for</param>
79  /// <param name="tradingDayPerYear">The number of trading days per year to increase result of Annual statistics</param>
80  /// <returns>Rolling sharpe ratio</returns>
81  public static Series<DateTime, double> Sharpe(Series<DateTime, double> equityCurve, int months, int tradingDayPerYear)
82  {
83  var riskFreeRate = (double)_interestRateProvider.GetAverageRiskFreeRate(equityCurve.Keys);
84  if (equityCurve.IsEmpty)
85  {
86  return equityCurve;
87  }
88 
89  var dailyReturns = equityCurve.ResampleEquivalence(date => date.Date, s => s.LastValue())
90  .PercentChange();
91 
92  var rollingSharpeData = new List<KeyValuePair<DateTime, double>>();
93  var firstDate = equityCurve.FirstKey();
94 
95  foreach (var date in equityCurve.Keys)
96  {
97  var nMonthsAgo = date.AddMonths(-months);
98  if (nMonthsAgo < firstDate)
99  {
100  continue;
101  }
102 
103  var algoPerformanceLookback = dailyReturns.Between(nMonthsAgo, date);
104  rollingSharpeData.Add(
105  new KeyValuePair<DateTime, double>(
106  date,
107  Statistics.Statistics.SharpeRatio(algoPerformanceLookback.Values.ToList(), riskFreeRate, tradingDayPerYear)
108  )
109  );
110  }
111 
112  return new Series<DateTime, double>(rollingSharpeData.Select(kvp => kvp.Key), rollingSharpeData.Select(kvp => kvp.Value));
113  }
114  }
115 }