Complete .mq5 source code

Crude Oil Expert Advisor MT5: XTIUSD MQL5 EA Code & Guide

Inspect an educational H1 EMA-crossover EA for a broker’s crude-oil symbol. The source uses an ATR threshold, fixed lots and initial ATR-based SL/TP. No reproducible performance result is supplied; verify contract settings, execution responses and held-out tests before considering deployment.

Strategy logic

Entry conditions

At a new H1 bar, compare EMA values on completed bars 2 and 1. A crossover and ATR at or above MinAtrFilter can trigger an order; there is no additional price-close-above-both-EMAs condition. The defaults are illustrative, not optimized. Position checks use this symbol and magic number; netting accounts still aggregate positions by symbol.

Exit conditions

Initial SL and TP are 1.5 and 2.5 ATR from the requested entry price by default. They are not trailing stops or guarantees of maximum loss. An opposite crossover requests closure first; the EA only attempts the new direction after no opposite owned position remains. The ATR gate precedes reversal handling, and H1 checks do not provide continuous risk management. Fixed IOC filling, lot size and price rounding must be checked against the broker contract.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  CrudeOilTrendEA.mq5                                             |
//|  Trend-following Expert Advisor for XTIUSD (Crude Oil) on MT5    |
//|  Strategy: EMA crossover + ATR volatility filter                 |
//|  DISCLAIMER: For educational purposes only. Past performance     |
//|  does not guarantee future results. Trade at your own risk.      |
//+------------------------------------------------------------------+
#property copyright "Pineify (pineify.app)"
#property version   "1.00"
#property strict

//--- Input parameters
input int    FastEmaPeriod  = 20;       // Fast EMA period
input int    SlowEmaPeriod  = 50;       // Slow EMA period
input int    AtrPeriod      = 14;       // ATR period
input double AtrMultSL      = 1.5;      // ATR multiplier for Stop Loss
input double AtrMultTP      = 2.5;      // ATR multiplier for Take Profit
input double MinAtrFilter   = 0.30;     // Minimum ATR (USD) to allow entry
input double LotSize        = 0.10;     // Fixed lot size
input int    MagicNumber    = 202501;   // Magic number to identify EA orders
input string TradeComment   = "CrudeOilTrendEA";

//--- Indicator handles
int handleFastEma = INVALID_HANDLE;
int handleSlowEma = INVALID_HANDLE;
int handleAtr     = INVALID_HANDLE;

//--- Buffers
double fastEmaBuffer[];
double slowEmaBuffer[];
double atrBuffer[];

