Lean  $LEAN_TAG$
SharpeRatio.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 Python.Runtime;
17 using QuantConnect.Data;
18 using QuantConnect.Python;
19 
21 {
22  /// <summary>
23  /// Calculation of the Sharpe Ratio (SR) developed by William F. Sharpe.
24  ///
25  /// Reference: https://www.investopedia.com/articles/07/sharpe_ratio.asp
26  /// Formula: S(x) = (Rx - Rf) / stdDev(Rx)
27  /// Where:
28  /// S(x) - sharpe ratio of x
29  /// Rx - average rate of return for x
30  /// Rf - risk-free rate
31  /// </summary>
32  public class SharpeRatio : IndicatorBase<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider
33  {
34  /// <summary>
35  /// Length of lookback period for the Sharpe ratio calculation
36  /// </summary>
37  private readonly int _period;
38 
39  /// <summary>
40  /// Risk-free rate model
41  /// </summary>
42  private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel;
43 
44  /// <summary>
45  /// RateOfChange indicator for calculating the sharpe ratio
46  /// </summary>
47  protected RateOfChange RateOfChange { get; }
48 
49  /// <summary>
50  /// RiskFreeRate indicator for calculating the sharpe ratio
51  /// </summary>
52  protected Identity RiskFreeRate { get; }
53 
54  /// <summary>
55  /// Indicator to store the calculation of the sharpe ratio
56  /// </summary>
57  protected IndicatorBase Ratio { get; set; }
58 
59  /// <summary>
60  /// Indicator to store the numerator of the Sharpe ratio calculation
61  /// </summary>
62  protected IndicatorBase Numerator { get; }
63 
64  /// <summary>
65  /// Required period, in data points, for the indicator to be ready and fully initialized.
66  /// </summary>
67  public int WarmUpPeriod { get; }
68 
69  /// <summary>
70  /// Returns whether the indicator is properly initialized with data
71  /// </summary>
72  public override bool IsReady => Ratio.Samples > _period;
73 
74  /// <summary>
75  /// Creates a new Sharpe Ratio indicator using the specified periods
76  /// </summary>
77  /// <param name="name">The name of this indicator</param>
78  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
79  /// <param name="riskFreeRateModel">Risk-free rate model</param>
80  public SharpeRatio(string name, int period, IRiskFreeInterestRateModel riskFreeRateModel)
81  : base(name)
82  {
83  _period = period;
84  _riskFreeInterestRateModel = riskFreeRateModel;
85 
86  // calculate sharpe ratio using indicators
87  RateOfChange = new RateOfChange(1);
88  RiskFreeRate = new Identity(name + "_RiskFreeRate");
89  Numerator = RateOfChange.SMA(period).Minus(RiskFreeRate);
90  var denominator = new StandardDeviation(period).Of(RateOfChange);
91  Ratio = Numerator.Over(denominator);
92 
93  // define warmup value;
94  // _roc is the base of our indicator chain + period of STD and SMA
96  }
97 
98  /// <summary>
99  /// Creates a new Sharpe Ratio indicator using the specified periods
100  /// </summary>
101  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
102  /// <param name="riskFreeRateModel">Risk-free rate model</param>
103  public SharpeRatio(int period, IRiskFreeInterestRateModel riskFreeRateModel)
104  : this($"SR({period})", period, riskFreeRateModel)
105  {
106  }
107 
108  /// <summary>
109  /// Creates a new Sharpe Ratio indicator using the specified period using a Python risk free rate model
110  /// </summary>
111  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
112  /// <param name="riskFreeRateModel">Risk-free rate model</param>
113  public SharpeRatio(string name, int period, PyObject riskFreeRateModel)
114  : this(name, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
115  {
116  }
117 
118  /// <summary>
119  /// Creates a new Sharpe Ratio indicator using the specified period using a Python risk free rate model
120  /// </summary>
121  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
122  /// <param name="riskFreeRateModel">Risk-free rate model</param>
123  public SharpeRatio(int period, PyObject riskFreeRateModel)
124  : this(period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
125  {
126  }
127 
128  /// <summary>
129  /// Creates a new Sharpe Ratio indicator using the specified periods
130  /// </summary>
131  /// <param name="name">The name of this indicator</param>
132  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
133  /// <param name="riskFreeRate">Risk-free rate for sharpe ratio calculation</param>
134  public SharpeRatio(string name, int period, decimal riskFreeRate = 0.0m)
135  : this(name, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate))
136  {
137  }
138 
139  /// <summary>
140  /// Creates a new SharpeRatio indicator using the specified periods
141  /// </summary>
142  /// <param name="period">Period of historical observation for sharpe ratio calculation</param>
143  /// <param name="riskFreeRate">Risk-free rate for sharpe ratio calculation</param>
144  public SharpeRatio(int period, decimal riskFreeRate = 0.0m)
145  : this($"SR({period},{riskFreeRate})", period, riskFreeRate)
146  {
147  }
148 
149  /// <summary>
150  /// Computes the next value for this indicator from the given state.
151  /// </summary>
152  /// <param name="input">The input given to the indicator</param>
153  /// <returns>A new value for this indicator</returns>
154  protected override decimal ComputeNextValue(IndicatorDataPoint input)
155  {
156  RiskFreeRate.Update(input.Time, _riskFreeInterestRateModel.GetInterestRate(input.Time));
157  RateOfChange.Update(input);
158  return Ratio;
159  }
160 
161  /// <summary>
162  /// Resets this indicator to its initial state
163  /// </summary>
164  public override void Reset()
165  {
166  Ratio.Reset();
168  base.Reset();
169  }
170  }
171 }