Lean  $LEAN_TAG$
Stochastics.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 QuantConnect.Data;
19 
21 {
22  /// <summary>
23  /// This indicator computes the Slow Stochastics %K and %D. The Fast Stochastics %K is is computed by
24  /// (Current Close Price - Lowest Price of given Period) / (Highest Price of given Period - Lowest Price of given Period)
25  /// multiplied by 100. Once the Fast Stochastics %K is calculated the Slow Stochastic %K is calculated by the average/smoothed price of
26  /// of the Fast %K with the given period. The Slow Stochastics %D is then derived from the Slow Stochastics %K with the given period.
27  /// </summary>
29  {
30  private readonly IndicatorBase<IndicatorDataPoint> _maximum;
31  private readonly IndicatorBase<IndicatorDataPoint> _minimum;
32  private readonly IndicatorBase<IndicatorDataPoint> _sumFastK;
33  private readonly IndicatorBase<IndicatorDataPoint> _sumSlowK;
34 
35  /// <summary>
36  /// Gets the value of the Fast Stochastics %K given Period.
37  /// </summary>
39 
40  /// <summary>
41  /// Gets the value of the Slow Stochastics given Period K.
42  /// </summary>
44 
45  /// <summary>
46  /// Gets the value of the Slow Stochastics given Period D.
47  /// </summary>
49 
50  /// <summary>
51  /// Creates a new Stochastics Indicator from the specified periods.
52  /// </summary>
53  /// <param name="name">The name of this indicator.</param>
54  /// <param name="period">The period given to calculate the Fast %K</param>
55  /// <param name="kPeriod">The K period given to calculated the Slow %K</param>
56  /// <param name="dPeriod">The D period given to calculated the Slow %D</param>
57  public Stochastic(string name, int period, int kPeriod, int dPeriod)
58  : base(name)
59  {
60  _maximum = new Maximum(name + "_Max", period);
61  _minimum = new Minimum(name + "_Min", period);
62  _sumFastK = new Sum(name + "_SumFastK", kPeriod);
63  _sumSlowK = new Sum(name + "_SumD", dPeriod);
64 
65  FastStoch = new FunctionalIndicator<IBaseDataBar>(name + "_FastStoch",
66  input => ComputeFastStoch(input),
67  fastStoch => _maximum.IsReady
68  );
69 
70  StochK = new FunctionalIndicator<IBaseDataBar>(name + "_StochK",
71  input => ComputeStochK(kPeriod, input),
72  stochK => _sumFastK.IsReady
73  );
74 
76  name + "_StochD",
77  input => ComputeStochD(dPeriod),
78  stochD => _sumSlowK.IsReady
79  );
80 
81  // Subtracting 2 since the first value is calculated after 'period' bars,
82  // and each smoothing step adds (kPeriod - 1) and (dPeriod - 1) respectively.
83  WarmUpPeriod = period + kPeriod + dPeriod - 2;
84  }
85 
86  /// <summary>
87  /// Creates a new <see cref="Stochastic"/> indicator from the specified inputs.
88  /// </summary>
89  /// <param name="period">The period given to calculate the Fast %K</param>
90  /// <param name="kPeriod">The K period given to calculated the Slow %K</param>
91  /// <param name="dPeriod">The D period given to calculated the Slow %D</param>
92  public Stochastic(int period, int kPeriod, int dPeriod)
93  : this($"STO({period},{kPeriod},{dPeriod})", period, kPeriod, dPeriod)
94  {
95  }
96 
97  /// <summary>
98  /// Gets a flag indicating when this indicator is ready and fully initialized
99  /// </summary>
100  public override bool IsReady => FastStoch.IsReady && StochK.IsReady && StochD.IsReady;
101 
102  /// <summary>
103  /// Required period, in data points, for the indicator to be ready and fully initialized.
104  /// </summary>
105  public int WarmUpPeriod { get; }
106 
107  /// <summary>
108  /// Computes the next value of this indicator from the given state
109  /// </summary>
110  /// <param name="input">The input given to the indicator</param>
111  protected override decimal ComputeNextValue(IBaseDataBar input)
112  {
113  _maximum.Update(input.Time, input.High);
114  _minimum.Update(input.Time, input.Low);
115  FastStoch.Update(input);
116  StochK.Update(input);
117  StochD.Update(input);
118 
119  return FastStoch.Current.Value;
120  }
121 
122  /// <summary>
123  /// Computes the Fast Stochastic %K.
124  /// </summary>
125  /// <param name="input">The input.</param>
126  /// <returns>The Fast Stochastics %K value.</returns>
127  private decimal ComputeFastStoch(IBaseDataBar input)
128  {
129  var fastStoch = 0m;
130  // It requires at least 'period' data points to compute Fast %K.
131  if (_maximum.IsReady)
132  {
133  var denominator = _maximum.Current.Value - _minimum.Current.Value;
134 
135  // if there's no range, just return constant zero
136  if (denominator == 0m)
137  {
138  return 0m;
139  }
140 
141  var numerator = input.Close - _minimum.Current.Value;
142  fastStoch = numerator / denominator;
143  _sumFastK.Update(input.Time, fastStoch);
144  }
145  return fastStoch * 100;
146  }
147 
148  /// <summary>
149  /// Computes the Slow Stochastic %K.
150  /// </summary>
151  /// <param name="constantK">The constant k.</param>
152  /// <param name="input">The input.</param>
153  /// <returns>The Slow Stochastics %K value.</returns>
154  private decimal ComputeStochK(int constantK, IBaseData input)
155  {
156  var stochK = 0m;
157  // It requires at least 'kPeriod' updates in _sumFastK for calculation.
158  if (_sumFastK.IsReady)
159  {
160  stochK = _sumFastK.Current.Value / constantK;
161  _sumSlowK.Update(input.Time, stochK);
162  }
163  return stochK * 100;
164  }
165 
166  /// <summary>
167  /// Computes the Slow Stochastic %D.
168  /// </summary>
169  /// <param name="constantD">The constant d.</param>
170  /// <returns>The Slow Stochastics %D value.</returns>
171  private decimal ComputeStochD(int constantD)
172  {
173  var stochD = 0m;
174  // It requires at least 'dPeriod' updates in _sumSlowK for calculation
175  if (_sumSlowK.IsReady)
176  {
177  stochD = _sumSlowK.Current.Value / constantD;
178  }
179  return stochD * 100;
180  }
181  /// <summary>
182  /// Resets this indicator to its initial state
183  /// </summary>
184  public override void Reset()
185  {
186  FastStoch.Reset();
187  StochK.Reset();
188  StochD.Reset();
189  _maximum.Reset();
190  _minimum.Reset();
191  _sumFastK.Reset();
192  _sumSlowK.Reset();
193  base.Reset();
194  }
195  }
196 }