FXTAA Русская версия

MACD divergence indicator for MT4

Divergence is one of the few technical concepts with a mechanical definition — which makes it automatable, and makes the automation's weaknesses precise rather than vague.

Updated: 2026-09-22

Divergence means price and an oscillator disagree about the strength of a move. Price makes a higher high; the oscillator makes a lower high. The interpretation is that the second push had less momentum behind it.

MT4's MACD is not the classic MACD

This catches people constantly. The standard MACD has three components: a fast line (EMA12 − EMA26), a signal line (EMA9 of the fast line), and a histogram of the difference between them.

MetaTrader 4's built-in indicator draws the fast line as the histogram and the signal line as a line. There is no histogram of the difference at all. So a strategy written against classic MACD and applied to MT4's version is reading different numbers than its author intended.

BufferClassic MACDMT4 built-in
MODE_MAINEMA12 − EMA26 (line)EMA12 − EMA26 (drawn as histogram)
MODE_SIGNALEMA9 of main (line)SMA9 of main (line)
Histogrammain − signalNot present

If you want the classic behaviour, compute iMACD(...,MODE_MAIN,i) - iMACD(...,MODE_SIGNAL,i) yourself. Do not assume the visual matches what you read about elsewhere.

Finding the pivots

Divergence detection reduces to finding two swing highs (or lows) in price and comparing the oscillator at those same bars. Everything difficult lives in "finding".

// A swing high: strictly higher than `depth` bars on each side
bool IsSwingHigh(int i, int depth)
{
   for(int k = 1; k <= depth; k++)
      if(High[i] <= High[i+k] || High[i] <= High[i-k]) return(false);
   return(true);
}

// Scan back for the two most recent confirmed swing highs
int FindDivergence(int depth, int maxBars)
{
   int found = 0, idx[2];

   for(int i = depth; i < maxBars && found < 2; i++)
   {
      if(i - depth < 0) continue;            // right side must exist = confirmed
      if(IsSwingHigh(i, depth)) { idx[found] = i; found++; }
   }
   if(found < 2) return(0);

   int recent = idx[0], older = idx[1];

   double pRecent = High[recent],  pOlder = High[older];
   double mRecent = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, recent);
   double mOlder  = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, older);

   if(pRecent > pOlder && mRecent < mOlder) return(-1);   // bearish divergence
   if(pRecent < pOlder && mRecent > mOlder) return(+1);   // bullish (on lows)
   return(0);
}

Why confirmation costs you `depth` bars

A swing high is only a swing high once enough bars have formed to its right. With depth = 5 you learn about the pivot five bars after it happened. That delay is not a flaw in the code — it is the definition.

Indicators that show divergence instantly are reporting unconfirmed pivots, which disappear when the next bar makes a new extreme. That is repainting, and it is the single most common reason a divergence indicator looks perfect on history and useless live.

If an indicator never shows a divergence that later vanishes, it is either waiting for confirmation or lying to you about the past.

What divergence does not tell you

The practical use is as a filter rather than a trigger: do not add to a position into divergence, tighten a stop when it appears, or require it as one of several conditions before a counter-trend entry.

Hidden divergence

The less-discussed variant inverts the comparison: price makes a higher low while the oscillator makes a lower low. This is read as trend continuation rather than reversal, and it fires during pullbacks. The detection code is the same with the inequalities swapped.