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:
  • Volatility Regime Detection: Calculate Bollinger Bands (20,2) and measure bandwidth. Narrow bands (bandwidth < 0.015) indicate compression, wide bands (>0.03) indicate expansion.

  • Breakout Confirmation: After compression, when price closes outside the bands with a full candle body (close-open > 0.7 × range), trigger entry.

  • Trend Filter: ADX(14) must be > 20 for trend direction; if ADX < 20, use mean reversion logic (price returns to MA).

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