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.
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 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
| 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.