forked from QuantConnect/Lean
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBeta.cs
182 lines (160 loc) · 7.16 KB
/
Beta.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
using MathNet.Numerics.Statistics;
namespace QuantConnect.Indicators
{
/// <summary>
/// In technical analysis Beta indicator is used to measure volatility or risk of a target (ETF) relative to the overall
/// risk (volatility) of the reference (market indexes). The Beta indicators compares target's price movement to the
/// movements of the indexes over the same period of time.
///
/// It is common practice to use the SPX index as a benchmark of the overall reference market when it comes to Beta
/// calculations.
/// </summary>
public class Beta : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// RollingWindow to store the data points of the target symbol
/// </summary>
private RollingWindow<decimal> _targetDataPoints;
/// <summary>
/// RollingWindow to store the data points of the reference symbol
/// </summary>
private RollingWindow<decimal> _referenceDataPoints;
/// <summary>
/// Symbol of the reference used
/// </summary>
private Symbol _referenceSymbol;
/// <summary>
/// Symbol of the target used
/// </summary>
private Symbol _targetSymbol;
/// <summary>
/// RollingWindow of returns of the target symbol in the given period
/// </summary>
private RollingWindow<double> _targetReturns;
/// <summary>
/// RollingWindow of returns of the reference symbol in the given period
/// </summary>
private RollingWindow<double> _referenceReturns;
/// <summary>
/// Beta of the target used in relation with the reference
/// </summary>
private decimal _beta;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; private set; }
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _targetDataPoints.Samples >= WarmUpPeriod && _referenceDataPoints.Samples >= WarmUpPeriod;
/// <summary>
/// Creates a new Beta indicator with the specified name, period, target and
/// reference values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Beta(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
: base(name)
{
// Assert the period is greater than two, otherwise the beta can not be computed
if (period < 2)
{
throw new Exception($"Period parameter for Beta indicator must be greater than 2 but was {period}");
}
WarmUpPeriod = period + 1;
_referenceSymbol = referenceSymbol;
_targetSymbol = targetSymbol;
_targetDataPoints = new RollingWindow<decimal>(2);
_referenceDataPoints = new RollingWindow<decimal>(2);
_targetReturns = new RollingWindow<double>(period);
_referenceReturns = new RollingWindow<double>(period);
_beta = 0;
}
/// <summary>
/// Computes the next value for this indicator from the given state.
///
/// As this indicator is receiving data points from two different symbols,
/// it's going to compute the next value when the amount of data points
/// of each of them is the same. Otherwise, it will return the last beta
/// value computed
/// </summary>
/// <param name="input">The input value of this indicator on this time step.
/// It can be either from the target or the reference symbol</param>
/// <returns>The beta value of the target used in relation with the reference</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
var inputSymbol = input.Symbol;
if (inputSymbol == _targetSymbol)
{
_targetDataPoints.Add(input.Close);
}
else if(inputSymbol == _referenceSymbol)
{
_referenceDataPoints.Add(input.Close);
}else
{
throw new Exception("The given symbol was not target or reference symbol");
}
if (_targetDataPoints.Samples == _referenceDataPoints.Samples && _referenceDataPoints.Count > 1)
{
_targetReturns.Add(GetNewReturn(_targetDataPoints));
_referenceReturns.Add(GetNewReturn(_referenceDataPoints));
ComputeBeta();
}
return _beta;
}
/// <summary>
/// Computes the returns with the new given data point and the last given data point
/// </summary>
/// <param name="rollingWindow">The collection of data points from which we want
/// to compute the return</param>
/// <returns>The returns with the new given data point</returns>
private static double GetNewReturn(RollingWindow<decimal> rollingWindow)
{
return (double) ((rollingWindow[0] / rollingWindow[1]) - 1);
}
/// <summary>
/// Computes the beta value of the target in relation with the reference
/// using the target and reference returns
/// </summary>
private void ComputeBeta()
{
var varianceComputed = _referenceReturns.Variance();
var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
// Avoid division with NaN or by zero
var variance = !varianceComputed.IsNaNOrZero() ? varianceComputed : 1;
var covariance = !covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0;
_beta = (decimal) (covariance / variance);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetDataPoints.Reset();
_referenceDataPoints.Reset();
_targetReturns.Reset();
_referenceReturns.Reset();
_beta = 0;
base.Reset();
}
}
}