/*
* 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
{
///
/// 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.
///
public class Alpha : BarIndicator, IIndicatorWarmUpPeriodProvider
{
///
/// Symbol of the reference used
///
private readonly Symbol _referenceSymbol;
///
/// Symbol of the target used
///
private readonly Symbol _targetSymbol;
///
/// Period of the indicator - alpha
///
private readonly decimal _alphaPeriod;
///
/// Rate of change of the target symbol
///
private readonly RateOfChange _targetROC;
///
/// Rate of change of the reference symbol
///
private readonly RateOfChange _referenceROC;
///
/// Alpha of the target used in relation with the reference
///
private decimal _alpha;
///
/// Beta of the target used in relation with the reference
///
private readonly Beta _beta;
///
/// Interest rate model used to compute the risk free rate
///
private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel;
///
/// 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 => _targetROC.IsReady && _beta.IsReady && _referenceROC.IsReady;
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
///
/// The name of this indicator
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate model of this indicator
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;
}
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
///
/// The name of this indicator
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate of this indicator for given period
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))
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period values
///
///
///
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate of this indicator for given period
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))
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period value
///
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha and beta
/// The risk free rate of this indicator for given period
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))
{
}
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
///
///
///
///
/// Period of the indicator - alpha and beta
/// The risk free rate of this indicator for given period
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, decimal? riskFreeRate = null)
: this(name, targetSymbol, referenceSymbol, period, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period values
///
///
///
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate model of this indicator
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, riskFreeRateModel)
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period value
///
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha and beta
/// The risk free rate model of this indicator
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
///
///
///
///
/// Period of the indicator - alpha and beta
/// The risk free rate model of this indicator
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
///
/// The name of this indicator
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate model of this indicator
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period values
///
///
///
/// Period of the indicator - alpha
/// Period of the indicator - beta
/// The risk free rate model of this indicator
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))
{
}
///
/// Creates a new Alpha indicator with the specified target, reference, and period value
///
/// The target symbol of this indicator
/// The reference symbol of this indicator
/// Period of the indicator - alpha and beta
/// The risk free rate model of this indicator
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
///
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
///
///
///
///
/// Period of the indicator - alpha and beta
/// The risk free rate model of this indicator
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
///
/// Computes the next value for this indicator from the given state.
///
///
///
///
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;
}
///
/// Computes the alpha of the target used in relation with the reference and stores it in the _alpha field
///
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.EndTime);
_alpha = targetMean - (riskFreeRate + _beta.Current.Value * (referenceMean - riskFreeRate));
}
///
/// Resets this indicator to its initial state
///
public override void Reset()
{
_targetROC.Reset();
_referenceROC.Reset();
_beta.Reset();
_alpha = 0m;
base.Reset();
}
}
}