/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using QuantConnect.Data; using QuantConnect.Data.Market; namespace QuantConnect.Indicators { /// /// This indicator computes the Slow Stochastics %K and %D. The Fast Stochastics %K is is computed by /// (Current Close Price - Lowest Price of given Period) / (Highest Price of given Period - Lowest Price of given Period) /// multiplied by 100. Once the Fast Stochastics %K is calculated the Slow Stochastic %K is calculated by the average/smoothed price of /// of the Fast %K with the given period. The Slow Stochastics %D is then derived from the Slow Stochastics %K with the given period. /// public class Stochastic : BarIndicator, IIndicatorWarmUpPeriodProvider { private readonly IndicatorBase _maximum; private readonly IndicatorBase _minimum; private readonly IndicatorBase _sumFastK; private readonly IndicatorBase _sumSlowK; /// /// Gets the value of the Fast Stochastics %K given Period. /// public IndicatorBase FastStoch { get; } /// /// Gets the value of the Slow Stochastics given Period K. /// public IndicatorBase StochK { get; } /// /// Gets the value of the Slow Stochastics given Period D. /// public IndicatorBase StochD { get; } /// /// Creates a new Stochastics Indicator from the specified periods. /// /// The name of this indicator. /// The period given to calculate the Fast %K /// The K period given to calculated the Slow %K /// The D period given to calculated the Slow %D public Stochastic(string name, int period, int kPeriod, int dPeriod) : base(name) { _maximum = new Maximum(name + "_Max", period); _minimum = new Minimum(name + "_Min", period); _sumFastK = new Sum(name + "_SumFastK", kPeriod); _sumSlowK = new Sum(name + "_SumD", dPeriod); FastStoch = new FunctionalIndicator(name + "_FastStoch", input => ComputeFastStoch(period, input), fastStoch => _maximum.IsReady, () => { } ); StochK = new FunctionalIndicator(name + "_StochK", input => ComputeStochK(period, kPeriod, input), stochK => _maximum.IsReady, () => { } ); StochD = new FunctionalIndicator( name + "_StochD", input => ComputeStochD(period, kPeriod, dPeriod), stochD => _maximum.IsReady, () => { } ); WarmUpPeriod = period; } /// /// Creates a new indicator from the specified inputs. /// /// The period given to calculate the Fast %K /// The K period given to calculated the Slow %K /// The D period given to calculated the Slow %D public Stochastic(int period, int kPeriod, int dPeriod) : this($"STO({period},{kPeriod},{dPeriod})", period, kPeriod, dPeriod) { } /// /// Gets a flag indicating when this indicator is ready and fully initialized /// public override bool IsReady => FastStoch.IsReady && StochK.IsReady && StochD.IsReady; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; } /// /// Computes the next value of this indicator from the given state /// /// The input given to the indicator protected override decimal ComputeNextValue(IBaseDataBar input) { _maximum.Update(input.Time, input.High); _minimum.Update(input.Time, input.Low); FastStoch.Update(input); StochK.Update(input); StochD.Update(input); return FastStoch; } /// /// Computes the Fast Stochastic %K. /// /// The period. /// The input. /// The Fast Stochastics %K value. private decimal ComputeFastStoch(int period, IBaseDataBar input) { var denominator = _maximum - _minimum; // if there's no range, just return constant zero if (denominator == 0m) { return 0m; } var numerator = input.Close - _minimum; var fastStoch = _maximum.Samples >= period ? numerator / denominator : decimal.Zero; _sumFastK.Update(input.Time, fastStoch); return fastStoch * 100; } /// /// Computes the Slow Stochastic %K. /// /// The period. /// The constant k. /// The input. /// The Slow Stochastics %K value. private decimal ComputeStochK(int period, int constantK, IBaseData input) { var stochK = _maximum.Samples >= (period + constantK - 1) ? _sumFastK / constantK : decimal.Zero; _sumSlowK.Update(input.Time, stochK); return stochK * 100; } /// /// Computes the Slow Stochastic %D. /// /// The period. /// The constant k. /// The constant d. /// The Slow Stochastics %D value. private decimal ComputeStochD(int period, int constantK, int constantD) { var stochD = _maximum.Samples >= (period + constantK + constantD - 2) ? _sumSlowK / constantD : decimal.Zero; return stochD * 100; } /// /// Resets this indicator to its initial state /// public override void Reset() { FastStoch.Reset(); StochK.Reset(); StochD.Reset(); _maximum.Reset(); _minimum.Reset(); _sumFastK.Reset(); _sumSlowK.Reset(); base.Reset(); } } }