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

  • Trend Strength Validation: ATR-normalized EMA spread classifies trend as weak/normal/strong — trades only allowed in normal or strong conditions.

  • Pullback Detection on M15: Price must retrace to EMA20 region or RSI 45-55 zone after the trend move.

  • Entry Trigger: Break of previous candle's high/low in the trend direction, confirmed by RSI divergence (price extreme vs RSI extreme).

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