Gold SMC EA MT5: Smart Money Concept Expert Advisor for XAUUSD
This page delivers a fully coded Gold SMC EA for MetaTrader 5 that automates Smart Money Concept trading on XAUUSD, targeting institutional order blocks, liquidity sweeps, and break-of-structure signals. The expert advisor is designed for traders who want to systematically exploit market-maker patterns on gold without manual chart watching.
Backtest Performance
Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.
Strategy Logic
Entry Conditions
The EA identifies bullish or bearish order blocks on the H1 chart by detecting the last up- or down-candle before a strong impulsive move, then waits for price to retrace and close inside that block. A market entry is triggered on the next candle open only when the higher-timeframe trend (H4 200-period EMA) aligns with the order block direction. An additional filter confirms that a liquidity sweep of a prior swing high or low occurred within the last 20 bars before entry, validating institutional activity.
Exit Conditions
Stop loss is placed 5 points beyond the opposite edge of the identified order block, giving the trade room to breathe while capping structural risk. Take profit is set at a fixed 1.8 R:R multiple of the stop-loss distance, targeting the next opposing swing liquidity pool. The EA also applies a break-even rule that moves the stop to entry price once price reaches 1.0 R in profit, locking in gains on trending gold moves.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| Gold SMC EA — Smart Money Concept Expert Advisor for XAUUSD |
//| Platform : MetaTrader 5 (MQL5 5.x) |
//| Symbol : XAUUSD | Timeframe: H1 |
//| DISCLAIMER: For educational purposes only. Past backtest results |
//| (win rate 54.9 %, max DD 12.6 %, Sharpe 1.52, 2023–2025) do |
//| not guarantee future performance. Trade at your own risk. |
//+------------------------------------------------------------------+
#property copyright "Pineify.app"
#property version "1.00"
#property strict
//--- Input parameters
input double InpLotSize = 0.10; // Fixed lot size
input int InpOBLookback = 5; // Order-block lookback (bars)
input int InpLiqLookback = 20; // Liquidity sweep lookback (bars)
input double InpRR = 1.8; // Take-profit R:R multiplier
input int InpH4EMAPeriod = 200; // H4 trend EMA period
input int InpMagicNumber = 202501; // EA magic number
input double InpSlippage = 3.0; // Max slippage in points
//--- Global handles & state
int g_h4EmaHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
bool g_inTrade = false;
//+------------------------------------------------------------------+
//| Helper: get H4 200-EMA value |
//+------------------------------------------------------------------+
double GetH4EMA()
{
double buf[];
ArraySetAsSeries(buf, true);
if(CopyBuffer(g_h4EmaHandle, 0, 0, 1, buf) < 1)
return 0.0;
return buf[0];
}
//+------------------------------------------------------------------+
//| Helper: detect bullish order block index on H1 |
//| Returns bar index of last up-candle before bearish impulse, or -1|
//+------------------------------------------------------------------+
int FindBullishOB(int lookback)
{
// Find the most recent bearish impulse (close drops > 2x ATR in 1 bar)
double atr[];
ArraySetAsSeries(atr, true);
int atrHandle = iATR(_Symbol, PERIOD_H1, 14);
if(atrHandle == INVALID_HANDLE) return -1;
if(CopyBuffer(atrHandle, 0, 1, lookback + 2, atr) < lookback + 1)
{ IndicatorRelease(atrHandle); return -1; }
for(int i = 1; i <= lookback; i++)
{
double open = iOpen(_Symbol, PERIOD_H1, i);
double close = iClose(_Symbol, PERIOD_H1, i);
double range = MathAbs(open - close);
if(close < open && range > 1.5 * atr[i]) // bearish impulse bar
{
// The order block is the last bullish candle just before this impulse
for(int j = i + 1; j <= i + 3; j++)
{
double jClose = iClose(_Symbol, PERIOD_H1, j);
double jOpen = iOpen(_Symbol, PERIOD_H1, j);
if(jClose > jOpen)
{ IndicatorRelease(atrHandle); return j; } // bullish OB found
}
}
}
IndicatorRelease(atrHandle);
return -1;
}
//+------------------------------------------------------------------+
//| Helper: detect bearish order block index on H1 |
//+------------------------------------------------------------------+
int FindBearishOB(int lookback)
{
double atr[];
ArraySetAsSeries(atr, true);
int atrHandle = iATR(_Symbol, PERIOD_H1, 14);
if(atrHandle == INVALID_HANDLE) return -1;
if(CopyBuffer(atrHandle, 0, 1, lookback + 2, atr) < lookback + 1)
{ IndicatorRelease(atrHandle); return -1; }
for(int i = 1; i <= lookback; i++)
{
double open = iOpen(_Symbol, PERIOD_H1, i);
double close = iClose(_Symbol, PERIOD_H1, i);
double range = MathAbs(open - close);
if(close > open && range > 1.5 * atr[i]) // bullish impulse bar
{
for(int j = i + 1; j <= i + 3; j++)
{
double jClose = iClose(_Symbol, PERIOD_H1, j);
double jOpen = iOpen(_Symbol, PERIOD_H1, j);
if(jClose < jOpen)
{ IndicatorRelease(atrHandle); return j; } // bearish OB found
}
}
}
IndicatorRelease(atrHandle);
return -1;
}
//+------------------------------------------------------------------+
//| Helper: check liquidity sweep within lookback bars |
//+------------------------------------------------------------------+
bool LiquiditySweepDetected(bool bullish, int lookback)
{
// Bullish sweep: wick below prior swing low then closes above it
// Bearish sweep: wick above prior swing high then closes below it
double swingLevel = bullish
? iLow(_Symbol, PERIOD_H1, iLowest(_Symbol, PERIOD_H1, MODE_LOW, lookback, 2))
: iHigh(_Symbol, PERIOD_H1, iHighest(_Symbol, PERIOD_H1, MODE_HIGH, lookback, 2));
for(int i = 1; i < lookback; i++)
{
double lo = iLow(_Symbol, PERIOD_H1, i);
double hi = iHigh(_Symbol, PERIOD_H1, i);
double cl = iClose(_Symbol, PERIOD_H1, i);
if(bullish && lo < swingLevel && cl > swingLevel) return true;
if(!bullish && hi > swingLevel && cl < swingLevel) return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Helper: check for open EA position |
//+------------------------------------------------------------------+
bool HasOpenPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
(long)PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Helper: apply break-even once 1.0 R reached |
//+------------------------------------------------------------------+
void ManageBreakEven()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if((long)PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double riskPts = MathAbs(openPrice - sl);
if(riskPts == 0) continue;
if(posType == POSITION_TYPE_BUY && sl < openPrice)
{
if(bid >= openPrice + riskPts) // 1R profit reached
{
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_SLTP;
req.symbol = _Symbol;
req.sl = openPrice + _Point;
req.tp = tp;
req.position = ticket;
OrderSend(req, res);
}
}
else if(posType == POSITION_TYPE_SELL && sl > openPrice)
{
if(ask <= openPrice - riskPts)
{
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_SLTP;
req.symbol = _Symbol;
req.sl = openPrice - _Point;
req.tp = tp;
req.position = ticket;
OrderSend(req, res);
}
}
}
}
//+------------------------------------------------------------------+
//| OnInit |
//+------------------------------------------------------------------+
int OnInit()
{
g_h4EmaHandle = iMA(_Symbol, PERIOD_H4, InpH4EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(g_h4EmaHandle == INVALID_HANDLE)
{
Print("Failed to create H4 EMA handle");
return INIT_FAILED;
}
Print("Gold SMC EA initialised. Magic=", InpMagicNumber);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| OnTick |
//+------------------------------------------------------------------+
void OnTick()
{
// Run logic once per closed H1 bar
datetime currentBarTime = iTime(_Symbol, PERIOD_H1, 0);
if(currentBarTime == g_lastBarTime) { ManageBreakEven(); return; }
g_lastBarTime = currentBarTime;
if(HasOpenPosition()) { ManageBreakEven(); return; }
double h4Ema = GetH4EMA();
double h1Close = iClose(_Symbol, PERIOD_H1, 1);
if(h4Ema == 0) return;
bool bullTrend = h1Close > h4Ema;
bool bearTrend = h1Close < h4Ema;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = _Point;
//--- Bullish SMC setup
if(bullTrend)
{
int obIdx = FindBullishOB(InpOBLookback);
if(obIdx > 0 && LiquiditySweepDetected(true, InpLiqLookback))
{
double obHigh = iHigh(_Symbol, PERIOD_H1, obIdx);
double obLow = iLow(_Symbol, PERIOD_H1, obIdx);
// Price must be retracing into OB zone
if(ask >= obLow && ask <= obHigh)
{
double sl = obLow - 5 * pt;
double tp = ask + InpRR * (ask - sl);
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = InpLotSize;
req.type = ORDER_TYPE_BUY;
req.price = ask;
req.sl = sl;
req.tp = tp;
req.magic = InpMagicNumber;
req.deviation = (ulong)InpSlippage;
req.comment = "GoldSMC_BUY";
req.type_filling = ORDER_FILLING_IOC;
if(!OrderSend(req, res))
Print("BUY order failed: ", GetLastError(), " retcode=", res.retcode);
}
}
}
//--- Bearish SMC setup
if(bearTrend)
{
int obIdx = FindBearishOB(InpOBLookback);
if(obIdx > 0 && LiquiditySweepDetected(false, InpLiqLookback))
{
double obHigh = iHigh(_Symbol, PERIOD_H1, obIdx);
double obLow = iLow(_Symbol, PERIOD_H1, obIdx);
if(bid >= obLow && bid <= obHigh)
{
double sl = obHigh + 5 * pt;
double tp = bid - InpRR * (sl - bid);
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = InpLotSize;
req.type = ORDER_TYPE_SELL;
req.price = bid;
req.sl = sl;
req.tp = tp;
req.magic = InpMagicNumber;
req.deviation = (ulong)InpSlippage;
req.comment = "GoldSMC_SELL";
req.type_filling = ORDER_FILLING_IOC;
if(!OrderSend(req, res))
Print("SELL order failed: ", GetLastError(), " retcode=", res.retcode);
}
}
}
}
//+------------------------------------------------------------------+
//| OnDeinit |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_h4EmaHandle != INVALID_HANDLE)
IndicatorRelease(g_h4EmaHandle);
Print("Gold SMC EA removed. Reason code: ", reason);
}
//+------------------------------------------------------------------+Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.
Generate a Custom XAUUSD SMC EA →
Pineify AI generates syntactically validated MQL5 Expert Advisors from plain English descriptions. Customize entry logic, risk management, and trading sessions — no coding required.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Bar-based, backtesting only | Tick-based, live trading |
| Deployment | TradingView alerts | Runs 24/5 on VPS/MT5 |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Built-in, no data download needed | Strategy Tester, tick data required |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
Pineify supports both platforms. Prototype your strategy visually in TradingView Pine Script, then generate the equivalent MQL5 EA for live MT5 trading.