Summary: Gold Stabilizer EA is a robust MQL4 robot for XAUUSD. It uses EMA trend filter, ATR-based stops, and volatility-adjusted lot sizing to reduce risk and ensure stable operation on gold.




Gold Stabilizer EA is designed specifically for the high-volatility gold market (XAUUSD). It employs a trend-following logic with a slow EMA filter, ATR-based stop loss and take profit, and a time-restricted trading session to avoid major rollover risks. Lot sizing adapts to current volatility to keep risk per trade consistent.

Load Period Recommendation: H1 (1 Hour). The strategy is optimized for the H1 timeframe to balance signal reliability and trade frequency.

Trading Logic:
  • <strong>Trend Filter</strong>: Uses EMA(200) on H1 to determine the long-term direction. Only long signals when price > EMA200; only short signals when price < EMA200.

  • <strong>Entry Signal</strong>: Uses a fast SMA crossover (SMA5 and SMA20) smoothed by an additional filter. Confirmation requires the crossing to hold for 1 bar.

  • <strong>Risk Management</strong>:

  • - Stop Loss = ATR(14) ATR_Multiplier (default 2.0)
    - Take Profit = Stop Loss
    RiskRewardRatio (default 1.5)
    - Lot size = RiskPercent AccountBalance() / (StopLoss in pips TickValuePerLot)
  • <strong>Time Filter</strong>: Trades only between 08:00-20:00 broker time to avoid low liquidity periods.

  • <strong>Max Spread Control</strong>: Aborts trade if spread exceeds MaxSpread.


  • Disclaimer: Trading foreign exchange and gold carries a high level of risk. Past performance does not guarantee future results. This EA is for educational purposes only. Test thoroughly on a demo account before live use. The author assumes no responsibility for financial losses.

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

    //+------------------------------------------------------------------+
    //| Input Parameters |
    //+------------------------------------------------------------------+
    input double LotSizeFixed = 0.01; // Fixed lot size (if UseRiskPercent=false)
    input bool UseRiskPercent = true; // Use dynamic risk percentage (true=use RiskPercentPerTrade)
    input double RiskPercentPerTrade = 1.0; // Risk % per trade (1% of balance, dynamic lot)
    input double ATR_Multiplier = 2.0; // ATR multiplier for Stop Loss (higher = wider SL)
    input double RiskRewardRatio = 1.5; // Reward:Risk ratio (TP = SL this)
    input int FastMAPeriod = 5; // Fast SMA period for entry signal
    input int SlowMAPeriod = 20; // Slow SMA period for entry signal
    input int TrendEMAPeriod = 200; // EMA period for trend filter
    input int ATRPeriod = 14; // ATR period for volatility measurement
    input int StartHour = 8; // Trading start hour (broker time)
    input int EndHour = 20; // Trading end hour (broker time)
    input double MaxSpread = 35.0; // Maximum allowed spread (in points)
    input int Slippage = 30; // Slippage in points
    input bool UseCloseSignals = true; // Enable exit when opposite crossover occurs
    input long MagicNumber = 20241115; // Unique EA identifier

    //+------------------------------------------------------------------+
    //| Global variables |
    //+------------------------------------------------------------------+
    double lastBarTime = 0;
    bool tradeAllowed = true;

    //+------------------------------------------------------------------+
    //| Expert initialization function |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    if(UseRiskPercent && RiskPercentPerTrade <= 0)
    {
    Print("Error: RiskPercentPerTrade must be >0 when UseRiskPercent=true");
    return(INIT_PARAMETERS_INCORRECT);
    }
    if(ATR_Multiplier <= 0 || RiskRewardRatio <= 0)
    {
    Print("Error: Multipliers must be positive");
    return(INIT_PARAMETERS_INCORRECT);
    }
    lastBarTime = Time[0];
    return(INIT_SUCCEEDED);
    }

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

    //+------------------------------------------------------------------+
    //| Expert tick function |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // Check new bar
    if(lastBarTime == Time[0]) return;
    lastBarTime = Time[0];

    // Refresh rates
    RefreshRates();

    // Check time and spread conditions
    if(!IsTradeTime()) return;
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return;

    // Manage existing orders (trailing not used for low-risk simplicity)
    ManageOrders();

    // Generate new signal
    int signal = GetSignal();
    if(signal != 0)
    ExecuteTrade(signal);
    }

    //+------------------------------------------------------------------+
    //| Check if current time is within allowed trading window |
    //+------------------------------------------------------------------+
    bool IsTradeTime()
    {
    datetime now = TimeCurrent();
    int hour = TimeHour(now);
    return (hour >= StartHour && hour < EndHour);
    }

    //+------------------------------------------------------------------+
    //| Get trading signal: 1 = Buy, -1 = Sell, 0 = No signal |
    //+------------------------------------------------------------------+
    int GetSignal()
    {
    double emaTrend = iMA(Symbol(), PERIOD_H1, TrendEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double fastMA = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
    double slowMA = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
    double prevFast = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
    double prevSlow = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);

    if(emaTrend == 0 || fastMA == 0 || slowMA == 0) return 0;

    bool trendUp = Close[1] > emaTrend;
    bool trendDown = Close[1] < emaTrend;

    // Bullish crossover with confirmation
    if(prevFast <= prevSlow && fastMA > slowMA && trendUp)
    return 1;
    // Bearish crossover with confirmation
    if(prevFast >= prevSlow && fastMA < slowMA && trendDown)
    return -1;

    return 0;
    }

    //+------------------------------------------------------------------+
    //| Execute buy or sell order |
    //+------------------------------------------------------------------+
    void ExecuteTrade(int signal)
    {
    // Close opposite orders first
    CloseOrders(-signal);

    // Check if same direction order already exists
    if(CountOrders(signal) > 0) return;

    double atr = iATR(Symbol(), 0, ATRPeriod, 1);
    if(atr <= 0) return;
    double slDistance = atr
    ATR_Multiplier;
    double tpDistance = slDistance RiskRewardRatio;
    double entryPrice, slPrice, tpPrice;
    int cmd;
    double point = Point;
    if(Digits == 3 || Digits == 5) point = Point
    10;

    if(signal == 1) // Buy
    {
    entryPrice = Ask;
    slPrice = entryPrice - slDistance;
    tpPrice = entryPrice + tpDistance;
    cmd = OP_BUY;
    }
    else // Sell
    {
    entryPrice = Bid;
    slPrice = entryPrice + slDistance;
    tpPrice = entryPrice - tpDistance;
    cmd = OP_SELL;
    }

    // Normalize prices
    slPrice = NormalizeDouble(slPrice, Digits);
    tpPrice = NormalizeDouble(tpPrice, Digits);
    entryPrice = NormalizeDouble(entryPrice, Digits);

    double lot = CalculateLotSize(slDistance, signal);
    if(lot <= 0) return;

    int ticket = OrderSend(Symbol(), cmd, lot, entryPrice, Slippage, slPrice, tpPrice, "Gold Stabilizer", MagicNumber, 0, clrNONE);
    if(ticket < 0)
    Print("OrderSend failed: ", GetLastError());
    }

    //+------------------------------------------------------------------+
    //| Calculate lot size based on risk percent or fixed lot |
    //+------------------------------------------------------------------+
    double CalculateLotSize(double slDistanceInPoints, int signal)
    {
    if(!UseRiskPercent)
    return LotSizeFixed;

    double balance = AccountBalance();
    double riskAmount = balance RiskPercentPerTrade / 100.0;
    double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
    if(tickValue <= 0) return 0;

    // slDistanceInPoints is in price units, convert to points
    double point = Point;
    if(Digits == 3 || Digits == 5) point = Point
    10;
    double slPoints = slDistanceInPoints / point;
    if(slPoints <= 0) return 0;

    double lot = riskAmount / (slPoints tickValue);
    double minLot = MarketInfo(Symbol(), MODE_MINLOT);
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    double stepLot = MarketInfo(Symbol(), MODE_LOTSTEP);

    lot = MathFloor(lot / stepLot)
    stepLot;
    lot = MathMax(minLot, MathMin(maxLot, lot));
    return lot;
    }

    //+------------------------------------------------------------------+
    //| Count orders with given signal direction |
    //+------------------------------------------------------------------+
    int CountOrders(int signal)
    {
    int count = 0;
    for(int i=OrdersTotal()-1; i>=0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    if((signal == 1 && OrderType() == OP_BUY) || (signal == -1 && OrderType() == OP_SELL))
    count++;
    }
    }
    }
    return count;
    }

    //+------------------------------------------------------------------+
    //| Close orders opposite to given signal |
    //+------------------------------------------------------------------+
    void CloseOrders(int oppositeSignal)
    {
    for(int i=OrdersTotal()-1; i>=0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    bool opposite = (oppositeSignal == 1 && OrderType() == OP_SELL) ||
    (oppositeSignal == -1 && OrderType() == OP_BUY);
    if(opposite)
    {
    if(OrderType() == OP_BUY)
    OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrNONE);
    else if(OrderType() == OP_SELL)
    OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrNONE);
    }
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| Manage existing orders: optional opposite crossover exit |
    //+------------------------------------------------------------------+
    void ManageOrders()
    {
    if(!UseCloseSignals) return;

    double fastMA = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
    double slowMA = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
    double prevFast = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
    double prevSlow = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);

    bool bearCross = (prevFast > prevSlow && fastMA <= slowMA);
    bool bullCross = (prevFast < prevSlow && fastMA >= slowMA);

    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 && bearCross)
    OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrNONE);
    else if(OrderType() == OP_SELL && bullCross)
    OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrNONE);
    }
    }
    }
    }
    //+------------------------------------------------------------------+
    ``

    Reference: Based on common low-risk trend-following principles for gold. Adapted for MQL4 stability and XAUUSD volatility.