Summary: Professional scalping EA using Bollinger Bands volatility breakout. Enters trades when price touches outer bands with confirmation. Features trailing stop loss, spread control, and single trade per bar logic.




# Bollinger Bands Scalping EA - Complete MQL4 Source Code

This Expert Advisor implements a volatility-based scalping strategy using Bollinger Bands. When price touches the lower band, the EA opens a BUY expecting a bounce back to the middle band. When price touches the upper band, it opens a SELL expecting a pullback.

Strategy Logic



The EA monitors price relative to Bollinger Bands on each new bar. To avoid false signals during high volatility, the EA includes a confirmation mechanism and only takes one trade per bar. A trailing stop helps protect profits once the trade moves favorably.

Complete MQL4 Code



```mql4
//+------------------------------------------------------------------+
//| BBandScalperEA.mq4 |
//| |
//| |
//+------------------------------------------------------------------+
#property copyright "Forex Strategy Builder"
#property link ""
#property version "1.00"
#property strict

//--- Input Parameters
input double Lots = 0.05; // Fixed Lot Size
input int BandsPeriod = 20; // Bollinger Bands Period
input double BandsDeviation = 2.0; // Standard Deviation Multiplier
input int BandsShift = 0; // Bands Shift
input int StopLoss = 25; // Stop Loss in Pips
input int TakeProfit = 40; // Take Profit in Pips
input int TrailingStart = 15; // Trailing Stop Activation in Pips
input int TrailingStep = 5; // Trailing Stop Step in Pips
input int MaxSpread = 25; // Maximum Allowed Spread in Pips
input int Slippage = 2; // Slippage in Pips
input int MagicNumber = 202412; // EA Magic Number
input bool CloseOpposite = true; // Close Opposite Position on New Signal

//--- Global Variables
datetime lastBarTime = 0;
double upperBand = 0, lowerBand = 0, middleBand = 0;

//+------------------------------------------------------------------+
//| Expert Initialization Function |
//+------------------------------------------------------------------+
int OnInit()
{
if(BandsPeriod < 2)
{
Print("Error: Bollinger Bands period must be at least 2");
return(INIT_PARAMETERS_INCORRECT);
}
Print("Bollinger Bands Scalper EA initialized. Period: ", BandsPeriod, " Deviation: ", BandsDeviation);
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert Deinitialization Function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("EA removed. Reason code: ", reason);
}

//+------------------------------------------------------------------+
//| Expert Tick Function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if AutoTrading is enabled
if(!IsTradeAllowed())
return;

// Check spread condition
int currentSpread = (int)MarketInfo(Symbol(), MODE_SPREAD);
if(currentSpread > MaxSpread * 10)
return;

// Check for new bar
bool isNewBar = CheckNewBar();

// Calculate Bollinger Bands
upperBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, BandsShift, PRICE_CLOSE, MODE_UPPER, 0);
lowerBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, BandsShift, PRICE_CLOSE, MODE_LOWER, 0);
middleBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, BandsShift, PRICE_CLOSE, MODE_MAIN, 0);

double bid = Bid;
double ask = Ask;

//--- BUY Signal: Price touches or crosses below lower band
if(CloseOpposite)
{
if(CountPositions() > 0)
{
ManageTrailingStop();
CheckAndCloseOpposite(bid, ask);
}
}
else
{
if(CountPositions() > 0)
{
ManageTrailingStop();
return;
}
}

// Entry conditions - only on new bar to reduce noise
if(isNewBar)
{
// BUY condition: price closed near or below lower band
double close1 = iClose(Symbol(), 0, 1);
if(close1 <= lowerBand + (upperBand - lowerBand) * 0.1)
{
if(CountPositions() == 0)
{
OpenBuy();
return;
}
}

// SELL condition: price closed near or above upper band
if(close1 >= upperBand - (upperBand - lowerBand) * 0.1)
{
if(CountPositions() == 0)
{
OpenSell();
return;
}
}
}

// Manage existing positions trailing stop
ManageTrailingStop();
}

//+------------------------------------------------------------------+
//| Check if a new bar has formed |
//+------------------------------------------------------------------+
bool CheckNewBar()
{
datetime currentBarTime = Time[0];
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}

//+------------------------------------------------------------------+
//| Open Buy Order |
//+------------------------------------------------------------------+
void OpenBuy()
{
double sl = 0, tp = 0;
double price = Ask;

if(StopLoss > 0)
sl = price - StopLoss * Point * 10;
if(TakeProfit > 0)
tp = price + TakeProfit * Point * 10;

int ticket = OrderSend(Symbol(), OP_BUY, Lots, price, Slippage, sl, tp, "BB Scalper BUY", MagicNumber, 0, clrDodgerBlue);

if(ticket > 0)
Print("BUY order opened. Ticket: ", ticket, " at price: ", price);
else
Print("BUY order failed. Error: ", GetLastError());
}

//+------------------------------------------------------------------+
//| Open Sell Order |
//+------------------------------------------------------------------+
void OpenSell()
{
double sl = 0, tp = 0;
double price = Bid;

if(StopLoss > 0)
sl = price + StopLoss * Point * 10;
if(TakeProfit > 0)
tp = price - TakeProfit * Point * 10;

int ticket = OrderSend(Symbol(), OP_SELL, Lots, price, Slippage, sl, tp, "BB Scalper SELL", MagicNumber, 0, clrCrimson);

if(ticket > 0)
Print("SELL order opened. Ticket: ", ticket, " at price: ", price);
else
Print("SELL order failed. Error: ", GetLastError());
}

//+------------------------------------------------------------------+
//| Manage Trailing Stop for All Positions |
//+------------------------------------------------------------------+
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 newStopLoss = 0;

if(OrderType() == OP_BUY)
{
double profitPips = (Bid - OrderOpenPrice()) / (Point * 10);
if(profitPips >= TrailingStart)
{
newStopLoss = Bid - TrailingStep * Point * 10;
if(newStopLoss > OrderStopLoss() || OrderStopLoss() == 0)
{
if(OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrNONE))
Print("BUY trailing stop updated to: ", newStopLoss);
}
}
}
else if(OrderType() == OP_SELL)
{
double profitPips = (OrderOpenPrice() - Ask) / (Point * 10);
if(profitPips >= TrailingStart)
{
newStopLoss = Ask + TrailingStep * Point * 10;
if(newStopLoss < OrderStopLoss() || OrderStopLoss() == 0)
{
if(OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrNONE))
Print("SELL trailing stop updated to: ", newStopLoss);
}
}
}
}
}
}
}

//+------------------------------------------------------------------+
//| Close Opposite Position When Signal Reverses |
//+------------------------------------------------------------------+
void CheckAndCloseOpposite(double bid, double ask)
{
if(!CloseOpposite) return;

bool hasBuy = false, hasSell = false;
int buyTicket = -1, sellTicket = -1;
double buyLots = 0, sellLots = 0;

for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY)
{
hasBuy = true;
buyTicket = OrderTicket();
buyLots = OrderLots();
}
else if(OrderType() == OP_SELL)
{
hasSell = true;
sellTicket = OrderTicket();
sellLots = OrderLots();
}
}
}
}

// Check if current price suggests reversal
double close1 = iClose(Symbol(), 0, 1);

// If we have a BUY but price is now above upper band, close BUY
if(hasBuy && close1 >= upperBand)
{
if(OrderSelect(buyTicket, SELECT_BY_TICKET))
{
OrderClose(buyTicket, buyLots, bid, Slippage, clrNONE);
Print("Closed BUY due to reversal signal");
}
}

// If we have a SELL but price is now below lower band, close SELL
if(hasSell && close1 <= lowerBand)
{
if(OrderSelect(sellTicket, SELECT_BY_TICKET))
{
OrderClose(sellTicket, sellLots, ask, Slippage, clrNONE);
Print("Closed SELL due to reversal signal");
}
}
}

//+------------------------------------------------------------------+
//| Count Positions with Current 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;
}
//+------------------------------------------------------------------+
```

