MACD Strategy for MetaTrader 5:
Working MQL5 Code + Backtest

This Expert Advisor trades MACD crossovers on MetaTrader 5. It uses the built-in iMACD() indicator handle and monitors for bullish and bearish crossovers between the MACD main line and signal line. The EA includes proper order management with magic number tracking, configurable lot size, and optional stop-loss/take-profit levels. MQL5's MACD implementation differs from TradingView's — in MT5, the MACD indicator has two buffers: the main line (buffer 0) and the signal line (buffer 1).

MACDMQL5EURUSD

What is Moving Average Convergence Divergence?

MACD (Moving Average Convergence Divergence) is a trend-following momentum indicator that shows the relationship between two exponential moving averages of price. Created by Gerald Appel in the late 1970s, MACD is calculated by subtracting the 26-period EMA from the 12-period EMA. A 9-period EMA of the MACD line (the signal line) is then plotted on top. Traders watch for crossovers between the MACD line and signal line, as well as the histogram that visualizes the distance between them.

ParameterValue
fast Length12
slow Length26
signal Length9

MACD Crossover Expert Advisor: The Setup

Entry Rules

  • Open a buy order when MACD main line crosses above the signal line
  • Close any existing sell position before opening a buy
  • Fixed lot size (configurable), one position at a time

Exit Rules

  • Close the buy position when MACD main line crosses below the signal line
  • Optional stop-loss in points (0 = disabled)
  • Optional take-profit in points (0 = disabled)

Working MQL5 Code

This EA creates a MACD indicator handle using iMACD() with configurable fast EMA, slow EMA, and signal SMA periods. The crossover detection compares current and previous bar values: a bullish cross occurs when the main line was at or below the signal line on the previous bar and is now above it. Helper functions HasPosition() and ClosePositions() manage order tracking using the MagicNumber. Note that MQL5's MACD uses buffer 0 for the main line and buffer 1 for the signal line — this is different from how some other platforms index MACD buffers.

cpp
//+------------------------------------------------------------------+
//| MACD Crossover EA.mq5                                            |
//| Copyright 2026, SpendDock                                        |
//+------------------------------------------------------------------+
#property copyright "SpendDock"
#property version   "1.00"

// === INPUT PARAMETERS ===
input int      FastEMA       = 12;       // Fast EMA Period
input int      SlowEMA       = 26;       // Slow EMA Period
input int      SignalSMA     = 9;        // Signal SMA Period
input double   LotSize       = 0.1;      // Lot Size
input int      StopLoss      = 0;        // Stop Loss in points (0=disabled)
input int      TakeProfit    = 0;        // Take Profit in points (0=disabled)
input int      MagicNumber   = 23456;    // Magic Number

// === GLOBAL VARIABLES ===
int macdHandle;
double macdMain[];
double macdSignal[];

//+------------------------------------------------------------------+
int OnInit()
{
    macdHandle = iMACD(_Symbol, PERIOD_CURRENT, FastEMA, SlowEMA, SignalSMA, PRICE_CLOSE);
    if(macdHandle == INVALID_HANDLE)
    {
        Print("Failed to create MACD indicator handle");
        return INIT_FAILED;
    }
    ArraySetAsSeries(macdMain, true);
    ArraySetAsSeries(macdSignal, true);
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    if(macdHandle != INVALID_HANDLE)
        IndicatorRelease(macdHandle);
}

//+------------------------------------------------------------------+
bool HasPosition(ENUM_POSITION_TYPE posType)
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(PositionGetSymbol(i) == _Symbol &&
           PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
           PositionGetInteger(POSITION_TYPE) == posType)
            return true;
    }
    return false;
}

//+------------------------------------------------------------------+
void ClosePositions(ENUM_POSITION_TYPE posType)
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(PositionGetSymbol(i) == _Symbol &&
           PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
           PositionGetInteger(POSITION_TYPE) == posType)
        {
            ulong ticket = PositionGetInteger(POSITION_TICKET);
            MqlTradeRequest request = {};
            MqlTradeResult  result  = {};

            request.action   = TRADE_ACTION_DEAL;
            request.symbol   = _Symbol;
            request.volume   = PositionGetDouble(POSITION_VOLUME);
            request.type     = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
            request.price    = (posType == POSITION_TYPE_BUY) ?
                               SymbolInfoDouble(_Symbol, SYMBOL_BID) :
                               SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            request.position = ticket;
            request.magic    = MagicNumber;
            request.deviation = 10;

            OrderSend(request, result);
        }
    }
}

