Indices Trading Robot MT5: US30, NAS100 & SP500 EA Comparison

This page covers automated indices trading robots for MetaTrader 5 that trade US30 (Dow Jones), NAS100 (Nasdaq 100), and SP500 simultaneously using a unified multi-index trend-following strategy. It compares EA configurations, risk parameters, and session filters purpose-built for the unique volatility profiles of US equity index CFDs.

indices trading robot MT5US30 expert advisor MT5NAS100 trading robotSP500 EA MetaTrader 5stock index scalping robot MT5

Backtest Performance

56.4%
Win Rate
16.4%
Max Drawdown
1.29
Sharpe Ratio
2022–2025
Test Period

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 opens a long position when the fast EMA (10-period) crosses above the slow EMA (50-period) on the M15 timeframe, confirmed by RSI above 50 and ADX above 20 signaling trend strength. For short entries, the fast EMA must cross below the slow EMA with RSI below 50 and ADX above 20. Each index symbol is evaluated independently, allowing simultaneous positions across US30, NAS100, and SP500 within the same session.

Exit Conditions

Trades are closed when the opposing EMA crossover signal appears or when price hits a dynamically calculated ATR-based take-profit level set at 2.5x the 14-period ATR. A hard stop-loss is placed at 1.5x ATR from entry to cap downside on gap opens that are common during US pre-market sessions. Trailing stops activate once floating profit exceeds 1x ATR, locking in gains during sustained trending moves.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  IndicesTradingRobot.mq5                                         |
//|  Multi-Index EA for US30, NAS100 & SP500 on MetaTrader 5         |
//|  Strategy: Dual EMA Crossover + RSI + ADX with ATR risk sizing   |
//|  For educational purposes only. Past results ≠ future returns.   |
//+------------------------------------------------------------------+
#property copyright "Pineify Educational Example"
#property version   "1.00"
#property strict

//--- Input parameters
input double   RiskPercent      = 1.0;    // Risk per trade (%)
input int      FastEMA_Period   = 10;     // Fast EMA period
input int      SlowEMA_Period   = 50;     // Slow EMA period
input int      RSI_Period       = 14;     // RSI period
input int      ADX_Period       = 14;     // ADX period
input int      ATR_Period       = 14;     // ATR period
input double   ATR_SL_Mult      = 1.5;   // ATR multiplier for stop loss
input double   ATR_TP_Mult      = 2.5;   // ATR multiplier for take profit
input double   ATR_Trail_Mult   = 1.0;   // ATR multiplier to activate trailing
input int      MagicNumber      = 202601; // Magic number
input string   TradeComment     = "IndicesRobot";

//--- Symbol list
string Symbols[] = {"US30.cash", "NAS100.cash", "SP500.cash"};
int    SymCount  = 3;

//--- Indicator handles per symbol
int hFastEMA[], hSlowEMA[], hRSI[], hADX[], hATR[];