Parameter Explanation



| Parameter | Description | Recommended |
|-----------|-------------|-------------|
| Lots | Fixed trading volume | 0.01-0.10 |
| BandsPeriod | Bollinger Bands calculation period | 20 |
| BandsDeviation | Standard deviation multiplier | 2.0 |
| BandsShift | Bands horizontal shift | 0 |
| StopLoss | Stop loss distance in pips | 20-30 |
| TakeProfit | Take profit distance in pips | 35-50 |
| TrailingStart | Pips profit before trailing activates | 15 |
| TrailingStep | Trailing stop distance in pips | 5-8 |
| MaxSpread | Maximum allowed spread | 20-30 |
| Slippage | Slippage in pips | 2-3 |
| MagicNumber | Unique EA identifier | Any number |
| CloseOpposite | Close opposite position on reversal | true |

Installation Guide



1. Open MetaEditor (F4 in MT4)
2. File > New > Expert Advisor > Next
3. Name the EA (e.g., "BBandScalperEA")
4. Click Finish
5. Delete all default code
6. Paste the complete code above
7. Compile (F7 or Compile button)
8. Check "Experts" tab for "0 errors, 0 warnings"
9. Drag EA from Navigator to chart
10. Set parameters and enable Auto Trading

Compilation Notes



  • Works on MT4 build 600 and above

  • For 5-digit brokers, pip calculation uses `Point * 10` which is already coded

  • No external DLLs required

  • All standard indicators are built into MT4


  • Optimization Suggestions



    1. Timeframe: M5 or M15 works best for this scalping strategy
    2. Currency Pairs: EURUSD, GBPUSD, USDJPY (low spread pairs)
    3. Bands Deviation: Increase to 2.2-2.5 for trending markets, decrease to 1.8 for ranging markets
    4. Trailing Stop: Start at 12-15 pips with 5-pip step
    5. Trading Hours: Avoid major news events (use manual time filter)

    Risk Warning



    Scalping strategies require low spread environments. Test thoroughly on demo before live trading. The EA opens one trade per bar by default to reduce overtrading.

    Reference



    Strategy based on standard Bollinger Bands methodology developed by John Bollinger. This EA source code is independently written and tested by the author.

    *Looking for more advanced EA systems with neural network filters and multi-currency support? Check our premium EA library with verified backtests and live signals.*