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 QuantConnect.Data;
18 
20 {
21  /// <summary>
22  /// This indicator computes the Slow Stochastics %K and %D. The Fast Stochastics %K is is computed by
23  /// (Current Close Price - Lowest Price of given Period) / (Highest Price of given Period - Lowest Price of given Period)
24  /// multiplied by 100. Once the Fast Stochastics %K is calculated the Slow Stochastic %K is calculated by the average/smoothed price of
25  /// of the Fast %K with the given period. The Slow Stochastics %D is then derived from the Slow Stochastics %K with the given period.
26  /// </summary>
28  {
29  private readonly IndicatorBase<IndicatorDataPoint> _maximum;
30  private readonly IndicatorBase<IndicatorDataPoint> _minimum;
31  private readonly IndicatorBase<IndicatorDataPoint> _sumFastK;
32  private readonly IndicatorBase<IndicatorDataPoint> _sumSlowK;
33 
34  /// <summary>
35  /// Gets the value of the Fast Stochastics %K given Period.
36  /// </summary>
38 
39  /// <summary>
40  /// Gets the value of the Slow Stochastics given Period K.
41  /// </summary>
43 
44  /// <summary>
45  /// Gets the value of the Slow Stochastics given Period D.
46  /// </summary>
48 
49  /// <summary>
50  /// Creates a new Stochastics Indicator from the specified periods.
51  /// </summary>
52  /// <param name="name">The name of this indicator.</param>
53  /// <param name="period">The period given to calculate the Fast %K</param>
54  /// <param name="kPeriod">The K period given to calculated the Slow %K</param>
55  /// <param name="dPeriod">The D period given to calculated the Slow %D</param>
56  public Stochastic(string name, int period, int kPeriod, int dPeriod)
57  : base(name)
58  {
59  _maximum = new Maximum(name + "_Max", period);
60  _minimum = new Minimum(name + "_Min", period);
61  _sumFastK = new Sum(name + "_SumFastK", kPeriod);
62  _sumSlowK = new Sum(name + "_SumD", dPeriod);
63 
64  FastStoch = new FunctionalIndicator<IBaseDataBar>(name + "_FastStoch",
65  input => ComputeFastStoch(period, input),
66  fastStoch => _maximum.IsReady,
67  () => { }
68  );
69 
70  StochK = new FunctionalIndicator<IBaseDataBar>(name + "_StochK",
71  input => ComputeStochK(period, kPeriod, input),
72  stochK => _maximum.IsReady,
73  () => { }
74  );
75 
77  name + "_StochD",
78  input => ComputeStochD(period, kPeriod, dPeriod),
79  stochD => _maximum.IsReady,
80  () => { }
81  );
82 
83  WarmUpPeriod = period;
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="period">The period.</param>
126  /// <param name="input">The input.</param>
127  /// <returns>The Fast Stochastics %K value.</returns>
128  private decimal ComputeFastStoch(int period, IBaseDataBar input)
129  {
130  var denominator = _maximum.Current.Value - _minimum.Current.Value;
131 
132  // if there's no range, just return constant zero
133  if (denominator == 0m)
134  {
135  return 0m;
136  }
137 
138  var numerator = input.Close - _minimum.Current.Value;
139  var fastStoch = _maximum.Samples >= period ? numerator / denominator : decimal.Zero;
140 
141  _sumFastK.Update(input.Time, fastStoch);
142  return fastStoch * 100;
143  }
144 
145  /// <summary>
146  /// Computes the Slow Stochastic %K.
147  /// </summary>
148  /// <param name="period">The period.</param>
149  /// <param name="constantK">The constant k.</param>
150  /// <param name="input">The input.</param>
151  /// <returns>The Slow Stochastics %K value.</returns>
152  private decimal ComputeStochK(int period, int constantK, IBaseData input)
153  {
154  var stochK = _maximum.Samples >= (period + constantK - 1) ? _sumFastK.Current.Value / constantK : decimal.Zero;
155  _sumSlowK.Update(input.Time, stochK);
156  return stochK * 100;
157  }
158 
159  /// <summary>
160  /// Computes the Slow Stochastic %D.
161  /// </summary>
162  /// <param name="period">The period.</param>
163  /// <param name="constantK">The constant k.</param>
164  /// <param name="constantD">The constant d.</param>
165  /// <returns>The Slow Stochastics %D value.</returns>
166  private decimal ComputeStochD(int period, int constantK, int constantD)
167  {
168  var stochD = _maximum.Samples >= (period + constantK + constantD - 2) ? _sumSlowK.Current.Value / constantD : decimal.Zero;
169  return stochD * 100;
170  }
171  /// <summary>
172  /// Resets this indicator to its initial state
173  /// </summary>
174  public override void Reset()
175  {
176  FastStoch.Reset();
177  StochK.Reset();
178  StochD.Reset();
179  _maximum.Reset();
180  _minimum.Reset();
181  _sumFastK.Reset();
182  _sumSlowK.Reset();
183  base.Reset();
184  }
185  }
186 }