US30 EA MT5: Complete Expert Advisor Guide for Dow Jones Trading
Review a complete H1 EMA-cross Expert Advisor for a broker-provided US30 instrument. It adds a completed 200 EMA and ADX reading, estimates lot size from ATR stop distance, and requests an early close on an opposite crossover. The source is educational; no verified 2021–2025 performance report or deployment guarantee accompanies it.
Strategy logic
Entry conditions
The 20/50 EMA cross uses two completed H1 bars. A buy also requires the current ask above the completed 200 EMA; a sell requires current bid below it. This is not a completed-close filter. ADX must meet its threshold, and no matching symbol-and-magic position may already exist. Data is checked before consuming the new-bar decision.
Exit conditions
Initial SL and TP are measured from the entry quote at 1.5 and 2.5 ATR. There is no candle-extreme stop or trailing stop. An opposite completed EMA cross requests closure; the request includes the actual position ticket, and a failed close is retried on later ticks while attached. No immediate reverse entry occurs in that decision. The nominal 2.5/1.5 distance ratio is not a guaranteed realized payoff.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| US30 Trend-Following Expert Advisor (MQL5 / MT5) |
//| Strategy : EMA 20/50 crossover + 200 EMA trend filter + ADX |
//| Risk : ATR-based stop-loss, fixed R:R take-profit |
//| 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 TrendEmaPeriod = 200; // Trend filter EMA period
input int AtrPeriod = 14; // ATR period
input int AdxPeriod = 14; // ADX period
input double AdxMinLevel = 20.0; // Minimum ADX for entry
input double AtrSlMultiple = 1.5; // Stop-loss ATR multiple
input double AtrTpMultiple = 2.5; // Take-profit ATR multiple
input double RiskPercent = 1.0; // Risk per trade (% of balance)
input ulong MagicNumber = 300049; // EA magic number
input string TradeComment = "US30_EA";
//--- Global handles
int g_handleFastEma = INVALID_HANDLE;
int g_handleSlowEma = INVALID_HANDLE;
int g_handleTrendEma = INVALID_HANDLE;
int g_handleAtr = INVALID_HANDLE;
int g_handleAdx = INVALID_HANDLE;
bool closePending=false;
//+------------------------------------------------------------------+
//| Expert initialisation |
//+------------------------------------------------------------------+
int OnInit()
{
if(FastEmaPeriod<1 || SlowEmaPeriod<=FastEmaPeriod || TrendEmaPeriod<1 || AtrPeriod<1 || AdxPeriod<1 || AdxMinLevel<0 || AdxMinLevel>100 || AtrSlMultiple<=0 || AtrTpMultiple<=0 || RiskPercent<=0 || RiskPercent>100) return INIT_PARAMETERS_INCORRECT;
g_handleFastEma = iMA(_Symbol, PERIOD_H1, FastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_handleSlowEma = iMA(_Symbol, PERIOD_H1, SlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_handleTrendEma = iMA(_Symbol, PERIOD_H1, TrendEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_handleAtr = iATR(_Symbol, PERIOD_H1, AtrPeriod);
g_handleAdx = iADX(_Symbol, PERIOD_H1, AdxPeriod);
if(g_handleFastEma == INVALID_HANDLE ||
g_handleSlowEma == INVALID_HANDLE ||
g_handleTrendEma == INVALID_HANDLE ||
g_handleAtr == INVALID_HANDLE ||
g_handleAdx == INVALID_HANDLE)
{
Print("US30 EA: Failed to create indicator handles. Error: ", GetLastError());
return INIT_FAILED;
}
Print("US30 EA initialized. Symbol=", _Symbol, " Magic=", MagicNumber);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_handleFastEma != INVALID_HANDLE) IndicatorRelease(g_handleFastEma);
if(g_handleSlowEma != INVALID_HANDLE) IndicatorRelease(g_handleSlowEma);
if(g_handleTrendEma != INVALID_HANDLE) IndicatorRelease(g_handleTrendEma);
if(g_handleAtr != INVALID_HANDLE) IndicatorRelease(g_handleAtr);
if(g_handleAdx != INVALID_HANDLE) IndicatorRelease(g_handleAdx);
Print("US30 EA deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Check whether EA already holds a position on this symbol |
//+------------------------------------------------------------------+
bool HasOpenPosition(ENUM_POSITION_TYPE &posType)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == (long)MagicNumber)
{
posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Calculate lot size from risk percent and stop distance |
//+------------------------------------------------------------------+
double CalcLotSize(double stopPriceDistance)
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = balance * RiskPercent / 100.0;
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(tickSize <= 0 || tickValue <= 0 || stopPriceDistance <= 0 || riskAmount<=0)
return 0.0;
double lotsRaw = riskAmount / (stopPriceDistance / tickSize * tickValue);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double lotMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double lotMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
if(lotStep<=0 || lotMin<=0 || lotMax<lotMin) return 0;
double lots=NormalizeDouble(MathFloor(MathMin(lotMax,lotsRaw)/lotStep)*lotStep,8);
return lots>=lotMin?lots:0;
}
//+------------------------------------------------------------------+
//| Close all positions for this EA |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != (long)MagicNumber) continue;
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.position = ticket;
req.type_filling = ORDER_FILLING_FOK;
req.volume = PositionGetDouble(POSITION_VOLUME);
req.magic = MagicNumber;
req.comment = TradeComment + "_CLOSE";
req.deviation = 20;
ENUM_POSITION_TYPE pt = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
req.type = (pt == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
req.price = (pt == POSITION_TYPE_BUY)
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(!OrderSend(req, res) || res.retcode!=TRADE_RETCODE_DONE)
Print("US30 EA CloseAllPositions error: ", res.retcode);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(closePending) { CloseAllPositions(); ENUM_POSITION_TYPE pendingType; closePending=HasOpenPosition(pendingType); if(closePending) return; }
//--- Only act on new H1 bar open
static datetime lastBarTime = 0;
datetime currentBarTime = (datetime)SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_LASTBAR_DATE);
if(currentBarTime==0 || currentBarTime==lastBarTime) return;
//--- Read indicator buffers (index 1 = previous closed bar)
double fastEma[2], slowEma[2], trendEma[2], atr[2], adx[2];
if(CopyBuffer(g_handleFastEma, 0, 1, 2, fastEma) < 2) return;
if(CopyBuffer(g_handleSlowEma, 0, 1, 2, slowEma) < 2) return;
if(CopyBuffer(g_handleTrendEma, 0, 1, 2, trendEma) < 2) return;
if(CopyBuffer(g_handleAtr, 0, 1, 2, atr) < 2) return;
if(CopyBuffer(g_handleAdx, 0, 1, 2, adx) < 2) return;
double prevFast = fastEma[0], currFast = fastEma[1];
double prevSlow = slowEma[0], currSlow = slowEma[1];
double currTrend = trendEma[1];
double currAtr = atr[1];
double currAdx = adx[1];
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(currAtr<=0 || ask<=0 || bid<=0) return;
lastBarTime=currentBarTime;
bool bullCross = (prevFast <= prevSlow) && (currFast > currSlow);
bool bearCross = (prevFast >= prevSlow) && (currFast < currSlow);
//--- Manage existing position (early exit on counter-crossover)
ENUM_POSITION_TYPE posType;
if(HasOpenPosition(posType))
{
if((posType==POSITION_TYPE_BUY && bearCross) || (posType==POSITION_TYPE_SELL && bullCross))
{ CloseAllPositions(); closePending=HasOpenPosition(posType); }
return;
}
//--- ADX trend-strength filter
if(currAdx < AdxMinLevel) return;
double stopDist, sl, tp, lots;
//--- Long entry
if(bullCross && ask > currTrend)
{
stopDist = AtrSlMultiple * currAtr;
sl = ask - stopDist;
tp = ask + AtrTpMultiple * currAtr;
lots = CalcLotSize(stopDist);
if(lots <= 0) return;
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = lots;
req.type = ORDER_TYPE_BUY;
req.price = ask;
req.sl = NormalizeDouble(sl,_Digits);
req.tp = NormalizeDouble(tp,_Digits);
req.type_filling = ORDER_FILLING_FOK;
req.deviation = 20;
req.magic = MagicNumber;
req.comment = TradeComment + "_BUY";
if(!OrderSend(req, res) || res.retcode!=TRADE_RETCODE_DONE)
Print("US30 EA BUY error: ", res.retcode);
}
//--- Short entry
else if(bearCross && bid < currTrend)
{
stopDist = AtrSlMultiple * currAtr;
sl = bid + stopDist;
tp = bid - AtrTpMultiple * currAtr;
lots = CalcLotSize(stopDist);
if(lots <= 0) return;
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = lots;
req.type = ORDER_TYPE_SELL;
req.price = bid;
req.sl = NormalizeDouble(sl,_Digits);
req.tp = NormalizeDouble(tp,_Digits);
req.type_filling = ORDER_FILLING_FOK;
req.deviation = 20;
req.magic = MagicNumber;
req.comment = TradeComment + "_SELL";
if(!OrderSend(req, res) || res.retcode!=TRADE_RETCODE_DONE)
Print("US30 EA SELL error: ", res.retcode);
}
}
//+------------------------------------------------------------------+Copy this code into MetaEditor, save it in the MQL5/Experts folder, and compile with F7.
Generate a custom US30 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.