Summary: Gold Aurora EA is an MQL4 expert advisor for XAUUSD that combines volatility breakout detection, ADX trend strength filter, and dynamic position sizing. Designed for stable H1 operation.




Gold Aurora EA is engineered for stable gold trading using a unique multi-strategy approach. Unlike single-strategy systems that fail when market conditions change, this EA monitors three distinct market states — ranging, trending, and breakout — and adapts its logic accordingly. The core entry signal is based on volatility contraction patterns (narrowing Bollinger Bands) followed by expansion breaks, confirmed by ADX trend direction. The EA includes an independent risk management module with daily loss limits, spread control, and a unique "market memory" function that prevents repeated entries after consecutive losses.

Recommended Timeframe: H1
Trading Logic:
1. Volatility Regime Detection: Calculate Bollinger Bands (20,2) and measure bandwidth. Narrow bands (bandwidth < 0.015) indicate compression, wide bands (>0.03) indicate expansion.
2. Breakout Confirmation: After compression, when price closes outside the bands with a full candle body (close-open > 0.7 × range), trigger entry.
3. Trend Filter: ADX(14) must be > 20 for trend direction; if ADX < 20, use mean reversion logic (price returns to MA).
4. Risk Management: Fixed stop loss at 1.8× ATR(14), take profit at 2.5× ATR. Trailing stop activates after 1× ATR profit.

