MACD Zero Lag by wiart

2378 downloads / 1235 views / Created: 08.02.2016
 Average Rating: 5

Indicator Description

This indicator is a MACD variant, called "Zero Lag MACD", because it is supposed to not lag behind the price, as opposed to the classical MACD.
The formula can be found at https://www.mql5.com/en/code/9993
ZeroLAG MACD(i) = (2*EMA(Close, EFP, i) - EMA(EMA(Close, FP, i), FP, i)) - (2*EMA(Close, SP, i) - EMA(EMA(Close, SP, i), SP, i));
ZeroLAG MACD Signal(i) = 2*EMA(ZeroLAG MACD(i), SigP, i) - EMA(EMA(ZeroLAG MACD(i), SigP, i), SigP, i);
where:
EMA - exponential moving average;
Close - a price of the closing of the bar;
FP - a period of the quick moving average;
SP - a period of the slow moving average;
SigP - a period of the signal moving average;

I improved it so that various moving average methods can be used (exponential, simple, weighted, smoothed), the default being Exponential.

Enjoy!
Laurent

Comments

//============================================================== // Forex Strategy Builder // Copyright © Miroslav Popov. All rights reserved. //============================================================== // THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE. //============================================================== using System; using System.Drawing; using ForexStrategyBuilder.Infrastructure.Entities; using ForexStrategyBuilder.Infrastructure.Enums; using ForexStrategyBuilder.Infrastructure.Interfaces; namespace ForexStrategyBuilder.Indicators.Store { public class MACDZRHistogram : Indicator { public MACDZRHistogram() { IndicatorName = "MACD Zero Lag"; PossibleSlots = SlotTypes.OpenFilter | SlotTypes.CloseFilter; SeparatedChart = true; IndicatorAuthor = "Laurent Wiart"; IndicatorVersion = "1.0"; IndicatorDescription = "MACD Zero Lag indicator." + Environment.NewLine + "The indicator compares two MACDs Zero Lag on bar Close. Based upon https://www.mql5.com/en/code/9993"; } public override void Initialize(SlotTypes slotType) { SlotType = slotType; // The ComboBox parameters IndParam.ListParam[0].Caption = "Logic"; IndParam.ListParam[0].ItemList = new[] { "MACD Zero Lag histogram rises", "MACD Zero Lag histogram falls", "MACD Zero Lag histogram is higher than the Level line", "MACD Zero Lag histogram is lower than the Level line", "MACD Zero Lag histogram crosses the Level line upward", "MACD Zero Lag histogram crosses the Level line downward", "MACD Zero Lag histogram changes its direction upward", "MACD Zero Lag histogram changes its direction downward" }; IndParam.ListParam[0].Index = 0; IndParam.ListParam[0].Text = IndParam.ListParam[0].ItemList[IndParam.ListParam[0].Index]; IndParam.ListParam[0].Enabled = true; IndParam.ListParam[0].ToolTip = "Logic of application of the indicator."; IndParam.ListParam[1].Caption = "Smoothing method"; IndParam.ListParam[1].ItemList = Enum.GetNames(typeof(MAMethod)); IndParam.ListParam[1].Index = (int)MAMethod.Exponential; IndParam.ListParam[1].Text = IndParam.ListParam[1].ItemList[IndParam.ListParam[1].Index]; IndParam.ListParam[1].Enabled = true; IndParam.ListParam[1].ToolTip = "The smoothing method of the MACD Zero Lag."; IndParam.ListParam[2].Caption = "Base price"; IndParam.ListParam[2].ItemList = Enum.GetNames(typeof(BasePrice)); IndParam.ListParam[2].Index = (int)BasePrice.Close; IndParam.ListParam[2].Text = IndParam.ListParam[2].ItemList[IndParam.ListParam[2].Index]; IndParam.ListParam[2].Enabled = true; IndParam.ListParam[2].ToolTip = "The price the MACD Zero Lag are based on."; IndParam.ListParam[3].Caption = "Signal line method"; IndParam.ListParam[3].ItemList = Enum.GetNames(typeof(MAMethod)); IndParam.ListParam[3].Index = (int)MAMethod.Exponential; IndParam.ListParam[3].Text = IndParam.ListParam[3].ItemList[IndParam.ListParam[3].Index]; IndParam.ListParam[3].Enabled = true; IndParam.ListParam[3].ToolTip = "The smoothing method of the signal line."; // The NumericUpDown parameters IndParam.NumParam[0].Caption = "Slow MA period"; IndParam.NumParam[0].Value = 26; IndParam.NumParam[0].Min = 1; IndParam.NumParam[0].Max = 200; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The period of Slow MA."; IndParam.NumParam[1].Caption = "Fast MA period"; IndParam.NumParam[1].Value = 12; IndParam.NumParam[1].Min = 1; IndParam.NumParam[1].Max = 200; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "The period of Fast MA."; IndParam.NumParam[2].Caption = "Signal line period"; IndParam.NumParam[2].Value = 9; IndParam.NumParam[2].Min = 1; IndParam.NumParam[2].Max = 200; IndParam.NumParam[2].Enabled = true; IndParam.NumParam[2].ToolTip = "The period of Signal line."; IndParam.NumParam[3].Caption = "Level"; IndParam.NumParam[3].Value = 0; IndParam.NumParam[3].Min = 0; IndParam.NumParam[3].Max = 5; IndParam.NumParam[3].Point = 4; IndParam.NumParam[3].Enabled = true; IndParam.NumParam[3].ToolTip = "A critical level (for the appropriate logic)."; // The CheckBox parameters IndParam.CheckParam[0].Caption = "Use previous bar value"; IndParam.CheckParam[0].Enabled = true; IndParam.CheckParam[0].ToolTip = "Use the indicator value from the previous bar."; } public override void Calculate(IDataSet dataSet) { DataSet = dataSet; // Reading the parameters var maMethod = (MAMethod)IndParam.ListParam[1].Index; var slMethod = (MAMethod)IndParam.ListParam[3].Index; var basePrice = (BasePrice)IndParam.ListParam[2].Index; var nSlow = (int)IndParam.NumParam[0].Value; var nFast = (int)IndParam.NumParam[1].Value; var nSignal = (int)IndParam.NumParam[2].Value; double dLevel = IndParam.NumParam[3].Value; int iPrvs = IndParam.CheckParam[0].Checked ? 1 : 0; // Calculation int iFirstBar = nSlow + nFast + 2; double[] adMASlow = MovingAverage(nSlow, 0, maMethod, Price(basePrice)); double[] adMAFast = MovingAverage(nFast, 0, maMethod, Price(basePrice)); double[] MAOfSlowMA = MovingAverage(nSlow, 0, maMethod, adMASlow); double[] MAOfFastMA = MovingAverage(nFast, 0, maMethod, adMAFast); var adMACDZR = new double[Bars]; var adSlowMACDZR = new double[Bars]; var adFastMACDZR = new double[Bars]; //ZeroLAG MACD(i) = (2 * EMA(Close, FP, i) - EMA(EMA(Close, FP, i), FP, i)) - (2 * EMA(Close, SP, i) - EMA(EMA(Close, SP, i), SP, i)); for (int iBar = nSlow - 1; iBar < Bars; iBar++) { adSlowMACDZR[iBar] = 2 * adMASlow[iBar] - MAOfSlowMA[iBar]; adFastMACDZR[iBar] = 2 * adMAFast[iBar] - MAOfFastMA[iBar]; //adMACDZR[iBar] = adMAFast[iBar] - adMASlow[iBar]; //MACD Histogram classic adMACDZR[iBar] = adFastMACDZR[iBar] - adSlowMACDZR[iBar]; } //ZeroLAG MACD Signal(i) = 2*EMA(ZeroLAG MACD(i), SigP, i) - EMA(EMA(ZeroLAG MACD(i), SigP, i), SigP, i); double[] MAOfMACDZR = MovingAverage(nSignal, 0, maMethod, adMACDZR); double[] MAofMAOfMACDZR = MovingAverage(nSignal, 0, maMethod, MAOfMACDZR); var maSignalLine = new double[Bars]; for (int iBar = nSlow - 1; iBar < Bars; iBar++) { maSignalLine[iBar] = 2*MAOfMACDZR[iBar] - MAofMAOfMACDZR[iBar]; //double[] maSignalLine = MovingAverage(nSignal, 0, slMethod, adMACDZR); } // adHistogram represents MACD oscillator var adHistogram = new double[Bars]; for (int iBar = nSlow + nSignal - 1; iBar < Bars; iBar++) adHistogram[iBar] = adMACDZR[iBar] - maSignalLine[iBar]; // Saving the components Component = new IndicatorComp[5]; Component[0] = new IndicatorComp { CompName = "MACD Zero Lag Histogram", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Histogram, FirstBar = iFirstBar, Value = adHistogram }; Component[1] = new IndicatorComp { CompName = "Signal line", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Gold, FirstBar = iFirstBar, Value = maSignalLine }; Component[2] = new IndicatorComp { CompName = "MACD Zero Lag line", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = iFirstBar, Value = adMACDZR }; Component[3] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = iFirstBar, Value = new double[Bars] }; Component[4] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = iFirstBar, Value = new double[Bars] }; // Sets the Component's type if (SlotType == SlotTypes.OpenFilter) { Component[3].DataType = IndComponentType.AllowOpenLong; Component[3].CompName = "Is long entry allowed"; Component[4].DataType = IndComponentType.AllowOpenShort; Component[4].CompName = "Is short entry allowed"; } else if (SlotType == SlotTypes.CloseFilter) { Component[3].DataType = IndComponentType.ForceCloseLong; Component[3].CompName = "Close out long position"; Component[4].DataType = IndComponentType.ForceCloseShort; Component[4].CompName = "Close out short position"; } // Calculation of the logic var indLogic = IndicatorLogic.It_does_not_act_as_a_filter; switch (IndParam.ListParam[0].Text) { case "MACD Zero Lag histogram rises": indLogic = IndicatorLogic.The_indicator_rises; break; case "MACD Zero Lag histogram falls": indLogic = IndicatorLogic.The_indicator_falls; break; case "MACD Zero Lag histogram is higher than the Level line": indLogic = IndicatorLogic.The_indicator_is_higher_than_the_level_line; SpecialValues = new[] { dLevel, -dLevel }; break; case "MACD Zero Lag histogram is lower than the Level line": indLogic = IndicatorLogic.The_indicator_is_lower_than_the_level_line; SpecialValues = new[] { dLevel, -dLevel }; break; case "MACD Zero Lag histogram crosses the Level line upward": indLogic = IndicatorLogic.The_indicator_crosses_the_level_line_upward; SpecialValues = new[] { dLevel, -dLevel }; break; case "MACD Zero Lag histogram crosses the Level line downward": indLogic = IndicatorLogic.The_indicator_crosses_the_level_line_downward; SpecialValues = new[] { dLevel, -dLevel }; break; case "MACD Zero Lag histogram changes its direction upward": indLogic = IndicatorLogic.The_indicator_changes_its_direction_upward; break; case "MACD Zero Lag histogram changes its direction downward": indLogic = IndicatorLogic.The_indicator_changes_its_direction_downward; break; } OscillatorLogic(iFirstBar, iPrvs, adHistogram, dLevel, -dLevel, ref Component[3], ref Component[4], indLogic); } public override void SetDescription() { string sLevelLong = (Math.Abs(IndParam.NumParam[3].Value - 0) < Epsilon ? "0" : IndParam.NumParam[3].ValueToString); string sLevelShort = (Math.Abs(IndParam.NumParam[3].Value - 0) < Epsilon ? "0" : "-" + IndParam.NumParam[3].ValueToString); EntryFilterLongDescription = ToString() + " "; EntryFilterShortDescription = ToString() + " "; ExitFilterLongDescription = ToString() + " "; ExitFilterShortDescription = ToString() + " "; switch (IndParam.ListParam[0].Text) { case "MACD Zero Lag histogram rises": EntryFilterLongDescription += "rises"; EntryFilterShortDescription += "falls"; ExitFilterLongDescription += "rises"; ExitFilterShortDescription += "falls"; break; case "MACD Zero Lag histogram falls": EntryFilterLongDescription += "falls"; EntryFilterShortDescription += "rises"; ExitFilterLongDescription += "falls"; ExitFilterShortDescription += "rises"; break; case "MACD Zero Lag histogram is higher than the Level line": EntryFilterLongDescription += "is higher than the Level " + sLevelLong; EntryFilterShortDescription += "is lower than the Level " + sLevelShort; ExitFilterLongDescription += "is higher than the Level " + sLevelLong; ExitFilterShortDescription += "is lower than the Level " + sLevelShort; break; case "MACD Zero Lag histogram is lower than the Level line": EntryFilterLongDescription += "is lower than the Level " + sLevelLong; EntryFilterShortDescription += "is higher than the Level " + sLevelShort; ExitFilterLongDescription += "is lower than the Level " + sLevelLong; ExitFilterShortDescription += "is higher than the Level " + sLevelShort; break; case "MACD Zero Lag histogram crosses the Level line upward": EntryFilterLongDescription += "crosses the Level " + sLevelLong + " upward"; EntryFilterShortDescription += "crosses the Level " + sLevelShort + " downward"; ExitFilterLongDescription += "crosses the Level " + sLevelLong + " upward"; ExitFilterShortDescription += "crosses the Level " + sLevelShort + " downward"; break; case "MACD Zero Lag histogram crosses the Level line downward": EntryFilterLongDescription += "crosses the Level " + sLevelLong + " downward"; EntryFilterShortDescription += "crosses the Level " + sLevelShort + " upward"; ExitFilterLongDescription += "crosses the Level " + sLevelLong + " downward"; ExitFilterShortDescription += "crosses the Level " + sLevelShort + " upward"; break; case "MACD Zero Lag histogram changes its direction upward": EntryFilterLongDescription += "changes its direction upward"; EntryFilterShortDescription += "changes its direction downward"; ExitFilterLongDescription += "changes its direction upward"; ExitFilterShortDescription += "changes its direction downward"; break; case "MACD Zero Lag histogram changes its direction downward": EntryFilterLongDescription += "changes its direction downward"; EntryFilterShortDescription += "changes its direction upward"; ExitFilterLongDescription += "changes its direction downward"; ExitFilterShortDescription += "changes its direction upward"; break; } } public override string ToString() { return IndicatorName + (IndParam.CheckParam[0].Checked ? "* (" : " (") + IndParam.ListParam[1].Text + ", " + // Method IndParam.ListParam[2].Text + ", " + // Price IndParam.ListParam[3].Text + ", " + // Signal MA Method IndParam.NumParam[0].ValueToString + ", " + // Slow MA period IndParam.NumParam[1].ValueToString + ", " + // Fast MA period IndParam.NumParam[2].ValueToString + ")"; // Signal MA period } } }
//+--------------------------------------------------------------------+ //| Copyright: (C) 2014 Forex Software Ltd. | //| Website: http://forexsb.com/ | //| Support: http://forexsb.com/forum/ | //| License: Proprietary under the following circumstances: | //| | //| This code is a part of Forex Strategy Builder. It is free for | //| use as an integral part of Forex Strategy Builder. | //| One can modify it in order to improve the code or to fit it for | //| personal use. This code or any part of it cannot be used in | //| other applications without a permission. | //| The contact information cannot be changed. | //| | //| NO LIABILITY FOR CONSEQUENTIAL DAMAGES | //| | //| In no event shall the author be liable for any damages whatsoever | //| (including, without limitation, incidental, direct, indirect and | //| consequential damages, damages for loss of business profits, | //| business interruption, loss of business information, or other | //| pecuniary loss) arising out of the use or inability to use this | //| product, even if advised of the possibility of such damages. | //+--------------------------------------------------------------------+ #property copyright "Copyright (C) 2016 Laurent Wiart." #property link "" #property version "1.00" #property strict #include <Forexsb.com/Indicator.mqh> #include <Forexsb.com/Enumerations.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class MACDZeroLag : public Indicator { public: MACDZeroLag(SlotTypes slotType) { SlotType=slotType; IndicatorName="MACD Zero Lag"; WarningMessage = ""; IsAllowLTF = true; ExecTime = ExecutionTime_DuringTheBar; IsSeparateChart = true; IsDiscreteValues = false; IsDefaultGroupAll = false; } virtual void Calculate(DataSet &dataSet); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MACDZeroLag::Calculate(DataSet &dataSet) { Data=GetPointer(dataSet); // Reading the parameters MAMethod maMethod = (MAMethod) ListParam[1].Index; MAMethod slMethod = (MAMethod) ListParam[3].Index; BasePrice basePrice = (BasePrice) ListParam[2].Index; int nSlow = (int) NumParam[0].Value; int nFast = (int) NumParam[1].Value; int nSignal = (int) NumParam[2].Value; double dLevel = NumParam[3].Value; int iPrvs = CheckParam[0].Checked ? 1 : 0; // Calculation int iFirstBar=nSlow+nFast+2; double basePrc[]; Price(basePrice,basePrc); double adMASlow[]; MovingAverage(nSlow,0,maMethod,basePrc,adMASlow); double adMAFast[]; MovingAverage(nFast,0,maMethod,basePrc,adMAFast); double MAOfMASlow[]; MovingAverage(nSlow,0,maMethod,adMASlow,MAOfMASlow); double MAOfMAFast[]; MovingAverage(nFast,0,maMethod,adMAFast,MAOfMAFast); double adMACDZR[]; ArrayResize(adMACDZR,Data.Bars); ArrayInitialize(adMACDZR,0); double adSlowMACDZR[]; ArrayResize(adSlowMACDZR,Data.Bars); ArrayInitialize(adSlowMACDZR,0); double adFastMACDZR[]; ArrayResize(adFastMACDZR,Data.Bars); ArrayInitialize(adFastMACDZR,0); //ZeroLAG MACD(i) = (2*EMA(Close, FP, i) - EMA(EMA(Close, FP, i), FP, i)) - (2*EMA(Close, SP, i) - EMA(EMA(Close, SP, i), SP, i)); for(int iBar=nSlow-1; iBar<Data.Bars; iBar++) { adSlowMACDZR[iBar] = 2 * adMASlow[iBar] - MAOfMASlow[iBar]; adFastMACDZR[iBar] = 2 * adMAFast[iBar] - MAOfMAFast[iBar]; //adMACDZR[iBar] = adMAFast[iBar] - adMASlow[iBar]; //MACD Histogram classic adMACDZR[iBar] = adFastMACDZR[iBar] - adSlowMACDZR[iBar]; } //ZeroLAG MACD Signal(i) = 2*EMA(ZeroLAG MACD(i), SigP, i) - EMA(EMA(ZeroLAG MACD(i), SigP, i), SigP, i); double MAOfMACDZR[]; MovingAverage(nSignal,0,slMethod,adMACDZR,MAOfMACDZR); double MAOfMAOfMACDZR[]; MovingAverage(nSignal,0,slMethod,MAOfMACDZR,MAOfMAOfMACDZR); double maSignalLine[]; ArrayResize(maSignalLine,Data.Bars); ArrayInitialize(maSignalLine,0); for(int iBar=nSlow-1; iBar<Data.Bars; iBar++) { maSignalLine[iBar] = 2 * MAOfMACDZR[iBar] - MAOfMAOfMACDZR[iBar]; //MovingAverage(nSignal,0,slMethod,adMACDZR,maSignalLine); } // adHistogram represents MACD oscillator double adHistogram[]; ArrayResize(adHistogram,Data.Bars); ArrayInitialize(adHistogram,0); for(int iBar=nSlow+nSignal-1; iBar<Data.Bars; iBar++) adHistogram[iBar]=adMACDZR[iBar]-maSignalLine[iBar]; // Saving the components ArrayResize(Component[0].Value,Data.Bars); Component[0].CompName = "Histogram"; Component[0].DataType = IndComponentType_IndicatorValue; Component[0].FirstBar = iFirstBar; ArrayCopy(Component[0].Value,adHistogram); ArrayResize(Component[1].Value,Data.Bars); Component[1].CompName = "Signal line"; Component[1].DataType = IndComponentType_IndicatorValue; Component[1].FirstBar = iFirstBar; ArrayCopy(Component[1].Value,maSignalLine); ArrayResize(Component[2].Value,Data.Bars); Component[2].CompName = "MACD line"; Component[2].DataType = IndComponentType_IndicatorValue; Component[2].FirstBar = iFirstBar; ArrayCopy(Component[2].Value,adMACDZR); ArrayResize(Component[3].Value,Data.Bars); Component[3].FirstBar=iFirstBar; ArrayResize(Component[4].Value,Data.Bars); Component[4].FirstBar=iFirstBar; // Sets the Component's type if(SlotType==SlotTypes_OpenFilter) { Component[3].DataType = IndComponentType_AllowOpenLong; Component[3].CompName = "Is long entry allowed"; Component[4].DataType = IndComponentType_AllowOpenShort; Component[4].CompName = "Is short entry allowed"; } else if(SlotType==SlotTypes_CloseFilter) { Component[3].DataType = IndComponentType_ForceCloseLong; Component[3].CompName = "Close out long position"; Component[4].DataType = IndComponentType_ForceCloseShort; Component[4].CompName = "Close out short position"; } // Calculation of the logic IndicatorLogic indLogic=IndicatorLogic_It_does_not_act_as_a_filter; if(ListParam[0].Text=="MACD Zero Lag rises") indLogic=IndicatorLogic_The_indicator_rises; else if(ListParam[0].Text=="MACD Zero Lag falls") indLogic=IndicatorLogic_The_indicator_falls; else if(ListParam[0].Text=="MACD Zero Lag is higher than the Level line") indLogic=IndicatorLogic_The_indicator_is_higher_than_the_level_line; else if(ListParam[0].Text=="MACD Zero Lag is lower than the Level line") indLogic=IndicatorLogic_The_indicator_is_lower_than_the_level_line; else if(ListParam[0].Text=="MACD Zero Lag crosses the Level line upward") indLogic=IndicatorLogic_The_indicator_crosses_the_level_line_upward; else if(ListParam[0].Text=="MACD Zero Lag crosses the Level line downward") indLogic=IndicatorLogic_The_indicator_crosses_the_level_line_downward; else if(ListParam[0].Text=="MACD Zero Lag changes its direction upward") indLogic=IndicatorLogic_The_indicator_changes_its_direction_upward; else if(ListParam[0].Text=="MACD Zero Lag changes its direction downward") indLogic=IndicatorLogic_The_indicator_changes_its_direction_downward; OscillatorLogic(iFirstBar,iPrvs,adHistogram,dLevel,-dLevel,Component[3],Component[4],indLogic); } //+------------------------------------------------------------------+
Risk warning: Forex, spread bets and CFD are leveraged products. They may not be suitable for you as they carry a high degree of risk to your capital and you can lose more than your initial investment. You should ensure you understand all of the risks.
Copyright © 2006 - 2017, Miroslav Popov; Created by Yavor Kirov