//+------------------------------------------------------------------+
//| Expert initialisation function                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(FastEmaPeriod<=0 || SlowEmaPeriod<=0 || AtrPeriod<=0 || AtrMultSL<=0 || AtrMultTP<=0 || MinAtrFilter<0 || LotSize<=0) return INIT_PARAMETERS_INCORRECT;
   //--- Create indicator handles
   handleFastEma = iMA(_Symbol, PERIOD_H1, FastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   handleSlowEma = iMA(_Symbol, PERIOD_H1, SlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   handleAtr     = iATR(_Symbol, PERIOD_H1, AtrPeriod);

   if(handleFastEma == INVALID_HANDLE ||
      handleSlowEma == INVALID_HANDLE ||
      handleAtr     == INVALID_HANDLE)
     {
      Print("ERROR: Failed to create indicator handles. EA will not run.");
      return INIT_FAILED;
     }

   //--- Set buffer as series (newest bar = index 0)
   ArraySetAsSeries(fastEmaBuffer, true);
   ArraySetAsSeries(slowEmaBuffer, true);
   ArraySetAsSeries(atrBuffer,     true);

   Print("CrudeOilTrendEA initialised on ", _Symbol,
         " | FastEMA=", FastEmaPeriod,
         " SlowEMA=", SlowEmaPeriod,
         " ATR=", AtrPeriod);
   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("CrudeOilTrendEA removed. Reason code: ", reason);
  }

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

   //--- Copy bars 0..2; crossover uses completed bars 1 and 2
   if(CopyBuffer(handleFastEma, 0, 0, 3, fastEmaBuffer) < 3) return;
   if(CopyBuffer(handleSlowEma, 0, 0, 3, slowEmaBuffer) < 3) return;
   if(CopyBuffer(handleAtr,     0, 0, 3, atrBuffer)     < 3) return;

   double fastNow  = fastEmaBuffer[1];  // Completed bar
   double fastPrev = fastEmaBuffer[2];
   double slowNow  = slowEmaBuffer[1];
   double slowPrev = slowEmaBuffer[2];
   double atrNow   = atrBuffer[1];

   //--- ATR volatility gate
   if(atrNow <= 0 || atrNow < MinAtrFilter) return;

   //--- Detect crossover signals
   bool bullCross = (fastPrev <= slowPrev) && (fastNow > slowNow);
   bool bearCross = (fastPrev >= slowPrev) && (fastNow < slowNow);

   //--- Check current position state
   bool hasLong  = PositionExists(POSITION_TYPE_BUY);
   bool hasShort = PositionExists(POSITION_TYPE_SELL);

   //--- Close opposite position on new signal, then open new trade
   if(bullCross)
     {
      if(hasShort) CloseAllPositions();
      if(!hasLong && !PositionExists(POSITION_TYPE_SELL)) OpenTrade(ORDER_TYPE_BUY, atrNow);
     }
   else if(bearCross)
     {
      if(hasLong)  CloseAllPositions();
      if(!hasShort && !PositionExists(POSITION_TYPE_BUY)) OpenTrade(ORDER_TYPE_SELL, atrNow);
     }
  }

//+------------------------------------------------------------------+
//| Check whether a position of given type exists for this EA        |
//+------------------------------------------------------------------+
bool PositionExists(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 &&
         PositionGetInteger(POSITION_MAGIC)  == MagicNumber &&
         PositionGetInteger(POSITION_TYPE)   == posType)
         return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Close all EA positions on this symbol                            |
//+------------------------------------------------------------------+
void CloseAllPositions()
  {
   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) != MagicNumber) continue;

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

      if(!OrderSend(req, res) || res.retcode != TRADE_RETCODE_DONE)
         Print("CloseAllPositions OrderSend failed: ", res.retcode);
     }
  }

//+------------------------------------------------------------------+
//| Open a new trade with ATR-based SL and TP                        |
//+------------------------------------------------------------------+
void OpenTrade(ENUM_ORDER_TYPE orderType, double atr)
  {
   double price   = (orderType == ORDER_TYPE_BUY)
                    ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                    : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double sl      = (orderType == ORDER_TYPE_BUY)
                    ? price - AtrMultSL * atr
                    : price + AtrMultSL * atr;
   double tp      = (orderType == ORDER_TYPE_BUY)
                    ? price + AtrMultTP * atr
                    : price - AtrMultTP * atr;

   int digits     = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   sl = NormalizeDouble(sl, digits);
   tp = NormalizeDouble(tp, digits);

   MqlTradeRequest req = {};
   MqlTradeResult  res = {};
   req.action    = TRADE_ACTION_DEAL;
   req.symbol    = _Symbol;
   req.volume    = LotSize;
   req.type      = orderType;
   req.price     = price;
   req.sl        = sl;
   req.tp        = tp;
   req.deviation = 10;
   req.magic     = MagicNumber;
   req.comment   = TradeComment;
   req.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(req, res) || res.retcode != TRADE_RETCODE_DONE)
      Print("OpenTrade OrderSend failed: retcode=", res.retcode,
            " type=", EnumToString(orderType));
   else
      Print("Trade request completed: ", EnumToString(orderType),
            " price=", price, " SL=", sl, " TP=", tp,
            " ticket=", res.order);
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor, save it in the MQL5/Experts folder, and compile with F7.

Generate a custom XTIUSD 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.