/*
* 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 System;
namespace QuantConnect.Indicators
{
///
/// This indicator creates the Schaff Trend Cycle
///
public class SchaffTrendCycle : Indicator, IIndicatorWarmUpPeriodProvider
{
// MACD Variables
private readonly MovingAverageConvergenceDivergence _MACD;
private readonly IndicatorBase _maximum;
private readonly IndicatorBase _minimum;
// _K = %K FROM MACD; _D = %D FROM _K
private readonly IndicatorBase _K;
private readonly IndicatorBase _D;
private readonly IndicatorBase _maximumD;
private readonly IndicatorBase _minimumD;
// PF = %K FROM %MACD_D; PFF = %D FROM PF
private readonly IndicatorBase _PF;
private readonly IndicatorBase _PFF;
///
/// Gets a flag indicating when this indicator is ready and fully initialized
///
public override bool IsReady => _MACD.IsReady;
///
/// Required period, in data points, for the indicator to be ready and fully initialized.
///
public int WarmUpPeriod { get; }
///
/// Creates the name string and calls on the indicator constructor with given parameters
/// https://www.tradingpedia.com/forex-trading-indicators/schaff-trend-cycle
///
/// The fast moving average period
/// The slow moving average period
/// The signal period
/// The type of moving averages to use
public SchaffTrendCycle(int cyclePeriod = 10, int fastPeriod = 23, int slowPeriod = 50, MovingAverageType type = MovingAverageType.Exponential)
: this($"SchaffTrendCycle({cyclePeriod},{fastPeriod},{slowPeriod})", cyclePeriod, fastPeriod, slowPeriod, type)
{
}
///
/// Creates a new schaff trend cycle with the specified parameters
///
/// The name of this indicator
/// The fast moving average period
/// The slow moving average period
/// The signal period
/// The type of moving averages to use
public SchaffTrendCycle(string name, int cyclePeriod, int fastPeriod, int slowPeriod, MovingAverageType type)
: base(name)
{
//Create MACD indicator and track max and min.
_MACD = new MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, cyclePeriod, type);
_maximum = _MACD.MAX(cyclePeriod, false);
_minimum = _MACD.MIN(cyclePeriod, false);
//Stochastics of MACD variables
_K = new Identity(name + "_K");
_D = type.AsIndicator(3).Of(_K, false);
_maximumD = _D.MAX(cyclePeriod, false);
_minimumD = _D.MIN(cyclePeriod, false);
//Stochastics of MACD Stochastics variables; _PFF is STC
_PF = new Identity(name + "_PF");
_PFF = type.AsIndicator(3).Of(_PF, false);
WarmUpPeriod = _MACD.WarmUpPeriod;
}
///
/// Computes the next value of this indicator from the given state
///
/// The input given to the indicator
/// A new value for this indicator
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
// Update internal indicator, automatically updates _maximum and _minimum
_MACD.Update(input);
// Update our Stochastics K, automatically updates our Stochastics D variable which is a smoothed version of K
var MACD_K = new IndicatorDataPoint(input.EndTime, ComputeStoch(_MACD.Current.Value, _maximum.Current.Value, _minimum.Current.Value));
_K.Update(MACD_K);
// With our Stochastic D values calculate PF
var PF = new IndicatorDataPoint(input.EndTime, ComputeStoch(_D.Current.Value, _maximumD.Current.Value, _minimumD.Current.Value));
_PF.Update(PF);
return _PFF.Current.Value;
}
///
/// Computes the stochastics value for a series.
///
/// The current value of the set
/// The max value of the set within a given period
/// The min value of the set within a given period
/// Stochastics value
private decimal ComputeStoch(decimal value, decimal highest, decimal lowest)
{
var numerator = value - lowest;
var denominator = highest - lowest;
return denominator > 0 ? (numerator / denominator) * 100 : decimal.Zero;
}
///
/// Resets this indicator to its initial state
///
public override void Reset()
{
_MACD.Reset();
_maximum.Reset();
_minimum.Reset();
_K.Reset();
_D.Reset();
_maximumD.Reset();
_minimumD.Reset();
_PF.Reset();
_PFF.Reset();
base.Reset();
}
}
}