Summary: Gold Signal Pulse EA is an MQL4 expert advisor for XAUUSD that combines EMA50 trend filter, RSI(14) momentum confirmation, ATR volatility guard, and dynamic position sizing. Suitable for H1 timeframe stable operation.




Gold Signal Pulse EA is designed specifically for gold (XAUUSD) with a conservative multi-confluence approach. Unlike aggressive grid or martingale systems, this EA requires three independent conditions to align before entering any trade: trend direction (EMA50), momentum (RSI), and volatility regime (ATR). The EA only trades in the direction of the primary trend and avoids entering during high-volatility periods. A dynamic position sizing system adjusts lot size based on current ATR levels, reducing exposure when gold volatility spikes. Additional safety features include daily equity drawdown protection, maximum spread control, Friday close mechanism, and a cooldown period after losing trades.

Recommended Timeframe: H1
Trading Logic:
  • Trend Filter: EMA(50) determines primary direction. Price above EMA → long only; below → short only.

  • Momentum Confirmation: RSI(14) must confirm the trend (RSI > 50 for longs, RSI < 50 for shorts).

  • Entry Signal: After trend confirmation, wait for a pullback to the EMA50 zone with a confirming candle (close beyond EMA in trend direction).

  • Volatility Guard: Current ATR(14) must not exceed 1.8x the 30-period average ATR.

  • Risk Management: Fixed stop loss based on 1.5x ATR, take profit at 3x ATR, trailing stop activates after 1x ATR profit.


  • ``mql4
    //+------------------------------------------------------------------+
    //| GoldSignalPulseEA.mq4 |
    //| |
    //+------------------------------------------------------------------+
    #property copyright ""
    #property link ""
    #property version "1.00"
    #property strict

    //--- input parameters with comments
    input double BaseLotSize = 0.01; // Base lot size (0.01 for XAUUSD)
    input int TrendEMAPeriod = 50; // EMA period for trend filter
    input int RSIPeriod = 14; // RSI period for momentum confirmation
    input int ATRPeriod = 14; // ATR period for volatility
    input double ATRMaxMultiplier = 1.8; // Max ATR vs avg ATR (volatility guard)
    input double ATRStopMultiplier = 1.5; // Stop loss as multiple of ATR
    input double ATRTakeMultiplier = 3.0; // Take profit as multiple of ATR
    input double TrailingStartATR = 1.0; // Trailing activates at profit (x ATR)
    input double TrailingStepATR = 0.5; // Trailing step (x ATR)
    input double RiskPerTradePercent = 1.0; // Dynamic lot sizing: risk % per trade
    input int MaxSpread = 35; // Maximum allowed spread in points
    input double DailyLossLimit = 5.0; // Daily loss limit as percentage
    input int CooldownMinutes = 30; // Cooldown after losing trade (minutes)
    input bool UseFridayClose = true; // Close trades before Friday 21:00 GMT
    input int MagicNumber = 202422; // Unique EA identifier

    //--- global variables
    double dailyStartBalance = 0;
    datetime lastBarTime = 0;
    bool fridayCloseExecuted = false;
    double avgATR = 0;
    datetime lastLossTime = 0;
    double currentATR = 0;

    //+------------------------------------------------------------------+
    //| Expert initialization function |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    dailyStartBalance = AccountBalance();
    lastBarTime = 0;
    fridayCloseExecuted = false;
    lastLossTime = 0;
    avgATR = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
    if(avgATR <= 0) avgATR = 250 Point;
    return(INIT_SUCCEEDED);
    }

    //+------------------------------------------------------------------+
    //| Expert deinitialization function |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
    Comment("");
    }

    //+------------------------------------------------------------------+
    //| Get trend direction from EMA |
    //+------------------------------------------------------------------+
    int GetTrendDirection()
    {
    double close1 = iClose(Symbol(), PERIOD_H1, 1);
    double ema = iMA(Symbol(), PERIOD_H1, TrendEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    if(close1 > ema) return 1;
    if(close1 < ema) return -1;
    return 0;
    }

    //+------------------------------------------------------------------+
    //| Check RSI momentum confirmation |
    //+------------------------------------------------------------------+
    bool CheckRSIMomentum(int direction)
    {
    double rsi = iRSI(Symbol(), PERIOD_H1, RSIPeriod, PRICE_CLOSE, 1);
    if(rsi <= 0) return false;

    if(direction == 1 && rsi > 50) return true;
    if(direction == -1 && rsi < 50) return true;
    return false;
    }

    //+------------------------------------------------------------------+
    //| Check pullback entry condition |
    //+------------------------------------------------------------------+
    bool CheckPullbackEntry(int direction, double &entryPrice, double &sl, double &tp, double atr)
    {
    double ema = iMA(Symbol(), PERIOD_H1, TrendEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double close1 = iClose(Symbol(), PERIOD_H1, 1);
    double low1 = iLow(Symbol(), PERIOD_H1, 1);
    double high1 = iHigh(Symbol(), PERIOD_H1, 1);

    if(direction == 1) // Long: price pulled back to EMA, then closed above
    {
    bool pulledToEMA = (low1 <= ema + (atr
    0.3)) && (close1 > ema);
    bool bullishClose = (close1 > iOpen(Symbol(), PERIOD_H1, 1));
    if(pulledToEMA && bullishClose)
    {
    entryPrice = Ask;
    sl = entryPrice - (atr ATRStopMultiplier);
    tp = entryPrice + (atr
    ATRTakeMultiplier);
    return true;
    }
    }
    else if(direction == -1) // Short: price pulled up to EMA, then closed below
    {
    bool pulledToEMA = (high1 >= ema - (atr 0.3)) && (close1 < ema);
    bool bearishClose = (close1 < iOpen(Symbol(), PERIOD_H1, 1));
    if(pulledToEMA && bearishClose)
    {
    entryPrice = Bid;
    sl = entryPrice + (atr
    ATRStopMultiplier);
    tp = entryPrice - (atr ATRTakeMultiplier);
    return true;
    }
    }
    return false;
    }

    //+------------------------------------------------------------------+
    //| Calculate dynamic lot size based on ATR volatility |
    //+------------------------------------------------------------------+
    double CalculateDynamicLotSize(double atr)
    {
    double lot = BaseLotSize;

    // Reduce lot size when ATR is above average (high volatility)
    if(avgATR > 0 && atr > avgATR)
    {
    double reduction = avgATR / atr;
    lot = BaseLotSize
    reduction;
    }

    // Risk-based sizing (optional, uses RiskPerTradePercent)
    if(RiskPerTradePercent > 0 && RiskPerTradePercent <= 5)
    {
    double accountBalance = AccountBalance();
    double riskAmount = accountBalance RiskPerTradePercent / 100.0;
    double slDistance = atr
    ATRStopMultiplier;
    double riskBasedLot = riskAmount / (slDistance 100);
    if(riskBasedLot > 0 && riskBasedLot < lot)
    lot = riskBasedLot;
    }

    lot = NormalizeDouble(lot, 2);
    if(lot < 0.01) lot = 0.01;
    if(lot > 1.0) lot = 1.0;
    return lot;
    }

    //+------------------------------------------------------------------+
    //| 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 = currentATR;
    if(atr <= 0) atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);

    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 in cooldown period after losing trade |
    //+------------------------------------------------------------------+
    bool IsInCooldown()
    {
    if(lastLossTime == 0) return false;
    return (TimeCurrent() - lastLossTime < CooldownMinutes
    60);
    }

    //+------------------------------------------------------------------+
    //| Record loss time when trade closes at a loss |
    //+------------------------------------------------------------------+
    void CheckAndRecordLoss()
    {
    static datetime lastCheck = 0;
    if(TimeCurrent() - lastCheck < 60) return;
    lastCheck = TimeCurrent();

    for(int i = OrdersHistoryTotal()-1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    if(OrderCloseTime() > lastLossTime && OrderProfit() < 0)
    {
    lastLossTime = OrderCloseTime();
    Print("Losing trade recorded. Cooldown activated for ", CooldownMinutes, " minutes.");
    }
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 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;
    }

    // Spread filter
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
    {
    Comment("Spread too high: ", MarketInfo(Symbol(), MODE_SPREAD));
    return;
    }

    // New bar logic (H1)
    if(Time[0] == lastBarTime)
    return;
    lastBarTime = Time[0];

    // Update ATR and average
    currentATR = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
    if(currentATR > 0) avgATR = (avgATR
    0.95) + (currentATR 0.05);

    // Check and record losing trades for cooldown
    CheckAndRecordLoss();

    // Manage existing position
    if(CountPositions() > 0)
    {
    ManageTrailingStop();
    return;
    }

    // Cooldown check after losing trade
    if(IsInCooldown())
    {
    Comment("Cooldown period active. Next trade allowed in ",
    (CooldownMinutes
    60 - (TimeCurrent() - lastLossTime)) / 60, " minutes.");
    return;
    }

    // Volatility guard: skip if ATR too high
    if(avgATR > 0 && currentATR > avgATR * ATRMaxMultiplier)
    {
    Comment("Volatility too high. ATR: ", currentATR);
    return;
    }

    // Get trend direction
    int trendDirection = GetTrendDirection();
    if(trendDirection == 0)
    {
    Comment("No clear trend direction");
    return;
    }

    // RSI momentum confirmation
    if(!CheckRSIMomentum(trendDirection))
    {
    Comment("RSI momentum not confirmed");
    return;
    }

    // Check pullback entry
    double entryPrice = 0, sl = 0, tp = 0;
    if(CheckPullbackEntry(trendDirection, entryPrice, sl, tp, currentATR))
    {
    double lot = CalculateDynamicLotSize(currentATR);
    int cmd = (trendDirection == 1) ? OP_BUY : OP_SELL;
    int ticket = OrderSend(Symbol(), cmd, lot, entryPrice, 5, sl, tp, "Signal Pulse", MagicNumber, 0, clrNONE);
    if(ticket < 0)
    Print("OrderSend failed: ", GetLastError());
    else
    Print("Entry opened. Direction: ", cmd==OP_BUY?"BUY":"SELL", " Lot: ", lot);
    }
    }

    //+------------------------------------------------------------------+
    //| 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 professional EA development principles for XAUUSD observed in commercial products as of Q1 2026.
    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 2 months before live deployment. Past performance does not guarantee future results.