Lean  $LEAN_TAG$
Beta.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;
18 using MathNet.Numerics.Statistics;
19 
21 {
22  /// <summary>
23  /// In technical analysis Beta indicator is used to measure volatility or risk of a target (ETF) relative to the overall
24  /// risk (volatility) of the reference (market indexes). The Beta indicators compares target's price movement to the
25  /// movements of the indexes over the same period of time.
26  ///
27  /// It is common practice to use the SPX index as a benchmark of the overall reference market when it comes to Beta
28  /// calculations.
29  /// </summary>
31  {
32  /// <summary>
33  /// RollingWindow to store the data points of the target symbol
34  /// </summary>
35  private RollingWindow<decimal> _targetDataPoints;
36 
37  /// <summary>
38  /// RollingWindow to store the data points of the reference symbol
39  /// </summary>
40  private RollingWindow<decimal> _referenceDataPoints;
41 
42  /// <summary>
43  /// Symbol of the reference used
44  /// </summary>
45  private Symbol _referenceSymbol;
46 
47  /// <summary>
48  /// Symbol of the target used
49  /// </summary>
50  private Symbol _targetSymbol;
51 
52  /// <summary>
53  /// RollingWindow of returns of the target symbol in the given period
54  /// </summary>
55  private RollingWindow<double> _targetReturns;
56 
57  /// <summary>
58  /// RollingWindow of returns of the reference symbol in the given period
59  /// </summary>
60  private RollingWindow<double> _referenceReturns;
61 
62  /// <summary>
63  /// Beta of the target used in relation with the reference
64  /// </summary>
65  private decimal _beta;
66 
67  /// <summary>
68  /// Required period, in data points, for the indicator to be ready and fully initialized.
69  /// </summary>
70  public int WarmUpPeriod { get; private set; }
71 
72  /// <summary>
73  /// Gets a flag indicating when the indicator is ready and fully initialized
74  /// </summary>
75  public override bool IsReady => _targetDataPoints.Samples >= WarmUpPeriod && _referenceDataPoints.Samples >= WarmUpPeriod;
76 
77  /// <summary>
78  /// Creates a new Beta indicator with the specified name, period, target and
79  /// reference values
80  /// </summary>
81  /// <param name="name">The name of this indicator</param>
82  /// <param name="period">The period of this indicator</param>
83  /// <param name="targetSymbol">The target symbol of this indicator</param>
84  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
85  public Beta(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
86  : base(name)
87  {
88  // Assert the period is greater than two, otherwise the beta can not be computed
89  if (period < 2)
90  {
91  throw new Exception($"Period parameter for Beta indicator must be greater than 2 but was {period}");
92  }
93 
94  WarmUpPeriod = period + 1;
95  _referenceSymbol = referenceSymbol;
96  _targetSymbol = targetSymbol;
97 
98  _targetDataPoints = new RollingWindow<decimal>(2);
99  _referenceDataPoints = new RollingWindow<decimal>(2);
100 
101  _targetReturns = new RollingWindow<double>(period);
102  _referenceReturns = new RollingWindow<double>(period);
103  _beta = 0;
104  }
105 
106  /// <summary>
107  /// Computes the next value for this indicator from the given state.
108  ///
109  /// As this indicator is receiving data points from two different symbols,
110  /// it's going to compute the next value when the amount of data points
111  /// of each of them is the same. Otherwise, it will return the last beta
112  /// value computed
113  /// </summary>
114  /// <param name="input">The input value of this indicator on this time step.
115  /// It can be either from the target or the reference symbol</param>
116  /// <returns>The beta value of the target used in relation with the reference</returns>
117  protected override decimal ComputeNextValue(TradeBar input)
118  {
119  var inputSymbol = input.Symbol;
120  if (inputSymbol == _targetSymbol)
121  {
122  _targetDataPoints.Add(input.Close);
123  }
124  else if(inputSymbol == _referenceSymbol)
125  {
126  _referenceDataPoints.Add(input.Close);
127  }else
128  {
129  throw new Exception("The given symbol was not target or reference symbol");
130  }
131 
132  if (_targetDataPoints.Samples == _referenceDataPoints.Samples && _referenceDataPoints.Count > 1)
133  {
134  _targetReturns.Add(GetNewReturn(_targetDataPoints));
135  _referenceReturns.Add(GetNewReturn(_referenceDataPoints));
136 
137  ComputeBeta();
138  }
139  return _beta;
140  }
141 
142  /// <summary>
143  /// Computes the returns with the new given data point and the last given data point
144  /// </summary>
145  /// <param name="rollingWindow">The collection of data points from which we want
146  /// to compute the return</param>
147  /// <returns>The returns with the new given data point</returns>
148  private static double GetNewReturn(RollingWindow<decimal> rollingWindow)
149  {
150  return (double) ((rollingWindow[0] / rollingWindow[1]) - 1);
151  }
152 
153  /// <summary>
154  /// Computes the beta value of the target in relation with the reference
155  /// using the target and reference returns
156  /// </summary>
157  private void ComputeBeta()
158  {
159  var varianceComputed = _referenceReturns.Variance();
160  var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
161 
162  // Avoid division with NaN or by zero
163  var variance = !varianceComputed.IsNaNOrZero() ? varianceComputed : 1;
164  var covariance = !covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0;
165  _beta = (decimal) (covariance / variance);
166  }
167 
168  /// <summary>
169  /// Resets this indicator to its initial state
170  /// </summary>
171  public override void Reset()
172  {
173  _targetDataPoints.Reset();
174  _referenceDataPoints.Reset();
175 
176  _targetReturns.Reset();
177  _referenceReturns.Reset();
178  _beta = 0;
179  base.Reset();
180  }
181  }
182 }