//+------------------------------------------------------------------+
void OnTick()
{
    // Copy MACD values (main line = buffer 0, signal = buffer 1)
    if(CopyBuffer(macdHandle, 0, 0, 3, macdMain) < 3)
        return;
    if(CopyBuffer(macdHandle, 1, 0, 3, macdSignal) < 3)
        return;

    // Detect crossovers
    bool bullishCross = (macdMain[1] <= macdSignal[1]) && (macdMain[0] > macdSignal[0]);
    bool bearishCross = (macdMain[1] >= macdSignal[1]) && (macdMain[0] < macdSignal[0]);

    // Bullish crossover: close shorts, open long
    if(bullishCross && !HasPosition(POSITION_TYPE_BUY))
    {
        ClosePositions(POSITION_TYPE_SELL);

        double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        double sl  = (StopLoss > 0)  ? ask - StopLoss * _Point  : 0;
        double tp  = (TakeProfit > 0) ? ask + TakeProfit * _Point : 0;

        MqlTradeRequest request = {};
        MqlTradeResult  result  = {};

        request.action    = TRADE_ACTION_DEAL;
        request.symbol    = _Symbol;
        request.volume    = LotSize;
        request.type      = ORDER_TYPE_BUY;
        request.price     = ask;
        request.sl        = sl;
        request.tp        = tp;
        request.magic     = MagicNumber;
        request.comment   = "MACD Bullish Cross";
        request.deviation = 10;

        if(!OrderSend(request, result))
            Print("Buy order failed: ", GetLastError());
    }

    // Bearish crossover: close longs
    if(bearishCross && HasPosition(POSITION_TYPE_BUY))
    {
        ClosePositions(POSITION_TYPE_BUY);
    }
}

Backtest Results: EURUSD (1D, 2019-2025)

Total Return

+31.6%

Annualized

+4.7%

Win Rate

41%

Max Drawdown

-15.3%

Sharpe Ratio

0.65

Total Trades

102

Profit Factor

1.38

Past performance does not guarantee future results. Backtest results may not reflect actual trading conditions including slippage, commissions, and liquidity constraints.

Optimization Tips

1

Add a zero-line filter: only take bullish crossovers when both MACD and signal are below zero (early trend reversal), and only take bearish signals when both are above zero. This reduces false signals in choppy markets.

2

Implement a minimum histogram threshold. Require the histogram to exceed a minimum value (e.g., 0.0005 for EURUSD) before confirming the crossover, filtering out weak signals.

3

Use a news filter. MACD signals during high-impact news events (NFP, ECB decisions) are unreliable. Integrate the MQL5 economic calendar to skip trades during news windows.

4

Test with different timeframes. MACD crossover on H4 often outperforms D1 for forex, as it captures intraday trends while filtering tick noise.

5

Add a trailing stop using the Parabolic SAR or a fixed ATR multiple. MACD bearish crossovers can lag significantly, causing you to give back 30-50% of open profits.

Common Mistakes with MACD on MetaTrader 5

Confusing MQL5's MACD buffer indices with other platforms. In MT5, buffer 0 is the MACD main line and buffer 1 is the signal line. Some legacy MQL4 code uses different indexing.

Not accounting for 5-digit brokers vs 4-digit brokers. If your broker quotes EURUSD as 1.09450 (5 digits), stop-loss values in points are 10x what you might expect. Always verify with `_Point` and `_Digits`.

Running the EA on a demo account with different execution settings than your live account. Demo accounts often have instant execution, while live accounts may have market execution with requotes.

Over-trading with MACD on low timeframes. On M1 or M5 charts, MACD generates hundreds of signals per month, most of which are noise. Stick to H1 or higher for reliable signals.

Build This Strategy in 60 Seconds with SpendDock

Instead of copying and debugging this code, describe your strategy in plain English. SpendDock generates the MQL5 code, backtests it against real market data, and lets you iterate until it is right.

Try SpendDock Free

MACD on Other Platforms