Hello,
I'm trying to re-purpose the code of the ATR indicator to make another indicator, but when I try to use the new indicator on a sample algorithm, the error is null reference in the ComputeNextValue method. Would appreciate any assistance!
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The AverageTrueRange indicator is a measure of volatility introduced by Welles Wilder in his
/// book: New Concepts in Technical Trading Systems. This indicator computes the TrueRange and then
/// smoothes the TrueRange over a given period.
///
/// TrueRange is defined as the maximum of the following:
/// High - Low
/// ABS(High - PreviousClose)
/// ABS(Low - PreviousClose)
/// atrDerivative
/// </summary>
public class atrDerivative : BarIndicator, IIndicatorWarmUpPeriodProvider
{
private IBaseDataBar _previous;
private decimal atrLong;
private readonly decimal _multipleL;
/// <summary>This indicator is used to smooth the TrueRange computation</summary>
/// <remarks>This is not exposed publicly since it is the same value as this indicator, meaning
/// that this '_smoother' computers the ATR directly, so exposing it publicly would be duplication</remarks>
///private readonly IndicatorBase<IndicatorDataPoint> _smoother;
private IndicatorBase<IndicatorDataPoint> _smootherL;
private readonly IndicatorBase<IndicatorDataPoint> _atrDerivative;
/// <summary>
/// Gets the true range which is the more volatile calculation to be smoothed by this indicator
/// </summary>
public IndicatorBase<IBaseDataBar> TrueRange { get; } //doesn't necessarily need to be public
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _smootherL.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Creates a new atrDerivative indicator using the specified period, multiple, and moving average types
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="periodL">The smoothing period used to smooth the true range values for long position</param>
/// <param name="multipleL">The the multiple for ATR of long position</param>
/// <param name="movingAverageTypeL">The type of smoothing used to smooth the true range values for long positions</param>
public atrDerivative(string name, int periodL = 20, decimal multipleL = 3m, MovingAverageType movingAverageTypeL = MovingAverageType.Wilders)
: base(name)
{
WarmUpPeriod = periodL;
_multipleL = multipleL;
_smootherL = movingAverageTypeL.AsIndicator($"{name}_{movingAverageTypeL}", periodL);
TrueRange = new FunctionalIndicator<IBaseDataBar>(name + "_TrueRange", currentBar =>
{
// in our ComputeNextValue function we'll just call the ComputeTrueRange
var nextValue = ComputeTrueRange(_previous, currentBar);
_previous = currentBar;
return nextValue;
} // in our IsReady function we just need at least one sample
, trueRangeIndicator => trueRangeIndicator.Samples >= 1
);
}
/// <summary>
/// Creates a new atrDerivative indicator using the specified period, multiple, and moving average types
/// </summary>
/// <param name="periodL">The smoothing period used to smooth the true range values for long position</param>
/// <param name="multipleL">The the multiple for ATR of long position</param>
/// <param name="movingAverageTypeL">The type of smoothing used to smooth the true range values for long positions</param>
public atrDerivative(int periodL = 20, decimal multipleL = 3m, MovingAverageType movingAverageTypeL = MovingAverageType.Wilders)
: this($"ATRD({periodL},{multipleL},{movingAverageTypeL})", periodL, multipleL, movingAverageTypeL)
{
}
/// <summary>
/// Computes the TrueRange from the current and previous trade bars
///
/// TrueRange is defined as the maximum of the following:
/// High - Low
/// ABS(High - PreviousClose)
/// ABS(Low - PreviousClose)
/// </summary>
/// <param name="previous">The previous trade bar</param>
/// <param name="current">The current trade bar</param>
/// <returns>The true range</returns>
public static decimal ComputeTrueRange(IBaseDataBar previous, IBaseDataBar current)
{
var range1 = current.High - current.Low;
if (previous == null)
{
return range1;
}
var range2 = Math.Abs(current.High - previous.Close);
var range3 = Math.Abs(current.Low - previous.Close);
return Math.Max(range1, Math.Max(range2, range3));
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
TrueRange.Update(input);
_smootherL.Update(input.Time, TrueRange);
_atrDerivative.Update(input.Time, input.Close - (_multipleL * _smootherL));
return _atrDerivative.Current.Value;
}
public override void Reset()
{
_previous = null;
_smootherL.Reset();
TrueRange.Reset();
_atrDerivative.Reset();
base.Reset();
}
}
}
Alexandre Catarino
Hi Tony Wise ,
The exception is a result of not initializing private field _atrDerivative which, consequently, is always null.
Tony Wise
Thank you, Alexandre! So, I would have needed to initialize it in the base method "atrDerivative"? In the meantime, I had found a work around by making it a "decimal" type. It is not initialized in the base method.
Tony Wise
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!