Bollinger Bands Breakout EA - Complete MQL4 Source Code
This Expert Advisor implements a classic volatility-based breakout strategy using Bollinger Bands. When price closes outside the upper or lower band and then re-enters the band, the EA opens a position in the breakout direction.
Strategy Logic
The Bollinger Bands consist of a middle SMA and two standard deviation channels. When price breaks above the upper band and closes back inside, a BUY signal is generated. When price breaks below the lower band and closes back inside, a SELL signal is generated. This captures momentum continuation after volatility expansion.
Complete MQL4 Code
``
mql4
//+------------------------------------------------------------------+
//| BBreakoutEA.mq4 |
//| Version 2.0 |
//+------------------------------------------------------------------+
#property copyright "Forex Strategy Builder"
#property link ""
#property version "2.00"
#property strict
//--- Input Parameters
input double LotSize = 0.1; // Fixed lot size
input int BBPeriod = 20; // Bollinger Bands period
input double BBDeviation = 2.0; // Standard deviation multiplier
input int MAPrice = PRICE_CLOSE; // Price type for bands
input int ATRPeriod = 14; // ATR period for filter
input double ATRFilter = 1.5; // Minimum ATR multiplier for entry
input int StopLoss = 0; // Stop loss in pips (0 = ATR based)
input int TakeProfit = 0; // Take profit in pips (0 = ATR based)
input double RiskPercent = 2.0; // Risk percentage per trade (0=use fixed lot)
input int TrailingStart = 25; // Trailing stop activation in pips
input int TrailingStep = 15; // Trailing stop distance in pips
input int MaxSpread = 35; // Maximum allowed spread in pips
input int MagicNumber = 202412; // EA magic number
input bool CloseOpposite = true; // Close opposite position on new signal
//--- Global Variables
double upperBand = 0, lowerBand = 0, middleBand = 0;
double atrValue = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(BBPeriod < 5)
{
Print("Error: Bollinger Bands period must be at least 5");
return(INIT_PARAMETERS_INCORRECT);
}
Print("Bollinger Bands Breakout EA initialized");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("EA removed. Reason code: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Safety checks
if(!IsTradeAllowed()) return;
if(IsNewBar() == false) return;
// Check spread
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread Point 10) return;
// Calculate indicators
CalculateBollingerBands();
atrValue = iATR(Symbol(), 0, ATRPeriod, 1);
// Validate ATR filter
if(atrValue <= 0) return;
if(ATRFilter > 0 && atrValue / Point < ATRFilter 10) return;
// Get current and previous close prices
double closeCurr = Close[0];
double closePrev = Close[1];
double upperPrev = iBands(Symbol(), 0, BBPeriod, BBDeviation, 0, MAPrice, MODE_UPPER, 1);
double lowerPrev = iBands(Symbol(), 0, BBPeriod, BBDeviation, 0, MAPrice, MODE_LOWER, 1);
// Check for existing positions
int posCount = CountPositions();
// BUY Signal: Price closed above upper band on previous bar, now inside
if(closePrev > upperPrev && closeCurr <= upperBand)
{
if(posCount > 0 && CloseOpposite) CloseAllPositions();
if(CountPositions() == 0) OpenBuy();
}
// SELL Signal: Price closed below lower band on previous bar, now inside
else if(closePrev < lowerPrev && closeCurr >= lowerBand)
{
if(posCount > 0 && CloseOpposite) CloseAllPositions();
if(CountPositions() == 0) OpenSell();
}
// Trailing stop management
if(posCount > 0) ManageTrailingStop();
}
//+------------------------------------------------------------------+
//| Calculate current Bollinger Bands values |
//+------------------------------------------------------------------+
void CalculateBollingerBands()
{
upperBand = iBands(Symbol(), 0, BBPeriod, BBDeviation, 0, MAPrice, MODE_UPPER, 0);
lowerBand = iBands(Symbol(), 0, BBPeriod, BBDeviation, 0, MAPrice, MODE_LOWER, 0);
middleBand = iBands(Symbol(), 0, BBPeriod, BBDeviation, 0, MAPrice, MODE_MAIN, 0);
}
//+------------------------------------------------------------------+
//| Open Buy Order |
//+------------------------------------------------------------------+
void OpenBuy()
{
double lot = CalculateLotSize();
double sl = 0, tp = 0;
double price = Ask;
// Calculate dynamic SL/TP based on ATR
if(StopLoss > 0)
{
sl = price - StopLoss Point 10;
}
else if(ATRPeriod > 0)
{
sl = price - atrValue 1.5;
}
if(TakeProfit > 0)
{
tp = price + TakeProfit Point 10;
}
else if(ATRPeriod > 0)
{
tp = price + atrValue 2.5;
}
int ticket = OrderSend(Symbol(), OP_BUY, lot, price, 3, sl, tp, "BB Breakout BUY", MagicNumber, 0, clrDodgerBlue);
if(ticket > 0)
Print("Buy order opened. Ticket: ", ticket);
else
Print("Buy order failed. Error: ", GetLastError());
}
//+------------------------------------------------------------------+
//| Open Sell Order |
//+------------------------------------------------------------------+
void OpenSell()
{
double lot = CalculateLotSize();
double sl = 0, tp = 0;
double price = Bid;
if(StopLoss > 0)
{
sl = price + StopLoss Point 10;
}
else if(ATRPeriod > 0)
{
sl = price + atrValue 1.5;
}
if(TakeProfit > 0)
{
tp = price - TakeProfit Point 10;
}
else if(ATRPeriod > 0)
{
tp = price - atrValue 2.5;
}
int ticket = OrderSend(Symbol(), OP_SELL, lot, price, 3, sl, tp, "BB Breakout SELL", MagicNumber, 0, clrCrimson);
if(ticket > 0)
Print("Sell order opened. Ticket: ", ticket);
else
Print("Sell order failed. Error: ", GetLastError());
}
//+------------------------------------------------------------------+
//| Calculate lot size based on risk percentage |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
if(RiskPercent <= 0 || StopLoss == 0 && ATRPeriod == 0)
return LotSize;
double riskMoney = AccountBalance() RiskPercent / 100.0;
double stopPoints;
if(StopLoss > 0)
stopPoints = StopLoss;
else
stopPoints = (atrValue 1.5) / (Point 10);
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double calculatedLot = riskMoney / (stopPoints tickValue);
calculatedLot = MathFloor(calculatedLot / lotStep) lotStep;
calculatedLot = MathMax(minLot, MathMin(maxLot, calculatedLot));
return NormalizeDouble(calculatedLot, 2);
}
//+------------------------------------------------------------------+
//| Count positions with this EA's magic number |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrWhite);
if(!result)
Print("Close failed: ", GetLastError());
}
}
}
}
//+------------------------------------------------------------------+
//| Trailing stop management |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
if(TrailingStart <= 0) return;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double newSL = 0;
double currentSL = OrderStopLoss();
if(OrderType() == OP_BUY)
{
double profitPoints = (Bid - OrderOpenPrice()) / (Point 10);
if(profitPoints >= TrailingStart)
{
newSL = Bid - TrailingStep Point 10;
if(newSL > currentSL || currentSL == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrWhite);
}
}
else if(OrderType() == OP_SELL)
{
double profitPoints = (OrderOpenPrice() - Ask) / (Point 10);
if(profitPoints >= TrailingStart)
{
newSL = Ask + TrailingStep Point 10;
if(newSL < currentSL || currentSL == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrWhite);
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check if new bar has formed |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime lastBarTime = 0;
datetime currentBarTime = Time[0];
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
`
Parameter Explanation
| Parameter | Description | Recommended Value |
|-----------|-------------|-------------------|
| LotSize | Fixed lot size when risk management disabled | 0.01-0.1 |
| BBPeriod | Bollinger Bands calculation period | 20 |
| BBDeviation | Standard deviation multiplier | 2.0 |
| MAPrice | Price type for band calculation | PRICE_CLOSE |
| ATRPeriod | ATR period for volatility filter | 14 |
| ATRFilter | Minimum ATR multiplier to allow trades | 1.0-2.0 |
| StopLoss | Fixed stop loss in pips (0 = ATR based) | 0 |
| TakeProfit | Fixed take profit in pips (0 = ATR based) | 0 |
| RiskPercent | Risk per trade (% of balance, 0=use fixed lot) | 1.0-2.0 |
| TrailingStart | Pips profit to activate trailing | 25 |
| TrailingStep | Trailing stop distance in pips | 15 |
| MaxSpread | Maximum spread to open trades | 30-40 |
| MagicNumber | Unique identifier for EA trades | Any number |
| CloseOpposite | Close existing position on opposite signal | true |
Installation Guide
Launch MetaEditor in MT4 (F4)
Create new Expert Advisor (File > New > Expert Advisor)
Replace default code with the complete MQL4 code above
Press F7 or click Compile button
Check "Experts" tab for successful compilation
Drag EA from Navigator to chart
Configure parameters in Inputs tab
Enable AutoTrading (Alt+T)
Compilation Tips
For 5-digit brokers, the EA uses Point * 10 for pip calculation automatically
Ensure #property strict` is present to avoid hidden errorsStrategy Optimization Suggestions
Reference
This EA source code is independently developed and tested based on standard Bollinger Bands breakout methodology described in John Bollinger's "Bollinger on Bollinger Bands".
For advanced EA collection including multi-strategy systems and neural network based filters, check our premium package with verified backtest reports.