Complete .mq5 source code

Gold Trend Following EA MT5: MQL5 XAUUSD Trend Strategy & Code

Study an H1 dual-EMA Expert Advisor with completed-bar signals, an ATR entry threshold and requested initial/trailing stops. The full MQL5 example is intended for code inspection and independent testing. It provides no verified gold performance record or evidence that these defaults are optimal.

Strategy logic

Entry conditions

Evaluate the completed H1 EMA 20/50 crossover once per new H1 bar. A buy or sell request also requires completed ATR 14 at least ATR_Min_Filter, measured in the symbol price units. The default 0.5 is a threshold choice, not an account-currency risk budget or proof that whipsaws are avoided. The source checks matching symbol-and-magic positions before entry and uses fixed lots.

Exit conditions

At each new H1 bar, request closure of positions opposite the completed crossover, then evaluate trailing stops before the ATR entry filter. Do not open the new direction while an opposite position remains after a failed or partial close. Initial requested SL and TP are 1.5 and 2.5 times ATR from the entry quote. Trailing uses the latest completed ATR for activation and distance and only tightens; it is not managed every tick or guaranteed to preserve profit. IOC can partially fill; reconcile results and test broker and account-mode constraints.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  GoldTrendFollowingEA.mq5                                        |
//|  XAUUSD Dual EMA Trend Following Expert Advisor                  |
//|  For MetaTrader 5 — MQL5 5.x compatible                         |
//|  DISCLAIMER: For educational purposes only. Past performance      |
//|  does not guarantee future results. Trade at your own risk.      |
//+------------------------------------------------------------------+
#property copyright "Pineify Example"
#property version   "1.00"
#property strict

//--- Input parameters
input int      FastEMA_Period   = 20;       // Fast EMA period
input int      SlowEMA_Period   = 50;       // Slow EMA period
input int      ATR_Period       = 14;       // ATR period
input double   ATR_SL_Mult     = 1.5;      // Stop-loss ATR multiplier
input double   ATR_TP_Mult     = 2.5;      // Take-profit ATR multiplier
input double   ATR_Trail_Mult  = 1.0;      // Trailing stop ATR multiplier
input double   ATR_Min_Filter  = 0.5;      // Min ATR in symbol price units for entry
input double   LotSize         = 0.10;     // Fixed lot size
input ulong    MagicNumber     = 20240001; // EA magic number

//--- Indicator handles
int handleFastEMA=INVALID_HANDLE;
int handleSlowEMA=INVALID_HANDLE;
int handleATR=INVALID_HANDLE;

//--- Buffers
double fastEMABuf[];
double slowEMABuf[];
double atrBuf[];

//+------------------------------------------------------------------+
//| Expert initialization function                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(FastEMA_Period<1 || SlowEMA_Period<1 || ATR_Period<1 || ATR_SL_Mult<=0 || ATR_TP_Mult<=0 ||
      ATR_Trail_Mult<=0 || ATR_Min_Filter<0 || LotSize<=0) return INIT_PARAMETERS_INCORRECT;
   // Create indicator handles
   handleFastEMA = iMA(_Symbol, PERIOD_H1, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
   handleSlowEMA = iMA(_Symbol, PERIOD_H1, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
   handleATR     = iATR(_Symbol, PERIOD_H1, ATR_Period);

   if(handleFastEMA == INVALID_HANDLE || handleSlowEMA == INVALID_HANDLE || handleATR == INVALID_HANDLE)
     {
      Print("ERROR: Failed to create indicator handles.");
      return INIT_FAILED;
     }

   // Set buffer as series (newest index = 0)
   ArraySetAsSeries(fastEMABuf, true);
   ArraySetAsSeries(slowEMABuf, true);
   ArraySetAsSeries(atrBuf, true);

   Print("GoldTrendFollowingEA initialized on ", _Symbol);
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(handleFastEMA!=INVALID_HANDLE) IndicatorRelease(handleFastEMA);
   if(handleSlowEMA!=INVALID_HANDLE) IndicatorRelease(handleSlowEMA);
   if(handleATR!=INVALID_HANDLE) IndicatorRelease(handleATR);
   Print("GoldTrendFollowingEA deinitialized. Reason: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
  {
   // Only act on a new H1 bar
   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_H1, 0);
   if(currentBarTime<=0 || currentBarTime == lastBarTime) return;

   // Copy indicator data (3 values: index 0 = current, 1 = prev)
   if(CopyBuffer(handleFastEMA, 0, 0, 3, fastEMABuf) < 3) return;
   if(CopyBuffer(handleSlowEMA, 0, 0, 3, slowEMABuf) < 3) return;
   if(CopyBuffer(handleATR,     0, 0, 2, atrBuf)     < 2) return;

   double fastNow  = fastEMABuf[1]; // Previous closed bar
   double fastPrev = fastEMABuf[2];
   double slowNow  = slowEMABuf[1];
   double slowPrev = slowEMABuf[2];
   double atr      = atrBuf[1];

   if(atr<=0 || !MathIsValidNumber(atr)) return;
   lastBarTime=currentBarTime;

   bool bullCross = (fastPrev <= slowPrev) && (fastNow > slowNow);
   bool bearCross = (fastPrev >= slowPrev) && (fastNow < slowNow);

   int openLongs  = CountPositions(POSITION_TYPE_BUY);
   int openShorts = CountPositions(POSITION_TYPE_SELL);

   // Close counter-direction positions on crossover
   if(bullCross && openShorts > 0) CloseAllPositions(POSITION_TYPE_SELL);
   if(bearCross && openLongs  > 0) CloseAllPositions(POSITION_TYPE_BUY);

   // Management is independent of the minimum-ATR entry filter.
   ManageTrailingStop(atr);
   if(atr<ATR_Min_Filter) return;
   // Open new positions only after opposing positions are confirmed absent
   if(bullCross && CountPositions(POSITION_TYPE_BUY)==0 && CountPositions(POSITION_TYPE_SELL)==0)
      OpenTrade(ORDER_TYPE_BUY, atr);

   if(bearCross && CountPositions(POSITION_TYPE_SELL)==0 && CountPositions(POSITION_TYPE_BUY)==0)
      OpenTrade(ORDER_TYPE_SELL, atr);

  }

//+------------------------------------------------------------------+
//| Open a market order                                               |
//+------------------------------------------------------------------+
void OpenTrade(ENUM_ORDER_TYPE orderType, double atr)
  {
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   double price, sl, tp;
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(orderType == ORDER_TYPE_BUY)
     {
      price = ask;
      sl    = NormalizeDouble(price - atr * ATR_SL_Mult, _Digits);
      tp    = NormalizeDouble(price + atr * ATR_TP_Mult, _Digits);
     }
   else
     {
      price = bid;
      sl    = NormalizeDouble(price + atr * ATR_SL_Mult, _Digits);
      tp    = NormalizeDouble(price - atr * ATR_TP_Mult, _Digits);
     }

   request.action    = TRADE_ACTION_DEAL;
   request.symbol    = _Symbol;
   request.volume    = LotSize;
   request.type      = orderType;
   request.price     = price;
   request.sl        = sl;
   request.tp        = tp;
   request.deviation = 10;
   request.magic     = MagicNumber;
   request.comment   = "GoldTrendEA";
   request.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(request,result) || (result.retcode!=TRADE_RETCODE_DONE && result.retcode!=TRADE_RETCODE_DONE_PARTIAL))
      Print("OrderSend failed: ", result.retcode, " ", result.comment);
   else
      Print("Order opened: ", EnumToString(orderType), " price=", price, " sl=", sl, " tp=", tp);
  }

//+------------------------------------------------------------------+
//| Count open positions by type                                      |
//+------------------------------------------------------------------+
int CountPositions(ENUM_POSITION_TYPE posType)
  {
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
         PositionGetInteger(POSITION_MAGIC) == (long)MagicNumber &&
         PositionGetInteger(POSITION_TYPE)  == posType)
         count++;
     }
   return count;
  }

