196 lines
7.8 KiB
C#
196 lines
7.8 KiB
C#
/*
|
|
* 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
|
|
{
|
|
/// <summary>
|
|
/// This indicator computes the Slow Stochastics %K and %D. The Fast Stochastic %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 Stochastic %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 Stochastic %D is then derived from the Slow Stochastic %K with the given period.
|
|
/// </summary>
|
|
public class Stochastic : BarIndicator, IIndicatorWarmUpPeriodProvider
|
|
{
|
|
private readonly IndicatorBase<IndicatorDataPoint> _maximum;
|
|
private readonly IndicatorBase<IndicatorDataPoint> _minimum;
|
|
private readonly IndicatorBase<IndicatorDataPoint> _sumFastK;
|
|
private readonly IndicatorBase<IndicatorDataPoint> _sumSlowK;
|
|
|
|
/// <summary>
|
|
/// Gets the value of the Fast Stochastic %K given Period.
|
|
/// </summary>
|
|
public IndicatorBase<IBaseDataBar> FastStoch { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the value of the Slow Stochastic given Period K.
|
|
/// </summary>
|
|
public IndicatorBase<IBaseDataBar> StochK { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the value of the Slow Stochastic given Period D.
|
|
/// </summary>
|
|
public IndicatorBase<IBaseDataBar> StochD { get; }
|
|
|
|
/// <summary>
|
|
/// Creates a new Stochastic Indicator from the specified periods.
|
|
/// </summary>
|
|
/// <param name="name">The name of this indicator.</param>
|
|
/// <param name="period">The period given to calculate the Fast %K</param>
|
|
/// <param name="kPeriod">The K period given to calculated the Slow %K</param>
|
|
/// <param name="dPeriod">The D period given to calculated the Slow %D</param>
|
|
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<IBaseDataBar>(name + "_FastStoch",
|
|
input => ComputeFastStoch(input),
|
|
fastStoch => _maximum.IsReady
|
|
);
|
|
|
|
StochK = new FunctionalIndicator<IBaseDataBar>(name + "_StochK",
|
|
input => ComputeStochK(kPeriod, input),
|
|
stochK => _sumFastK.IsReady
|
|
);
|
|
|
|
StochD = new FunctionalIndicator<IBaseDataBar>(
|
|
name + "_StochD",
|
|
input => ComputeStochD(dPeriod),
|
|
stochD => _sumSlowK.IsReady
|
|
);
|
|
|
|
// Subtracting 2 since the first value is calculated after 'period' bars,
|
|
// and each smoothing step adds (kPeriod - 1) and (dPeriod - 1) respectively.
|
|
WarmUpPeriod = period + kPeriod + dPeriod - 2;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="Stochastic"/> indicator from the specified inputs.
|
|
/// </summary>
|
|
/// <param name="period">The period given to calculate the Fast %K</param>
|
|
/// <param name="kPeriod">The K period given to calculated the Slow %K</param>
|
|
/// <param name="dPeriod">The D period given to calculated the Slow %D</param>
|
|
public Stochastic(int period, int kPeriod, int dPeriod)
|
|
: this($"STO({period},{kPeriod},{dPeriod})", period, kPeriod, dPeriod)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a flag indicating when this indicator is ready and fully initialized
|
|
/// </summary>
|
|
public override bool IsReady => FastStoch.IsReady && StochK.IsReady && StochD.IsReady;
|
|
|
|
/// <summary>
|
|
/// Required period, in data points, for the indicator to be ready and fully initialized.
|
|
/// </summary>
|
|
public int WarmUpPeriod { get; }
|
|
|
|
/// <summary>
|
|
/// Computes the next value of this indicator from the given state
|
|
/// </summary>
|
|
/// <param name="input">The input given to the indicator</param>
|
|
protected override decimal ComputeNextValue(IBaseDataBar input)
|
|
{
|
|
_maximum.Update(input.EndTime, input.High);
|
|
_minimum.Update(input.EndTime, input.Low);
|
|
FastStoch.Update(input);
|
|
StochK.Update(input);
|
|
StochD.Update(input);
|
|
|
|
return FastStoch.Current.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the Fast Stochastic %K.
|
|
/// </summary>
|
|
/// <param name="input">The input.</param>
|
|
/// <returns>The Fast Stochastic %K value.</returns>
|
|
private decimal ComputeFastStoch(IBaseDataBar input)
|
|
{
|
|
var fastStoch = 0m;
|
|
// It requires at least 'period' data points to compute Fast %K.
|
|
if (_maximum.IsReady)
|
|
{
|
|
var denominator = _maximum.Current.Value - _minimum.Current.Value;
|
|
|
|
// if there's no range, just return constant zero
|
|
if (denominator == 0m)
|
|
{
|
|
return 0m;
|
|
}
|
|
|
|
var numerator = input.Close - _minimum.Current.Value;
|
|
fastStoch = numerator / denominator;
|
|
_sumFastK.Update(input.EndTime, fastStoch);
|
|
}
|
|
return fastStoch * 100;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the Slow Stochastic %K.
|
|
/// </summary>
|
|
/// <param name="constantK">The constant k.</param>
|
|
/// <param name="input">The input.</param>
|
|
/// <returns>The Slow Stochastic %K value.</returns>
|
|
private decimal ComputeStochK(int constantK, IBaseData input)
|
|
{
|
|
var stochK = 0m;
|
|
// It requires at least 'kPeriod' updates in _sumFastK for calculation.
|
|
if (_sumFastK.IsReady)
|
|
{
|
|
stochK = _sumFastK.Current.Value / constantK;
|
|
_sumSlowK.Update(input.EndTime, stochK);
|
|
}
|
|
return stochK * 100;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the Slow Stochastic %D.
|
|
/// </summary>
|
|
/// <param name="constantD">The constant d.</param>
|
|
/// <returns>The Slow Stochastic %D value.</returns>
|
|
private decimal ComputeStochD(int constantD)
|
|
{
|
|
var stochD = 0m;
|
|
// It requires at least 'dPeriod' updates in _sumSlowK for calculation
|
|
if (_sumSlowK.IsReady)
|
|
{
|
|
stochD = _sumSlowK.Current.Value / constantD;
|
|
}
|
|
return stochD * 100;
|
|
}
|
|
/// <summary>
|
|
/// Resets this indicator to its initial state
|
|
/// </summary>
|
|
public override void Reset()
|
|
{
|
|
FastStoch.Reset();
|
|
StochK.Reset();
|
|
StochD.Reset();
|
|
_maximum.Reset();
|
|
_minimum.Reset();
|
|
_sumFastK.Reset();
|
|
_sumSlowK.Reset();
|
|
base.Reset();
|
|
}
|
|
}
|
|
}
|