Lean  $LEAN_TAG$
ChoppinessIndex.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;
17 using System.Linq;
19 
21 {
22  /// <summary>
23  /// The ChoppinessIndex indicator is an indicator designed to determine if the market is choppy (trading sideways)
24  /// or not choppy (trading within a trend in either direction)
25  /// </summary>
27  {
28 
29  private readonly int _period;
30  private readonly RollingWindow<decimal> _highs;
31  private readonly RollingWindow<decimal> _lows;
32  private readonly IndicatorBase<IBaseDataBar> _trueRange;
33  private readonly RollingWindow<decimal> _trueRangeHistory;
34 
35  /// <summary>
36  /// Gets a flag indicating when this indicator is ready and fully initialized
37  /// </summary>
38  public override bool IsReady => Samples >= WarmUpPeriod;
39 
40  /// <summary>
41  /// Required period, in data points, for the indicator to be ready and fully initialized.
42  /// </summary>
43  public int WarmUpPeriod { get; }
44 
45  /// <summary>
46  /// Creates a new ChoppinessIndex indicator using the specified period and moving average type
47  /// </summary>
48  /// <param name="name">The name of this indicator</param>
49  /// <param name="period">The period used for rolling windows for highs and lows</param>
50  public ChoppinessIndex(string name, int period)
51  : base(name)
52  {
53  _period = period;
54 
55  _trueRange = new TrueRange();
56  _trueRangeHistory = new RollingWindow<decimal>(period);
57 
58  _highs = new RollingWindow<decimal>(period);
59  _lows = new RollingWindow<decimal>(period);
60 
61  WarmUpPeriod = period;
62  }
63 
64  /// <summary>
65  /// Creates a new ChoppinessIndex indicator using the specified period
66  /// </summary>
67  /// <param name="period">The period used for rolling windows for highs and lows</param>
68  public ChoppinessIndex(int period)
69  : this($"CHOP({period})", period)
70  {
71  }
72 
73  /// <summary>
74  /// Computes the next value of this indicator from the given state
75  /// </summary>
76  /// <param name="input">The input given to the indicator</param>
77  /// <returns>A new value for this indicator</returns>
78  protected override decimal ComputeNextValue(IBaseDataBar input)
79  {
80  // compute the true range
81  _trueRange.Update(input);
82 
83  // store candle high and low
84  _highs.Add(input.High);
85  _lows.Add(input.Low);
86 
87  // store true range in rolling window
88  if (_trueRange.IsReady)
89  {
90  _trueRangeHistory.Add(_trueRange.Current.Value);
91  }
92  else
93  {
94  _trueRangeHistory.Add(input.High - input.Low);
95  }
96 
97  if (IsReady)
98  {
99  // calculate max high and min low
100  var maxHigh = _highs.Max();
101  var minLow = _lows.Min();
102 
103  if (maxHigh != minLow)
104  {
105  // return CHOP index
106  return (decimal)(100.0 * Math.Log10(((double) _trueRangeHistory.Sum()) / ((double) (maxHigh - minLow))) / Math.Log10(_period));
107  }
108  else
109  {
110  // situation of maxHigh = minLow represents a totally "choppy" or stagnant market,
111  // with no price movement at all.
112  // It's the extreme case of consolidation, hence the maximum value of 100 for the index
113  return 100m;
114  }
115  }
116  else
117  {
118  // return 0 when indicator is not ready
119  return 0m;
120  }
121  }
122 
123  /// <summary>
124  /// Resets this indicator to its initial state
125  /// </summary>
126  public override void Reset()
127  {
128  _trueRange.Reset();
129  _trueRangeHistory.Reset();
130  _highs.Reset();
131  _lows.Reset();
132  base.Reset();
133  }
134  }
135 }