XAUUSD Expert Advisor MT5: H1 EMA/ADX MQL5 Example and Test Guide
A complete educational MQL5 Expert Advisor for an H1 50/200 EMA cross with ADX confirmation. Attach it to the actual broker-provided gold symbol; the source uses that chart symbol and does not identify gold contracts automatically. It demonstrates initial ATR exits and estimated stop-loss sizing, not validated live performance or a daily loss guard.
Strategy logic
Entry conditions
On each new H1 bar, the EA waits for all four indicator buffers. It compares two completed EMA values for a strict crossover and checks completed ADX against its threshold. ATR must be positive but there is no separate minimum-volatility filter. A matching symbol/magic position blocks another entry. Attaching mid-bar can evaluate the most recently completed cross; restart state is not persisted.
Exit conditions
Initial stop and target distances are one and two completed ATR values from the requested entry quote, rounded to the broker tick grid. There is no trailing stop, daily drawdown emergency close, opposite-cross close, news filter or spread limit. Requested 1:2 distances are not a realized reward-to-risk guarantee: rounding, actual fills, costs and gaps affect outcomes. Stops are broker requests and can be rejected.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| XAUUSD Expert Advisor - Trend Following H1 |
//| Pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify.app"
#property version "1.00"
input int MagicNumber = 456789;
input double RiskPercent = 1.0;
input int EMA_Fast = 50;
input int EMA_Slow = 200;
input int ADX_Period = 14;
input double ADX_Min = 25.0;
input int ATR_Period = 14;
int emaFastH=INVALID_HANDLE, emaSlowH=INVALID_HANDLE, adxH=INVALID_HANDLE, atrH=INVALID_HANDLE;
datetime lastBar=0;
double emaFast[], emaSlow[], adxMain[], atrBuf[];
int OnInit() {
if(MagicNumber<=0 || RiskPercent<=0 || RiskPercent>100 || EMA_Fast<1 || EMA_Slow<=EMA_Fast || ADX_Period<1 || ADX_Min<0 || ADX_Min>100 || ATR_Period<1) return INIT_PARAMETERS_INCORRECT;
emaFastH = iMA(_Symbol, PERIOD_H1, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
emaSlowH = iMA(_Symbol, PERIOD_H1, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
adxH = iADX(_Symbol, PERIOD_H1, ADX_Period);
atrH = iATR(_Symbol, PERIOD_H1, ATR_Period);
if(emaFastH==INVALID_HANDLE || emaSlowH==INVALID_HANDLE || adxH==INVALID_HANDLE || atrH==INVALID_HANDLE) return INIT_FAILED;
ArraySetAsSeries(emaFast, true); ArraySetAsSeries(emaSlow, true);
ArraySetAsSeries(adxMain, true); ArraySetAsSeries(atrBuf, true);
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason) {
IndicatorRelease(emaFastH); IndicatorRelease(emaSlowH);
IndicatorRelease(adxH); IndicatorRelease(atrH);
}
void OnTick() {
datetime current=iTime(_Symbol,PERIOD_H1,0);
if(current==0 || current==lastBar) return;
if(CopyBuffer(emaFastH,0,0,3,emaFast)!=3 || CopyBuffer(emaSlowH,0,0,3,emaSlow)!=3 ||
CopyBuffer(adxH,0,0,3,adxMain)!=3 || CopyBuffer(atrH,0,0,3,atrBuf)!=3 || atrBuf[1]<=0) return;
lastBar=current;
if (CountPositions(MagicNumber) > 0) return;
bool adxConfirm = adxMain[1] >= ADX_Min;
double atr = atrBuf[1];
double sl = atr * 1.0;
double tp = atr * 2.0;
bool goldenCross = emaFast[2] < emaSlow[2] && emaFast[1] > emaSlow[1];
bool deathCross = emaFast[2] > emaSlow[2] && emaFast[1] < emaSlow[1];
if (goldenCross && adxConfirm) OpenTrade(ORDER_TYPE_BUY, sl, tp, MagicNumber);
if (deathCross && adxConfirm) OpenTrade(ORDER_TYPE_SELL, sl, tp, MagicNumber);
}
double CalcLots(ENUM_ORDER_TYPE side,double entry,double stop) {
double minimum=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN),maximum=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
double step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP),loss=0;
double budget=AccountInfoDouble(ACCOUNT_BALANCE)*RiskPercent/100.0;
if(minimum<=0 || maximum<minimum || step<=0 || budget<=0 || entry<=0 || stop<=0) return 0;
if(!OrderCalcProfit(side,_Symbol,minimum,entry,stop,loss) || loss>=0) return 0;
double lots=NormalizeDouble(MathFloor(MathMin(budget*minimum/MathAbs(loss),maximum)/step)*step,8);
return lots>=minimum?lots:0;
}
int CountPositions(int magic) {
int n = 0;
for (int i = PositionsTotal()-1; i >= 0; i--) {
ulong t = PositionGetTicket(i);
if (PositionSelectByTicket(t) && PositionGetString(POSITION_SYMBOL)==_Symbol &&
(int)PositionGetInteger(POSITION_MAGIC)==magic) n++;
} return n;
}
void OpenTrade(ENUM_ORDER_TYPE type,double sl,double tp,int magic) {
MqlTick tick; if(!SymbolInfoTick(_Symbol,tick) || tick.ask<=0 || tick.bid<=0) return;
double grid=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); if(grid<=0) return;
MqlTradeRequest req={}; MqlTradeResult res={};
req.action=TRADE_ACTION_DEAL; req.symbol=_Symbol; req.type=type;
req.price=(type==ORDER_TYPE_BUY)?tick.ask:tick.bid;
req.sl=NormalizeDouble(MathRound(((type==ORDER_TYPE_BUY)?req.price-sl:req.price+sl)/grid)*grid,_Digits);
req.tp=NormalizeDouble(MathRound(((type==ORDER_TYPE_BUY)?req.price+tp:req.price-tp)/grid)*grid,_Digits);
req.volume=CalcLots(type,req.price,req.sl); if(req.volume<=0) return;
req.magic=magic; req.comment="Pineify XAUUSD"; req.type_filling=ORDER_FILLING_IOC;
if(!OrderSend(req,res) || (res.retcode!=TRADE_RETCODE_DONE && res.retcode!=TRADE_RETCODE_DONE_PARTIAL))
Print("Order rejected: ",res.retcode," ",res.comment);
else Print("Execution response: ",res.retcode," volume=",res.volume);
}Copy this code into MetaEditor, save it in the MQL5/Experts folder, and compile with F7.
Generate a custom XAUUSD trend-following EA
Describe the entry, exit, position, order, and risk rules you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Series evaluated on chart updates | Event handlers with explicit buffers |
| Deployment | Runs in TradingView with alerts | Runs in the MT5 terminal or on a VPS |
| Broker access | Strategy orders are simulated; live automation needs a separate integration | Direct broker connectivity |
| Backtesting | Strategy Tester for strategy scripts | Strategy Tester for Expert Advisors |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
The calculation can be implemented on either platform, but the runtime model and buffer APIs differ.
Frequently Asked Questions
Related MQL5 pages
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.