Files
T
Derek Melchin 3eb9dbb55c Update Alpha.cs (#7630)
The old description is incorrect. A stock can have positive Alpha but have negative Beta. In this case, if the benchmark increases, the performance of the stock may be dominated by its negative Beta, causing it to underperform the benchmark.
2023-12-15 15:59:23 -03:00

342 lines
16 KiB
C#

/*
* 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 Python.Runtime;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Python;
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// In financial analysis, the Alpha indicator is used to measure the performance of an investment (such as a stock or ETF)
/// relative to a benchmark index, often representing the broader market. Alpha indicates the excess return of the investment
/// compared to the return of the benchmark index.
///
/// The S P 500 index is frequently used as a benchmark in Alpha calculations to represent the overall market performance.
/// Alpha is an essential tool for investors to understand the idiosyncratic returns of their investment that aren't caused
/// by movement in the underlying benchmark.
/// </summary>
public class Alpha : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Symbol of the reference used
/// </summary>
private readonly Symbol _referenceSymbol;
/// <summary>
/// Symbol of the target used
/// </summary>
private readonly Symbol _targetSymbol;
/// <summary>
/// Period of the indicator - alpha
/// </summary>
private readonly decimal _alphaPeriod;
/// <summary>
/// Rate of change of the target symbol
/// </summary>
private readonly RateOfChange _targetROC;
/// <summary>
/// Rate of change of the reference symbol
/// </summary>
private readonly RateOfChange _referenceROC;
/// <summary>
/// Alpha of the target used in relation with the reference
/// </summary>
private decimal _alpha;
/// <summary>
/// Beta of the target used in relation with the reference
/// </summary>
private readonly Beta _beta;
/// <summary>
/// Interest rate model used to compute the risk free rate
/// </summary>
private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel;
/// <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 => _targetROC.IsReady && _beta.IsReady && _referenceROC.IsReady;
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, IRiskFreeInterestRateModel riskFreeRateModel)
: base(name)
{
// Assert that the target and reference symbols are not the same
if (targetSymbol == referenceSymbol)
{
throw new ArgumentException("The target and reference symbols cannot be the same.");
}
// Assert that the period is greater than 2, otherwise the alpha can not be computed
if (alphaPeriod < 1)
{
throw new ArgumentException("The period must be equal or greater than 1.");
}
// Assert that the beta period is greater than 2, otherwise the beta can not be computed
if (betaPeriod < 2)
{
throw new ArgumentException("The beta period must be equal or greater than 2.");
}
_targetSymbol = targetSymbol;
_referenceSymbol = referenceSymbol;
_alphaPeriod = alphaPeriod;
_riskFreeInterestRateModel = riskFreeRateModel;
_targetROC = new RateOfChange($"{name}_TargetROC", alphaPeriod);
_referenceROC = new RateOfChange($"{name}_ReferenceROC", alphaPeriod);
_beta = new Beta($"{name}_Beta", _targetSymbol, _referenceSymbol, betaPeriod);
WarmUpPeriod = alphaPeriod >= betaPeriod ? alphaPeriod + 1 : betaPeriod + 1;
_alpha = 0m;
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, decimal? riskFreeRate = null)
: this(name, targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, decimal? riskFreeRate = null)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod},{riskFreeRate})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, decimal? riskFreeRate = null)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period},{riskFreeRate})", targetSymbol, referenceSymbol, period, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, decimal? riskFreeRate = null)
: this(name, targetSymbol, referenceSymbol, period, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, PyObject riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
if (input is null)
{
throw new ArgumentNullException(nameof(input));
}
var inputSymbol = input.Symbol;
if (inputSymbol == _targetSymbol)
{
_targetROC.Update(input.EndTime, input.Close);
}
else if (inputSymbol == _referenceSymbol)
{
_referenceROC.Update(input.EndTime, input.Close);
}
else
{
throw new ArgumentException($"The input symbol {inputSymbol} is not the target or reference symbol.");
}
_beta.Update(input);
if (_targetROC.Samples == _referenceROC.Samples && _referenceROC.Samples > 0)
{
ComputeAlpha();
}
return _alpha;
}
/// <summary>
/// Computes the alpha of the target used in relation with the reference and stores it in the _alpha field
/// </summary>
private void ComputeAlpha()
{
if (!_beta.IsReady || !_targetROC.IsReady || !_referenceROC.IsReady)
{
_alpha = 0m;
return;
}
var targetMean = _targetROC.Current.Value / _alphaPeriod;
var referenceMean = _referenceROC.Current.Value / _alphaPeriod;
var riskFreeRate = _riskFreeInterestRateModel.GetInterestRate(_targetROC.Current.Time);
_alpha = targetMean - (riskFreeRate + _beta.Current.Value * (referenceMean - riskFreeRate));
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetROC.Reset();
_referenceROC.Reset();
_beta.Reset();
_alpha = 0m;
base.Reset();
}
}
}