```mql4
//+------------------------------------------------------------------+
//| GoldAuroraEA.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 BBP Period = 20; // Bollinger Bands period
input double BBDeviation = 2.0; // Bollinger Bands deviation
input double CompressionThreshold = 0.015; // Bandwidth threshold for compression (<0.015)
input double ExpansionThreshold = 0.030; // Bandwidth threshold for expansion (>0.030)
input double BodyRangeMinRatio = 0.7; // Minimum body/range ratio for momentum candle
input int ADXPeriod = 14; // ADX period for trend strength
input int ADXTrendThreshold = 20; // ADX threshold for trend detection
input int ATRPeriod = 14; // ATR period for stop loss
input double ATRStopMultiplier = 1.8; // Stop loss as multiple of ATR
input double ATRTakeMultiplier = 2.5; // 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 int MaxConsecutiveLosses = 3; // Max consecutive losses before pause
input int MagicNumber = 202501; // 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

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

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

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

//+------------------------------------------------------------------+
//| Calculate Bollinger Bands width (bandwidth) |
//+------------------------------------------------------------------+
double CalculateBandwidth(int shift)
{
double upper = iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, PRICE_CLOSE, MODE_UPPER, shift);
double lower = iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, PRICE_CLOSE, MODE_LOWER, shift);
double middle = iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, PRICE_CLOSE, MODE_MAIN, shift);
if(middle <= 0) return 0;
return (upper - lower) / middle;
}

//+------------------------------------------------------------------+
//| Check momentum candle quality |
//+------------------------------------------------------------------+
bool IsQualityMomentumCandle(int direction)
{
double open = iOpen(Symbol(), PERIOD_H1, 1);
double close = iClose(Symbol(), PERIOD_H1, 1);
double high = iHigh(Symbol(), PERIOD_H1, 1);
double low = iLow(Symbol(), PERIOD_H1, 1);
double range = high - low;
double body = MathAbs(close - open);

if(range <= 0) return false;
if(body / range < BodyRangeMinRatio) return false;

if(direction == 1) // bullish momentum
return (close > open && close > iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, MODE_UPPER, 1));
else if(direction == -1) // bearish momentum
return (close < open && close < iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, MODE_LOWER, 1));

return false;
}

//+------------------------------------------------------------------+
//| Get ADX trend direction and strength |
//+------------------------------------------------------------------+
int GetADXTrend()
{
double adx = iADX(Symbol(), PERIOD_H1, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
double diPlus = iADX(Symbol(), PERIOD_H1, ADXPeriod, PRICE_CLOSE, MODE_PLUSDI, 1);
double diMinus = iADX(Symbol(), PERIOD_H1, ADXPeriod, PRICE_CLOSE, MODE_MINUSDI, 1);

if(adx < ADXTrendThreshold) return 0; // no trend (mean reversion mode)
if(diPlus > diMinus) return 1;
if(diMinus > diPlus) return -1;
return 0;
}

//+------------------------------------------------------------------+
//| Mean reversion entry (range market logic) |
//+------------------------------------------------------------------+
bool CheckMeanReversionEntry(int &cmd, double &entryPrice, double &sl, double &tp, double atr)
{
double close1 = iClose(Symbol(), PERIOD_H1, 1);
double ma20 = iMA(Symbol(), PERIOD_H1, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double upperBand = iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, MODE_UPPER, 1);
double lowerBand = iBands(Symbol(), PERIOD_H1, BBPeriod, BBDeviation, 0, MODE_LOWER, 1);

// Buy when price bounces from lower band toward MA
if(close1 < lowerBand + (upperBand - lowerBand) * 0.2 && close1 > ma20 * 0.998)
{
cmd = OP_BUY;
entryPrice = Ask;
sl = entryPrice - (atr * ATRStopMultiplier * 0.8);
tp = entryPrice + (atr * ATRTakeMultiplier * 0.7);
return true;
}
// Sell when price bounces from upper band toward MA
else if(close1 > upperBand - (upperBand - lowerBand) * 0.2 && close1 < ma20 * 1.002)
{
cmd = OP_SELL;
entryPrice = Bid;
sl = entryPrice + (atr * ATRStopMultiplier * 0.8);
tp = entryPrice - (atr * ATRTakeMultiplier * 0.7);
return true;
}
return false;
}

//+------------------------------------------------------------------+
//| Trend breakout entry |
//+------------------------------------------------------------------+
bool CheckTrendBreakoutEntry(int trendDir, double &entryPrice, double &sl, double &tp, double atr)
{
if(trendDir == 0) return false;

double bandwidth = CalculateBandwidth(1);
bool isCompressed = (bandwidth > 0 && bandwidth < CompressionThreshold);

if(!isCompressed) return false;

if(trendDir == 1 && IsQualityMomentumCandle(1))
{
cmd = OP_BUY;
entryPrice = Ask;
sl = entryPrice - (atr * ATRStopMultiplier);
tp = entryPrice + (atr * ATRTakeMultiplier);
return true;
}
else if(trendDir == -1 && IsQualityMomentumCandle(-1))
{
cmd = OP_SELL;
entryPrice = Bid;
sl = entryPrice + (atr * ATRStopMultiplier);
tp = entryPrice - (atr * ATRTakeMultiplier);
return true;
}
return false;
}

//+------------------------------------------------------------------+
//| Track consecutive losses for market memory |
//+------------------------------------------------------------------+
void TrackTradeResult()
{
static int prevTotalOrders = 0;
static double prevEquity = 0;

int currentOrders = CountPositions();
double currentEquity = AccountEquity();

// Check if a trade just closed
if(prevTotalOrders > 0 && currentOrders == 0)
{
double equityChange = currentEquity - prevEquity;
if(equityChange < 0) // loss occurred
{
consecutiveLosses++;
lastLossTime = TimeCurrent();
}
else if(equityChange > 0) // profit occurred
{
consecutiveLosses = 0;
}
}

if(currentOrders > 0)
prevEquity = currentEquity;

prevTotalOrders = currentOrders;
}

//+------------------------------------------------------------------+
//| Manage trailing stop |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atr)
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
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;
}
}
}
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Track trade results for market memory
TrackTradeResult();

// Market memory: pause after consecutive losses
if(consecutiveLosses >= MaxConsecutiveLosses)
{
if(TimeCurrent() - lastLossTime < 3600) // pause for 1 hour
{
Comment("Market memory active: ", consecutiveLosses, " consecutive losses. Paused.");
return;
}
else
{
consecutiveLosses = 0; // reset after cooldown
}
}

// 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];

// Manage existing position
int posCount = CountPositions();
if(posCount > 0)
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > 0) ManageTrailingStop(atr);
return;
}

// Get ATR for volatility
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > 0) avgATR = (avgATR * 0.95) + (atr * 0.05);

// Determine market regime via ADX
int adxTrend = GetADXTrend();
double bandwidth = CalculateBandwidth(1);

int cmd = -1;
double entryPrice = 0, sl = 0, tp = 0;
bool entryFound = false;

// Regime 1: Trend market (ADX >= 20) with volatility compression
if(adxTrend != 0 && bandwidth < CompressionThreshold)
{
entryFound = CheckTrendBreakoutEntry(adxTrend, entryPrice, sl, tp, atr);
if(entryFound) cmd = (adxTrend == 1) ? OP_BUY : OP_SELL;
}
// Regime 2: Ranging market (ADX < 20) - use mean reversion
else if(adxTrend == 0)
{
entryFound = CheckMeanReversionEntry(cmd, entryPrice, sl, tp, atr);
}

if(entryFound && cmd != -1)
{
int ticket = OrderSend(Symbol(), cmd, LotSize, entryPrice, 5, sl, tp, "Gold Aurora", MagicNumber, 0, clrNONE);
if(ticket < 0)
Print("OrderSend failed: ", GetLastError());
else
Print("Entry opened. Regime: ", adxTrend!=0?"Trend":"Range");
}
}

//+------------------------------------------------------------------+
//| 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 multi-strategy principles observed in professional gold trading systems including GEN V Gold and UV Gold .
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.