/* * 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 two moving averages defined on a base indicator and produces the difference /// between the fast and slow averages. /// public class MovingAverageConvergenceDivergence : Indicator, IIndicatorWarmUpPeriodProvider { /// /// Gets the fast average indicator /// public IndicatorBase Fast { get; } /// /// Gets the slow average indicator /// public IndicatorBase Slow { get; } /// /// Gets the signal of the MACD /// public IndicatorBase Signal { get; } /// /// Developed by Thomas Aspray in 1986, the MACD-Histogram measures the distance between MACD and its signal line, /// is an oscillator that fluctuates above and below the zero line. /// Bullish or bearish divergences in the MACD-Histogram can alert chartists to an imminent signal line crossover in MACD. /// public IndicatorBase Histogram { get; } /// /// Gets a flag indicating when this indicator is ready and fully initialized /// public override bool IsReady => Signal.IsReady; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; } /// /// Creates a new MACD with the specified parameters /// /// The fast moving average period /// The slow moving average period /// The signal period /// The type of moving averages to use public MovingAverageConvergenceDivergence(int fastPeriod, int slowPeriod, int signalPeriod, MovingAverageType type = MovingAverageType.Exponential) : this($"MACD({fastPeriod},{slowPeriod},{signalPeriod})", fastPeriod, slowPeriod, signalPeriod, type) { } /// /// Creates a new MACD 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 MovingAverageConvergenceDivergence(string name, int fastPeriod, int slowPeriod, int signalPeriod, MovingAverageType type = MovingAverageType.Exponential) : base(name) { if (fastPeriod >= slowPeriod) { throw new ArgumentException("MovingAverageConvergenceDivergence: fastPeriod must be less than slowPeriod", $"{nameof(fastPeriod)}, {nameof(slowPeriod)}"); } Fast = type.AsIndicator(name + "_Fast", fastPeriod); Slow = type.AsIndicator(name + "_Slow", slowPeriod); Signal = type.AsIndicator(name + "_Signal", signalPeriod); Histogram = new Identity(name + "_Histogram"); WarmUpPeriod = slowPeriod + signalPeriod - 1; } /// /// 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) { var fastReady = Fast.Update(input); var slowReady = Slow.Update(input); var macd = Fast.Current.Value - Slow.Current.Value; if (fastReady && slowReady) { if (Signal.Update(input.EndTime, macd)) { Histogram.Update(input.EndTime, macd - Signal.Current.Value); } } return macd; } /// /// Resets this indicator to its initial state /// public override void Reset() { Fast.Reset(); Slow.Reset(); Signal.Reset(); Histogram.Reset(); base.Reset(); } } }