/* * 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 { /// /// 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. /// public class Beta : BarIndicator, IIndicatorWarmUpPeriodProvider { /// /// RollingWindow to store the data points of the target symbol /// private readonly RollingWindow _targetDataPoints; /// /// RollingWindow to store the data points of the reference symbol /// private readonly RollingWindow _referenceDataPoints; /// /// Symbol of the reference used /// private readonly Symbol _referenceSymbol; /// /// Symbol of the target used /// private readonly Symbol _targetSymbol; /// /// RollingWindow of returns of the target symbol in the given period /// private readonly RollingWindow _targetReturns; /// /// RollingWindow of returns of the reference symbol in the given period /// private readonly RollingWindow _referenceReturns; /// /// Beta of the target used in relation with the reference /// private decimal _beta; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; private set; } /// /// Gets a flag indicating when the indicator is ready and fully initialized /// public override bool IsReady => _targetDataPoints.Samples >= WarmUpPeriod && _referenceDataPoints.Samples >= WarmUpPeriod; /// /// Creates a new Beta indicator with the specified name, target, reference, /// and period values /// /// The name of this indicator /// The target symbol of this indicator /// The period of this indicator /// The reference symbol of this indicator public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period) : base(name) { // Assert the period is greater than two, otherwise the beta can not be computed if (period < 2) { throw new ArgumentException($"Period parameter for Beta indicator must be greater than 2 but was {period}"); } WarmUpPeriod = period + 1; _referenceSymbol = referenceSymbol; _targetSymbol = targetSymbol; _targetDataPoints = new RollingWindow(2); _referenceDataPoints = new RollingWindow(2); _targetReturns = new RollingWindow(period); _referenceReturns = new RollingWindow(period); _beta = 0; } /// /// Creates a new Beta indicator with the specified target, reference, /// and period values /// /// The target symbol of this indicator /// The period of this indicator /// The reference symbol of this indicator public Beta(Symbol targetSymbol, Symbol referenceSymbol, int period) : this($"B({period})", targetSymbol, referenceSymbol, period) { } /// /// Creates a new Beta indicator with the specified name, period, target and /// reference values /// /// The name of this indicator /// The period of this indicator /// The target symbol of this indicator /// The reference symbol of this indicator /// Constructor overload for backward compatibility. public Beta(string name, int period, Symbol targetSymbol, Symbol referenceSymbol) : this(name, targetSymbol, referenceSymbol, period) { } /// /// 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 /// /// The input value of this indicator on this time step. /// It can be either from the target or the reference symbol /// The beta value of the target used in relation with the reference protected override decimal ComputeNextValue(IBaseDataBar input) { var inputSymbol = input.Symbol; if (inputSymbol == _targetSymbol) { _targetDataPoints.Add(input.Close); } else if(inputSymbol == _referenceSymbol) { _referenceDataPoints.Add(input.Close); } else { throw new ArgumentException("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; } /// /// Computes the returns with the new given data point and the last given data point /// /// The collection of data points from which we want /// to compute the return /// The returns with the new given data point private static double GetNewReturn(RollingWindow rollingWindow) { return (double) ((rollingWindow[0].SafeDivision(rollingWindow[1]) - 1)); } /// /// Computes the beta value of the target in relation with the reference /// using the target and reference returns /// 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); } /// /// Resets this indicator to its initial state /// public override void Reset() { _targetDataPoints.Reset(); _referenceDataPoints.Reset(); _targetReturns.Reset(); _referenceReturns.Reset(); _beta = 0; base.Reset(); } } }