This indicator is useful for coders because there's a standalone iZeroLagMACD function.
Code: Select all
//-------------------------------------------------------------------
// ZeroLag MACD function - self-contained, no iCustom dependency
// mode: 0 = MACD line, 1 = Signal line
// Uses double-EMA (EMA of EMA) for zero-lag filtering on fast, slow, and signal
//-------------------------------------------------------------------
double iZeroLagMACD(const string symbol, int timeframe, int fastPeriod, int slowPeriod, int signalPeriod, int priceType, int mode, int index)
{
// EMA needs enough warm-up bars for convergence
int depth = MathMax(slowPeriod, fastPeriod) * 10;
int totalBars = iBars(symbol, timeframe);
if (depth > totalBars - index) depth = totalBars - index;
if (depth < 2) return(0);
double alpha1 = 2.0 / (1.0 + fastPeriod);
double alpha2 = 2.0 / (1.0 + slowPeriod);
double alpha3 = 2.0 / (1.0 + signalPeriod);
// Work arrays: ema11=fast EMA1, ema12=fast EMA2, ema21=slow EMA1, ema22=slow EMA2
double ema11, ema12, ema21, ema22, ema31, ema32;
double macdVal, signalVal;
int n;
// Start from the oldest bar and iterate forward
int startBar = index + depth - 1;
double price = iMA(symbol, timeframe, 1, 0, MODE_SMA, priceType, startBar);
ema11 = price;
ema12 = price;
ema21 = price;
ema22 = price;
macdVal = 0;
ema31 = 0;
ema32 = 0;
for (n = startBar - 1; n >= index; n--)
{
price = iMA(symbol, timeframe, 1, 0, MODE_SMA, priceType, n);
ema11 = ema11 + alpha1 * (price - ema11);
ema12 = ema12 + alpha1 * (ema11 - ema12);
ema21 = ema21 + alpha2 * (price - ema21);
ema22 = ema22 + alpha2 * (ema21 - ema22);
macdVal = (2.0 * ema11 - ema12) - (2.0 * ema21 - ema22);
ema31 = ema31 + alpha3 * (macdVal - ema31);
ema32 = ema32 + alpha3 * (ema31 - ema32);
}
if (mode == 0)
return(macdVal); // MACD line
signalVal = 2.0 * ema31 - ema32;
return(signalVal); // Signal line
}
//-------------------------------------------------------------------