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:
1. Trend Filter: EMA(50) determines primary direction. Price above EMA → long only; below → short only.
2. Momentum Confirmation: RSI(14) must confirm the trend (RSI > 50 for longs, RSI < 50 for shorts).
3. Entry Signal: After trend confirmation, wait for a pullback to the EMA50 zone with a confirming candle (close beyond EMA in trend direction).
4. Volatility Guard: Current ATR(14) must not exceed 1.8x the 30-period average ATR.
5. 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.