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.
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.
| Buffer | Classic MACD | MT4 built-in |
|---|---|---|
| MODE_MAIN | EMA12 − EMA26 (line) | EMA12 − EMA26 (drawn as histogram) |
| MODE_SIGNAL | EMA9 of main (line) | SMA9 of main (line) |
| Histogram | main − signal | Not 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
- Timing. Divergence can persist through several more pushes. In a strong trend it appears repeatedly and resolves only at the end.
- Magnitude. A divergence before a ten-pip pullback and one before a reversal look identical at the moment of detection.
- Direction, reliably. It signals weakening momentum. Weakening momentum frequently precedes continuation after a pause.
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.