chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user