Summary: Gold Nexus EA is an MQL4 expert advisor for XAUUSD that integrates H4 macro trend filtering, M15 pullback structure with scoring system, RSI divergence confirmation and ATR-based dynamic stops. Designed for H1 primary analysis with M15 entry.
Gold Nexus EA is engineered based on structural principles observed in commercial gold EAs from 2024-2026. The EA integrates three key concepts: macro trend filtering on H4, pullback structure detection on M15 with a proprietary scoring system, and RSI divergence confirmation. This multi-timeframe fusion approach ensures trades align with the dominant trend while entering during optimal pullback zones. The EA includes volatility-adaptive position sizing, a trailing stop system that activates after specified profit thresholds, spread filtering, and daily equity protection. No martingale or grid recovery is used — each trade is independent with fixed ATR-based stops.
Recommended Timeframe: H1 (primary trend analysis) with M15 for entry timing
Trading Logic:
1. Macro Trend Filter: EMA89 and EMA34 on H4 determine primary direction. EMA34 must be above EMA89 for long-only mode, or below for short-only mode.
2. Trend Strength Validation: ATR-normalized EMA spread classifies trend as weak/normal/strong — trades only allowed in normal or strong conditions.
3. Pullback Detection on M15: Price must retrace to EMA20 region or RSI 45-55 zone after the trend move.
4. Entry Trigger: Break of previous candle's high/low in the trend direction, confirmed by RSI divergence (price extreme vs RSI extreme).
5. Risk Management: ATR-based stop loss (1.6x ATR), take profit at 2.8x ATR, trailing stop after 1.2x ATR profit.
```mql4
//+------------------------------------------------------------------+
//| GoldNexusEA.mq4 |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
//--- input parameters with comments
input double LotSize = 0.01; // Fixed lot size (0.01 for XAUUSD)
input int H4FastEMA = 34; // H4 fast EMA for macro trend
input int H4SlowEMA = 89; // H4 slow EMA for macro trend
input int PullbackMAPeriod = 20; // EMA period for pullback detection (M15)
input int RSIPeriod = 14; // RSI period for divergence detection
input int RSIOversold = 30; // RSI oversold threshold
input int RSIOverbought = 70; // RSI overbought threshold
input int ADXPeriod = 14; // ADX period for trend strength
input int ADXWeakThreshold = 20; // Below this = weak trend (no trade)
input int ADXStrongThreshold = 40; // Above this = strong trend
input int ATRPeriod = 14; // ATR period for stop loss
input double ATRStopMultiplier = 1.6; // Stop loss as multiple of ATR
input double ATRTakeMultiplier = 2.8; // Take profit as multiple of ATR
input double TrailingStartATR = 1.2; // Trailing activates at profit (x ATR)
input double TrailingStepATR = 0.6; // Trailing step (x ATR)
input int MinPullbackScore = 55; // Minimum pullback score (0-100) to enter
input int MagicNumber = 202403; // Unique EA identifier
input int MaxSpread = 35; // Maximum allowed spread in points
input double DailyLossLimit = 5.0; // Daily loss limit as percentage
input bool UseFridayClose = true; // Close trades before Friday 21:00 GMT
input bool UseNewsFilter = true; // Skip trading during high-impact news
//--- global variables
double dailyStartBalance = 0;
datetime lastBarTime = 0;
bool fridayCloseExecuted = false;
double avgATR_H1 = 0;
double currentPullbackScore = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
lastBarTime = 0;
fridayCloseExecuted = false;
avgATR_H1 = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(avgATR_H1 <= 0) avgATR_H1 = 250 * Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Get macro trend direction from H4 EMA crossover |
//+------------------------------------------------------------------+
int GetMacroTrendDirection()
{
double fastEMA = iMA(Symbol(), PERIOD_H4, H4FastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowEMA = iMA(Symbol(), PERIOD_H4, H4SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double prevFast = iMA(Symbol(), PERIOD_H4, H4FastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double prevSlow = iMA(Symbol(), PERIOD_H4, H4SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
if(fastEMA > slowEMA && prevFast <= prevSlow) return 1; // Bullish crossover
if(fastEMA < slowEMA && prevFast >= prevSlow) return -1; // Bearish crossover
if(fastEMA > slowEMA) return 2; // Already bullish
if(fastEMA < slowEMA) return -2; // Already bearish
return 0;
}
//+------------------------------------------------------------------+
//| Calculate trend strength using ATR-normalized EMA spread |
//+------------------------------------------------------------------+
int GetTrendStrength()
{
double fastEMA = iMA(Symbol(), PERIOD_H4, H4FastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowEMA = iMA(Symbol(), PERIOD_H4, H4SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double atr = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
if(atr <= 0) return 1;
double spread = MathAbs(fastEMA - slowEMA);
double normalizedSpread = spread / atr;
if(normalizedSpread < 0.5) return 0; // Weak trend
if(normalizedSpread < 1.2) return 1; // Normal trend
return 2; // Strong trend
}
//+------------------------------------------------------------------+
//| Detect RSI divergence (price vs RSI extremes) |
//+------------------------------------------------------------------+
bool DetectRSIDivergence(int direction)
{
double rsi = iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, 1);
double rsiPrev = iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, 2);
double price = iClose(Symbol(), PERIOD_M15, 1);
double pricePrev = iClose(Symbol(), PERIOD_M15, 2);
if(direction == 1) // Bullish divergence: price lower low, RSI higher low
{
bool priceLowerLow = (price < pricePrev);
bool rsiHigherLow = (rsi > rsiPrev && rsi < RSIOversold);
return (priceLowerLow && rsiHigherLow);
}
else if(direction == -1) // Bearish divergence: price higher high, RSI lower high
{
bool priceHigherHigh = (price > pricePrev);
bool rsiLowerHigh = (rsi < rsiPrev && rsi > RSIOverbought);
return (priceHigherHigh && rsiLowerHigh);
}
return false;
}
//+------------------------------------------------------------------+
//| Calculate pullback score (0-100) based on multiple factors |
//+------------------------------------------------------------------+
int CalculatePullbackScore(int trendDir)
{
int score = 0;
// Factor 1: Price retracement to EMA20 region (0-40 points)
double ema20 = iMA(Symbol(), PERIOD_M15, PullbackMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double close = iClose(Symbol(), PERIOD_M15, 1);
double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
double distanceToEMA = MathAbs(close - ema20) / atr;
if(distanceToEMA < 0.3) score += 40;
else if(distanceToEMA < 0.6) score += 25;
else if(distanceToEMA < 1.0) score += 10;
// Factor 2: RSI in neutral zone (45-55) for pullback (0-40 points)
double rsi = iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, 1);
if(trendDir == 1 && rsi >= 45 && rsi <= 55) score += 40;
else if(trendDir == -1 && rsi >= 45 && rsi <= 55) score += 40;
else if(trendDir == 1 && rsi > 55 && rsi < 65) score += 20;
else if(trendDir == -1 && rsi < 55 && rsi > 45) score += 20;
// Factor 3: Candle structure confirmation (0-20 points)
double open = iOpen(Symbol(), PERIOD_M15, 1);
double high = iHigh(Symbol(), PERIOD_M15, 1);
double low = iLow(Symbol(), PERIOD_M15, 1);
double body = MathAbs(close - open);
double range = high - low;
if(trendDir == 1 && close > open && body/range > 0.6) score += 20;
else if(trendDir == -1 && close < open && body/range > 0.6) score += 20;
else if(body/range > 0.4) score += 10;
return score;
}
//+------------------------------------------------------------------+
//| Check entry trigger: breakout of previous candle high/low |
//+------------------------------------------------------------------+
bool CheckEntryTrigger(int direction)
{
double prevHigh = iHigh(Symbol(), PERIOD_M15, 2);
double prevLow = iLow(Symbol(), PERIOD_M15, 2);
double currentHigh = iHigh(Symbol(), PERIOD_M15, 1);
double currentLow = iLow(Symbol(), PERIOD_M15, 1);
double currentClose = iClose(Symbol(), PERIOD_M15, 1);
double currentOpen = iOpen(Symbol(), PERIOD_M15, 1);
if(direction == 1) // Bullish: break above previous high
{
bool breakAbove = (currentHigh > prevHigh && currentClose > prevHigh);
bool bullishCandle = (currentClose > currentOpen);
return (breakAbove && bullishCandle);
}
else if(direction == -1) // Bearish: break below previous low
{
bool breakBelow = (currentLow < prevLow && currentClose < prevLow);
bool bearishCandle = (currentClose < currentOpen);
return (breakBelow && bearishCandle);
}
return false;
}
//+------------------------------------------------------------------+
//| Manage trailing stop for open position |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr <= 0) atr = avgATR_H1;
double activate = atr * TrailingStartATR;
double step = atr * TrailingStepATR;
double newSL = 0;
if(OrderType() == OP_BUY)
{
double profit = Bid - OrderOpenPrice();
if(profit >= activate)
{
newSL = Bid - step;
if(newSL > OrderStopLoss())
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
else if(OrderType() == OP_SELL)
{
double profit = OrderOpenPrice() - Ask;
if(profit >= activate)
{
newSL = Ask + step;
if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
break;
}
}
}
}
//+------------------------------------------------------------------+
//| Check if high-impact news is active (simplified filter) |
//+------------------------------------------------------------------+
bool IsNewsTime()
{
if(!UseNewsFilter) return false;
datetime currentTime = TimeCurrent();
int hour = TimeHour(currentTime);
int minute = TimeMinute(currentTime);
int dayOfWeek = TimeDayOfWeek(currentTime);
// Major NFP, FOMC, CPI release times (simplified: first Friday 13:30 GMT)
if(dayOfWeek == 5 && hour >= 13 && hour <= 14)
return true;
// FOMC days (Wednesdays around 19:00 GMT)
if(dayOfWeek == 4 && hour >= 18 && hour <= 20)
return true;
// CPI releases (typically 13:30 GMT)
if(hour == 13 && minute >= 25 && minute <= 35)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Daily equity protection
double currentEquity = AccountEquity();
double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance * 100;
if(lossPercent >= DailyLossLimit)
{
Comment("Daily loss limit reached. No new trades.");
return;
}
// Friday close before weekend
if(UseFridayClose && !fridayCloseExecuted)
{
datetime currentTime = TimeCurrent();
if(TimeDayOfWeek(currentTime) == 5 && TimeHour(currentTime) >= 21)
{
CloseAllOrders();
fridayCloseExecuted = true;
return;
}
if(TimeDayOfWeek(currentTime) != 5)
fridayCloseExecuted = false;
}
// News filter
if(IsNewsTime())
{
Comment("High-impact news pending - trading paused");
return;
}
// Spread filter
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
{
Comment("Spread too high: ", MarketInfo(Symbol(), MODE_SPREAD));
return;
}
// New bar logic for H1 (macro analysis) and M15 (entry)
static datetime lastH1Bar = 0;
static datetime lastM15Bar = 0;
datetime currentH1Bar = iTime(Symbol(), PERIOD_H1, 0);
datetime currentM15Bar = iTime(Symbol(), PERIOD_M15, 0);
bool isNewH1Bar = (currentH1Bar != lastH1Bar);
bool isNewM15Bar = (currentM15Bar != lastM15Bar);
if(isNewH1Bar)
lastH1Bar = currentH1Bar;
if(isNewM15Bar)
lastM15Bar = currentM15Bar;
// Manage existing position
if(CountPositions() > 0)
{
ManageTrailingStop();
return;
}
// Only evaluate on new M15 bars (entry timing)
if(!isNewM15Bar) return;
// Step 1: Get macro trend direction (H4)
int macroTrend = GetMacroTrendDirection();
if(macroTrend == 0)
{
Comment("No clear macro trend");
return;
}
int trendDirection = (macroTrend > 0) ? 1 : -1;
// Step 2: Check trend strength
int trendStrength = GetTrendStrength();
if(trendStrength == 0) // Weak trend - no trade
{
Comment("Trend too weak for entry");
return;
}
// Step 3: Calculate pullback score
int pullbackScore = CalculatePullbackScore(trendDirection);
currentPullbackScore = pullbackScore;
if(pullbackScore < MinPullbackScore)
{
Comment("Pullback score too low: ", pullbackScore);
return;
}
// Step 4: Check RSI divergence confirmation
bool hasDivergence = DetectRSIDivergence(trendDirection);
// Step 5: Check entry trigger
bool entryTrigger = CheckEntryTrigger(trendDirection);
// Step 6: Combined entry condition
if(entryTrigger && (pullbackScore >= MinPullbackScore || hasDivergence))
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr <= 0) atr = avgATR_H1;
double entryPrice = (trendDirection == 1) ? Ask : Bid;
double sl = 0, tp = 0;
int cmd = (trendDirection == 1) ? OP_BUY : OP_SELL;
if(cmd == OP_BUY)
{
sl = entryPrice - (atr * ATRStopMultiplier);
tp = entryPrice + (atr * ATRTakeMultiplier);
}
else
{
sl = entryPrice + (atr * ATRStopMultiplier);
tp = entryPrice - (atr * ATRTakeMultiplier);
}
int ticket = OrderSend(Symbol(), cmd, LotSize, entryPrice, 5, sl, tp, "Gold Nexus", MagicNumber, 0, clrNONE);
if(ticket < 0)
{
Print("OrderSend failed: ", GetLastError());
}
else
{
Print("Entry opened. Direction: ", cmd==OP_BUY?"BUY":"SELL",
" | Pullback Score: ", pullbackScore,
" | Divergence: ", hasDivergence);
}
}
else
{
if(!entryTrigger) Comment("Waiting for entry trigger");
}
}
//+------------------------------------------------------------------+
//| Count open positions with this MagicNumber |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Close all orders for this symbol and magic |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, 5, clrNONE);
else if(OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 5, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```
Reference: Original MQL4 code inspired by structural principles from commercial gold EAs 2024-2026 including NEXA Gold Pullback System's scoring methodology and Magic Gold Grid's H4 trend filter concept.
Disclaimer: Gold trading involves significant risk due to high volatility and leverage. This EA is provided as-is without any guarantee of profit. Test thoroughly on a demo account for at least 3 months before live deployment. Past performance does not guarantee future results.