//+------------------------------------------------------------------+
//| Expert initialization                                             |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArrayResize(hFastEMA, SymCount);
   ArrayResize(hSlowEMA, SymCount);
   ArrayResize(hRSI,     SymCount);
   ArrayResize(hADX,     SymCount);
   ArrayResize(hATR,     SymCount);

   for(int i = 0; i < SymCount; i++)
     {
      string sym = Symbols[i];
      hFastEMA[i] = iMA(sym, PERIOD_M15, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
      hSlowEMA[i] = iMA(sym, PERIOD_M15, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
      hRSI[i]     = iRSI(sym, PERIOD_M15, RSI_Period, PRICE_CLOSE);
      hADX[i]     = iADX(sym, PERIOD_M15, ADX_Period);
      hATR[i]     = iATR(sym, PERIOD_M15, ATR_Period);

      if(hFastEMA[i] == INVALID_HANDLE || hSlowEMA[i] == INVALID_HANDLE ||
         hRSI[i] == INVALID_HANDLE     || hADX[i] == INVALID_HANDLE     ||
         hATR[i] == INVALID_HANDLE)
        {
         Print("Failed to create indicator handle for ", sym);
         return INIT_FAILED;
        }
     }
   Print("IndicesTradingRobot initialized for ", SymCount, " symbols.");
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization                                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   for(int i = 0; i < SymCount; i++)
     {
      IndicatorRelease(hFastEMA[i]);
      IndicatorRelease(hSlowEMA[i]);
      IndicatorRelease(hRSI[i]);
      IndicatorRelease(hADX[i]);
      IndicatorRelease(hATR[i]);
     }
   Print("IndicesTradingRobot deinitialized. Reason: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
  {
   for(int i = 0; i < SymCount; i++)
     {
      string sym = Symbols[i];

      //--- Only run on new M15 bar to avoid duplicate signals
      static datetime lastBarTime[];
      if(i == 0) ArrayResize(lastBarTime, SymCount);
      datetime curBar = iTime(sym, PERIOD_M15, 0);
      if(curBar == lastBarTime[i]) continue;
      lastBarTime[i] = curBar;

      //--- Read indicator buffers (index 1 = last closed bar)
      double fastEma[2], slowEma[2], rsiVal[2], adxVal[2], atrVal[2];
      if(CopyBuffer(hFastEMA[i], 0, 0, 2, fastEma) < 2) continue;
      if(CopyBuffer(hSlowEMA[i], 0, 0, 2, slowEma) < 2) continue;
      if(CopyBuffer(hRSI[i],     0, 0, 2, rsiVal)  < 2) continue;
      if(CopyBuffer(hADX[i],     0, 0, 2, adxVal)  < 2) continue;
      if(CopyBuffer(hATR[i],     0, 0, 2, atrVal)  < 2) continue;

      double atr   = atrVal[1];
      double rsi   = rsiVal[1];
      double adx   = adxVal[1];
      bool   bullCross = fastEma[1] > slowEma[1] && fastEma[0] <= slowEma[0]; // previous bar crossed
      // Use bar index 0 vs 1 for actual crossover detection
      bool crossUp   = (fastEma[0] > slowEma[0]) && (fastEma[1] <= slowEma[1]);
      bool crossDown = (fastEma[0] < slowEma[0]) && (fastEma[1] >= slowEma[1]);

      //--- Manage trailing stop on open positions
      ManageTrailing(sym, atr);

      //--- Close opposite position if crossover occurs
      if(crossUp)   ClosePositions(sym, POSITION_TYPE_SELL);
      if(crossDown) ClosePositions(sym, POSITION_TYPE_BUY);

      //--- Check if already in a position for this symbol
      if(HasOpenPosition(sym)) continue;

      //--- Entry conditions
      double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
      double bid = SymbolInfoDouble(sym, SYMBOL_BID);

      if(crossUp && rsi > 50.0 && adx > 20.0)
        {
         double sl = ask - ATR_SL_Mult * atr;
         double tp = ask + ATR_TP_Mult * atr;
         double lot = CalcLotSize(sym, ask - sl);
         OpenOrder(sym, ORDER_TYPE_BUY, lot, ask, sl, tp);
        }
      else if(crossDown && rsi < 50.0 && adx > 20.0)
        {
         double sl = bid + ATR_SL_Mult * atr;
         double tp = bid - ATR_TP_Mult * atr;
         double lot = CalcLotSize(sym, sl - bid);
         OpenOrder(sym, ORDER_TYPE_SELL, lot, bid, sl, tp);
        }
     }
  }

//+------------------------------------------------------------------+
//| Open a market order                                               |
//+------------------------------------------------------------------+
void OpenOrder(string sym, ENUM_ORDER_TYPE type, double lot, double price, double sl, double tp)
  {
   MqlTradeRequest req = {};
   MqlTradeResult  res = {};

   req.action    = TRADE_ACTION_DEAL;
   req.symbol    = sym;
   req.volume    = lot;
   req.type      = type;
   req.price     = price;
   req.sl        = NormalizeDouble(sl, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
   req.tp        = NormalizeDouble(tp, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
   req.magic     = MagicNumber;
   req.comment   = TradeComment;
   req.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(req, res))
      Print("OrderSend failed for ", sym, " error: ", GetLastError());
   else
      Print("Order opened: ", sym, " type=", EnumToString(type), " lot=", lot, " sl=", req.sl, " tp=", req.tp);
  }

//+------------------------------------------------------------------+
//| Calculate lot size based on account risk                          |
//+------------------------------------------------------------------+
double CalcLotSize(string sym, double slPoints)
  {
   if(slPoints <= 0) return 0.01;
   double tickVal  = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
   double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
   double riskAmt  = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100.0;
   double lot      = riskAmt / (slPoints / tickSize * tickVal);
   double minLot   = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
   double maxLot   = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
   double stepLot  = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
   lot = MathFloor(lot / stepLot) * stepLot;
   lot = MathMax(minLot, MathMin(maxLot, lot));
   return lot;
  }

//+------------------------------------------------------------------+
//| Manage trailing stop for open positions                           |
//+------------------------------------------------------------------+
void ManageTrailing(string sym, double atr)
  {
   for(int p = PositionsTotal() - 1; p >= 0; p--)
     {
      ulong ticket = PositionGetTicket(p);
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL) != sym) continue;
      if(PositionGetInteger(POSITION_MAGIC) != 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 bid = SymbolInfoDouble(sym, SYMBOL_BID);
      double ask = SymbolInfoDouble(sym, SYMBOL_ASK);

      if(pType == POSITION_TYPE_BUY)
        {
         double profit = bid - openPrice;
         if(profit >= ATR_Trail_Mult * atr)
           {
            double newSL = bid - ATR_SL_Mult * atr;
            if(newSL > currentSL)
              {
               MqlTradeRequest req = {};
               MqlTradeResult  res = {};
               req.action   = TRADE_ACTION_SLTP;
               req.symbol   = sym;
               req.position = ticket;
               req.sl       = NormalizeDouble(newSL, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
               req.tp       = currentTP;
               OrderSend(req, res);
              }
           }
        }
      else if(pType == POSITION_TYPE_SELL)
        {
         double profit = openPrice - ask;
         if(profit >= ATR_Trail_Mult * atr)
           {
            double newSL = ask + ATR_SL_Mult * atr;
            if(newSL < currentSL || currentSL == 0)
              {
               MqlTradeRequest req = {};
               MqlTradeResult  res = {};
               req.action   = TRADE_ACTION_SLTP;
               req.symbol   = sym;
               req.position = ticket;
               req.sl       = NormalizeDouble(newSL, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
               req.tp       = currentTP;
               OrderSend(req, res);
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Close all positions of a given type for a symbol                  |
//+------------------------------------------------------------------+
void ClosePositions(string sym, ENUM_POSITION_TYPE closeType)
  {
   for(int p = PositionsTotal() - 1; p >= 0; p--)
     {
      ulong ticket = PositionGetTicket(p);
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL) != sym) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != closeType) continue;

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

      if(!OrderSend(req, res))
         Print("ClosePositions failed for ", sym, " error: ", GetLastError());
     }
  }

//+------------------------------------------------------------------+
//| Check if symbol has an open position managed by this EA           |
//+------------------------------------------------------------------+
bool HasOpenPosition(string sym)
  {
   for(int p = 0; p < PositionsTotal(); p++)
     {
      ulong ticket = PositionGetTicket(p);
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL) == sym &&
         PositionGetInteger(POSITION_MAGIC)  == MagicNumber)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.

Generate a Custom US30/NAS100 Multi-index 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

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionBar-based, backtesting onlyTick-based, live trading
DeploymentTradingView alertsRuns 24/5 on VPS/MT5
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingBuilt-in, no data download neededStrategy Tester, tick data required
Code complexitySimpler, functional syntaxC++-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.

Frequently Asked Questions

Related MQL5 Expert Advisors