Lean  $LEAN_TAG$
AverageTrueRange.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
18 
20 {
21  /// <summary>
22  /// The AverageTrueRange indicator is a measure of volatility introduced by Welles Wilder in his
23  /// book: New Concepts in Technical Trading Systems. This indicator computes the TrueRange and then
24  /// smoothes the TrueRange over a given period.
25  ///
26  /// TrueRange is defined as the maximum of the following:
27  /// High - Low
28  /// ABS(High - PreviousClose)
29  /// ABS(Low - PreviousClose)
30  /// </summary>
32  {
33  private IBaseDataBar _previous;
34 
35  /// <summary>This indicator is used to smooth the TrueRange computation</summary>
36  /// <remarks>This is not exposed publicly since it is the same value as this indicator, meaning
37  /// that this '_smoother' computers the ATR directly, so exposing it publicly would be duplication</remarks>
38  private readonly IndicatorBase<IndicatorDataPoint> _smoother;
39 
40  /// <summary>
41  /// Gets the true range which is the more volatile calculation to be smoothed by this indicator
42  /// </summary>
44 
45  /// <summary>
46  /// Gets a flag indicating when this indicator is ready and fully initialized
47  /// </summary>
48  public override bool IsReady => _smoother.IsReady;
49 
50  /// <summary>
51  /// Required period, in data points, for the indicator to be ready and fully initialized.
52  /// </summary>
53  public int WarmUpPeriod { get; }
54 
55  /// <summary>
56  /// Creates a new AverageTrueRange indicator using the specified period and moving average type
57  /// </summary>
58  /// <param name="name">The name of this indicator</param>
59  /// <param name="period">The smoothing period used to smooth the true range values</param>
60  /// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
61  public AverageTrueRange(string name, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
62  : base(name)
63  {
64  WarmUpPeriod = period;
65 
66  _smoother = movingAverageType.AsIndicator($"{name}_{movingAverageType}", period);
67 
68  TrueRange = new FunctionalIndicator<IBaseDataBar>(name + "_TrueRange", currentBar =>
69  {
70  // in our ComputeNextValue function we'll just call the ComputeTrueRange
71  var nextValue = ComputeTrueRange(_previous, currentBar);
72  _previous = currentBar;
73  return nextValue;
74  } // in our IsReady function we just need at least one sample
75  , trueRangeIndicator => trueRangeIndicator.Samples >= 1
76  );
77  }
78 
79  /// <summary>
80  /// Creates a new AverageTrueRange indicator using the specified period and moving average type
81  /// </summary>
82  /// <param name="period">The smoothing period used to smooth the true range values</param>
83  /// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
84  public AverageTrueRange(int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
85  : this($"ATR({period})", period, movingAverageType)
86  {
87  }
88 
89  /// <summary>
90  /// Computes the TrueRange from the current and previous trade bars
91  ///
92  /// TrueRange is defined as the maximum of the following:
93  /// High - Low
94  /// ABS(High - PreviousClose)
95  /// ABS(Low - PreviousClose)
96  /// </summary>
97  /// <param name="previous">The previous trade bar</param>
98  /// <param name="current">The current trade bar</param>
99  /// <returns>The true range</returns>
100  public static decimal ComputeTrueRange(IBaseDataBar previous, IBaseDataBar current)
101  {
102  var range1 = current.High - current.Low;
103  if (previous == null)
104  {
105  return range1;
106  }
107 
108  var range2 = Math.Abs(current.High - previous.Close);
109  var range3 = Math.Abs(current.Low - previous.Close);
110 
111  return Math.Max(range1, Math.Max(range2, range3));
112  }
113 
114  /// <summary>
115  /// Computes the next value of this indicator from the given state
116  /// </summary>
117  /// <param name="input">The input given to the indicator</param>
118  /// <returns>A new value for this indicator</returns>
119  protected override decimal ComputeNextValue(IBaseDataBar input)
120  {
121  // compute the true range and then send it to our smoother
122  TrueRange.Update(input);
123  _smoother.Update(input.Time, TrueRange.Current.Value);
124 
125  return _smoother.Current.Value;
126  }
127 
128  /// <summary>
129  /// Resets this indicator to its initial state
130  /// </summary>
131  public override void Reset()
132  {
133  _previous = null;
134  _smoother.Reset();
135  TrueRange.Reset();
136  base.Reset();
137  }
138  }
139 }