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  ///
30  /// The indicator only updates when both assets have a price for a time step. When a bar is missing for one of the assets,
31  /// the indicator value fills forward to improve the accuracy of the indicator.
32  /// </summary>
33  public class Beta : DualSymbolIndicator<decimal>
34  {
35  /// <summary>
36  /// RollingWindow of returns of the target symbol in the given period
37  /// </summary>
38  private readonly RollingWindow<double> _targetReturns;
39 
40  /// <summary>
41  /// RollingWindow of returns of the reference symbol in the given period
42  /// </summary>
43  private readonly RollingWindow<double> _referenceReturns;
44 
45  /// <summary>
46  /// Gets a flag indicating when the indicator is ready and fully initialized
47  /// </summary>
48  public override bool IsReady => _targetReturns.IsReady && _referenceReturns.IsReady;
49 
50  /// <summary>
51  /// Creates a new Beta indicator with the specified name, target, reference,
52  /// and period values
53  /// </summary>
54  /// <param name="name">The name of this indicator</param>
55  /// <param name="targetSymbol">The target symbol of this indicator</param>
56  /// <param name="period">The period of this indicator</param>
57  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
58  public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period)
59  : base(name, targetSymbol, referenceSymbol, 2)
60  {
61  // Assert the period is greater than two, otherwise the beta can not be computed
62  if (period < 2)
63  {
64  throw new ArgumentException($"Period parameter for Beta indicator must be greater than 2 but was {period}.");
65  }
66 
67  _targetReturns = new RollingWindow<double>(period);
68  _referenceReturns = new RollingWindow<double>(period);
69  WarmUpPeriod = period + 1 + (IsTimezoneDifferent ? 1 : 0);
70  }
71 
72  /// <summary>
73  /// Creates a new Beta indicator with the specified target, reference,
74  /// and period values
75  /// </summary>
76  /// <param name="targetSymbol">The target symbol of this indicator</param>
77  /// <param name="period">The period of this indicator</param>
78  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
79  public Beta(Symbol targetSymbol, Symbol referenceSymbol, int period)
80  : this($"B({period})", targetSymbol, referenceSymbol, period)
81  {
82  }
83 
84  /// <summary>
85  /// Creates a new Beta indicator with the specified name, period, target and
86  /// reference values
87  /// </summary>
88  /// <param name="name">The name of this indicator</param>
89  /// <param name="period">The period of this indicator</param>
90  /// <param name="targetSymbol">The target symbol of this indicator</param>
91  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
92  /// <remarks>Constructor overload for backward compatibility.</remarks>
93  public Beta(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
94  : this(name, targetSymbol, referenceSymbol, period)
95  {
96  }
97 
98  /// <summary>
99  /// Adds the closing price to the corresponding symbol's data set (target or reference).
100  /// Computes returns when there are enough data points for each symbol.
101  /// </summary>
102  /// <param name="input">The input value for this symbol</param>
103  protected override void AddDataPoint(IBaseDataBar input)
104  {
105  if (input.Symbol == TargetSymbol)
106  {
107  TargetDataPoints.Add(input.Close);
108  if (TargetDataPoints.Count > 1)
109  {
110  _targetReturns.Add(GetNewReturn(TargetDataPoints));
111  }
112  }
113  else if (input.Symbol == ReferenceSymbol)
114  {
115  ReferenceDataPoints.Add(input.Close);
116  if (ReferenceDataPoints.Count > 1)
117  {
118  _referenceReturns.Add(GetNewReturn(ReferenceDataPoints));
119  }
120  }
121  else
122  {
123  throw new ArgumentException($"The given symbol {input.Symbol} was not {TargetSymbol} or {ReferenceSymbol} symbol");
124  }
125  }
126 
127  /// <summary>
128  /// Computes the returns with the new given data point and the last given data point
129  /// </summary>
130  /// <param name="rollingWindow">The collection of data points from which we want
131  /// to compute the return</param>
132  /// <returns>The returns with the new given data point</returns>
133  private static double GetNewReturn(RollingWindow<decimal> rollingWindow)
134  {
135  return (double)((rollingWindow[0].SafeDivision(rollingWindow[1]) - 1));
136  }
137 
138  /// <summary>
139  /// Computes the beta value of the target in relation with the reference
140  /// using the target and reference returns
141  /// </summary>
142  protected override void ComputeIndicator()
143  {
144  var varianceComputed = _referenceReturns.Variance();
145  var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
146 
147  // Avoid division with NaN or by zero
148  var variance = !varianceComputed.IsNaNOrZero() ? varianceComputed : 1;
149  var covariance = !covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0;
150  IndicatorValue = (decimal)(covariance / variance);
151  }
152 
153  /// <summary>
154  /// Resets this indicator to its initial state
155  /// </summary>
156  public override void Reset()
157  {
158  _targetReturns.Reset();
159  _referenceReturns.Reset();
160  base.Reset();
161  }
162  }
163 }