Summary: BTC Volatility Navigator EA is an MQL4 expert advisor for Bitcoin (BTCUSD). It uses volatility contraction breakout with RSI divergence and dynamic position sizing. Suitable for H4 timeframe.




BTC Volatility Navigator EA is built specifically for Bitcoin's unique market behavior: high volatility, frequent gaps, and strong trend persistence. The EA detects periods of volatility contraction (Bollinger Bands squeeze) and enters on breakout with RSI momentum confirmation. A dynamic position sizing mechanism reduces exposure during extreme volatility. The system includes a hard stop-loss based on ATR, trailing stop for profit protection, and a weekly drawdown limiter to preserve capital during adverse conditions.

Recommended Timeframe: H4
Trading Logic:
  • Volatility Contraction: Bollinger Bands (20,2) bandwidth falls below 0.3 <em> average bandwidth over 50 bars.

  • Breakout Entry: Price closes above upper band for long, or below lower band for short, with RSI(14) > 55 for long or < 45 for short.

  • Dynamic Lot Sizing: Base lot = 0.01 per $2000 balance. Reduced by up to 50% when ATR is above 1.5x average.

  • Risk Management: Stop loss at 2.5x ATR, take profit at 5x ATR. Trailing stop activates after 2.5x ATR profit. Weekly loss limit 10%.


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

    //--- input parameters with comments
    input double RiskPerEquity = 1.0; // Risk per trade as % of equity (1%)
    input int BandsPeriod = 20; // Bollinger Bands period
    input double BandsDeviation = 2.0; // Bollinger Bands deviation
    input double BandwidthThreshold = 0.3; // Bandwidth contraction threshold (0.3 = 30% of avg)
    input int RSIPeriod = 14; // RSI period for momentum confirmation
    input int ATRPeriod = 14; // ATR period for stop loss
    input double ATRStopMultiplier = 2.5; // Stop loss as multiple of ATR
    input double ATRTakeMultiplier = 5.0; // Take profit as multiple of ATR
    input double TrailingStart = 2.5; // Trailing start in ATR multiples
    input double TrailingStep = 1.0; // Trailing step in ATR multiples
    input int MagicNumber = 202417; // Unique EA identifier
    input int MaxSpread = 200; // Maximum allowed spread in points (BTC has wider spread)
    input double WeeklyLossLimit = 10.0; // Weekly loss limit as percentage of balance
    input bool UseWeekendClose = true; // Close all trades before Sunday 22:00 GMT

    //--- global variables
    double weeklyStartBalance = 0;
    datetime lastBarTime = 0;
    bool weekendCloseExecuted = false;
    double avgBandwidth = 0;
    double avgATR = 0;

    //+------------------------------------------------------------------+
    //| Expert initialization function |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    weeklyStartBalance = AccountBalance();
    lastBarTime = 0;
    weekendCloseExecuted = false;
    avgATR = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
    if(avgATR <= 0) avgATR = 500 Point;
    avgBandwidth = CalculateBandwidth();
    return(INIT_SUCCEEDED);
    }

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

    //+------------------------------------------------------------------+
    //| Calculate Bollinger Bands bandwidth |
    //+------------------------------------------------------------------+
    double CalculateBandwidth()
    {
    double upper = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
    double lower = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
    double middle = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_MAIN, 1);
    if(middle <= 0) return 0;
    return (upper - lower) / middle;
    }

    //+------------------------------------------------------------------+
    //| Calculate average bandwidth over last 50 bars |
    //+------------------------------------------------------------------+
    double GetAvgBandwidth()
    {
    double sum = 0;
    int count = 0;
    for(int i = 1; i <= 50; i++)
    {
    double upper = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, i);
    double lower = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, i);
    double middle = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_MAIN, i);
    if(middle > 0)
    {
    sum += (upper - lower) / middle;
    count++;
    }
    }
    if(count == 0) return 0.5;
    return sum / count;
    }

    //+------------------------------------------------------------------+
    //| Expert tick function |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // Weekly equity protection
    double currentEquity = AccountEquity();
    double lossPercent = (weeklyStartBalance - currentEquity) / weeklyStartBalance 100;
    if(lossPercent >= WeeklyLossLimit)
    {
    Comment("Weekly loss limit reached. No new trades.");
    return;
    }

    // Weekend close before Sunday night (broker gap risk)
    if(UseWeekendClose && !weekendCloseExecuted)
    {
    datetime currentTime = TimeCurrent();
    if(TimeDayOfWeek(currentTime) == 0 && TimeHour(currentTime) >= 22)
    {
    CloseAllOrders();
    weekendCloseExecuted = true;
    return;
    }
    if(TimeDayOfWeek(currentTime) != 0)
    weekendCloseExecuted = false;
    }

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

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

    // Update average ATR
    double atr = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
    if(atr > 0) avgATR = (avgATR
    0.95) + (atr 0.05);

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

    // Volatility contraction detection
    double currentBW = CalculateBandwidth();
    double avgBW = GetAvgBandwidth();
    if(avgBW > 0 && currentBW > avgBW
    BandwidthThreshold)
    {
    Comment("No volatility contraction. Bandwidth: ", currentBW);
    return;
    }

    // Bollinger Bands values
    double upperBand = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
    double lowerBand = iBands(Symbol(), PERIOD_H4, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
    double close1 = iClose(Symbol(), PERIOD_H4, 1);
    double rsi = iRSI(Symbol(), PERIOD_H4, RSIPeriod, PRICE_CLOSE, 1);

    // Dynamic lot sizing based on balance and volatility
    double baseLot = NormalizeDouble(AccountBalance() RiskPerEquity / 10000.0, 2);
    if(baseLot < 0.01) baseLot = 0.01;
    if(baseLot > 2.0) baseLot = 2.0;

    // Reduce lot size during high volatility
    double volatilityFactor = 1.0;
    if(atr > avgATR
    1.5 && avgATR > 0)
    volatilityFactor = 0.5;
    double finalLot = NormalizeDouble(baseLot volatilityFactor, 2);
    if(finalLot < 0.01) finalLot = 0.01;

    int cmd = -1;
    double sl = 0, tp = 0;
    double ask = Ask;
    double bid = Bid;

    // Long breakout: price closes above upper band, RSI > 55 confirming momentum
    if(close1 > upperBand && rsi > 55)
    {
    cmd = OP_BUY;
    sl = bid - (atr
    ATRStopMultiplier);
    tp = bid + (atr ATRTakeMultiplier);
    }
    // Short breakout: price closes below lower band, RSI < 45 confirming momentum
    else if(close1 < lowerBand && rsi < 45)
    {
    cmd = OP_SELL;
    sl = ask + (atr
    ATRStopMultiplier);
    tp = ask - (atr ATRTakeMultiplier);
    }

    if(cmd != -1)
    {
    int ticket = OrderSend(Symbol(), cmd, finalLot, (cmd==OP_BUY?ask:bid), 5, sl, tp, "BTC Navigator", MagicNumber, 0, clrNONE);
    if(ticket < 0)
    Print("OrderSend failed: ", GetLastError());
    }
    }

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

    double newSL = 0;
    double trailTrigger = atr
    TrailingStart;

    if(OrderType() == OP_BUY)
    {
    double profitPoints = (Bid - OrderOpenPrice()) / Point;
    if(profitPoints >= trailTrigger / Point)
    {
    newSL = Bid - (atr TrailingStep);
    if(newSL > OrderStopLoss())
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated for BUY #", OrderTicket());
    }
    }
    }
    else if(OrderType() == OP_SELL)
    {
    double profitPoints = (OrderOpenPrice() - Ask) / Point;
    if(profitPoints >= trailTrigger / Point)
    {
    newSL = Ask + (atr
    TrailingStep);
    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated for SELL #", OrderTicket());
    }
    }
    }
    break;
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 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 for educational purposes.
    Disclaimer: Bitcoin trading carries extremely high risk due to volatility, liquidity gaps, and broker differences. This EA is provided as-is without any guarantee of profit. Test extensively on a demo account for at least 3 months before live trading. Past performance does not guarantee future results.