//+------------------------------------------------------------------+
//| Close all positions of a given type                               |
//+------------------------------------------------------------------+
void CloseAllPositions(ENUM_POSITION_TYPE posType)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != (long)MagicNumber) continue;
      if(PositionGetInteger(POSITION_TYPE)  != posType) continue;

      MqlTradeRequest req = {};
      MqlTradeResult  res = {};
      req.action   = TRADE_ACTION_DEAL;
      req.symbol   = _Symbol;
      req.position = ticket;
      req.volume   = PositionGetDouble(POSITION_VOLUME);
      req.type     = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
      req.price    = (posType == POSITION_TYPE_BUY)
                     ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
                     : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      req.deviation    = 10;
      req.magic        = MagicNumber;
      req.type_filling = ORDER_FILLING_IOC;

      if(!OrderSend(req,res) || (res.retcode!=TRADE_RETCODE_DONE && res.retcode!=TRADE_RETCODE_DONE_PARTIAL))
         Print("Close failed ticket=", ticket, " retcode=", res.retcode);
     }
  }

//+------------------------------------------------------------------+
//| Manage ATR-based trailing stop                                    |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atr)
  {
   double trailDist = atr * ATR_Trail_Mult;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != (long)MagicNumber) continue;

      double openPrice  = PositionGetDouble(POSITION_PRICE_OPEN);
      double currentSL  = PositionGetDouble(POSITION_SL);
      double currentTP  = PositionGetDouble(POSITION_TP);
      ENUM_POSITION_TYPE pType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

      double newSL = currentSL;

      if(pType == POSITION_TYPE_BUY)
        {
         double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double trail = NormalizeDouble(bid - trailDist, _Digits);
         // Only trail if in profit by at least 1x ATR
         if(bid >= openPrice + trailDist && trail > currentSL)
            newSL = trail;
        }
      else if(pType == POSITION_TYPE_SELL)
        {
         double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         double trail = NormalizeDouble(ask + trailDist, _Digits);
         if(ask <= openPrice - trailDist && (trail < currentSL || currentSL == 0))
            newSL = trail;
        }

      if(newSL != currentSL)
        {
         MqlTradeRequest req = {};
         MqlTradeResult  res = {};
         req.action   = TRADE_ACTION_SLTP;
         req.symbol   = _Symbol;
         req.position = ticket;
         req.sl       = newSL;
         req.tp       = currentTP;
         if(!OrderSend(req,res) || res.retcode!=TRADE_RETCODE_DONE)
            PrintFormat("Trailing modification failed: %u %s",res.retcode,res.comment);
        }
     }
  }
//+------------------------------------------------------------------+

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

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessStrategy orders are simulated; live automation needs a separate integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-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

Technical references

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.