Viewing the resource: Bollinger Bands EA: Trade Mean-Reversion with Precision

Bollinger Bands EA: Trade Mean-Reversion with Precision

Allan Munene Mutiiria 2025-06-20 22:27:32 70 Views
Join our fun, newbie-friendly guide to the Bollinger Bands EA MQL5 code! We’ll explain every funct...

Introduction

Hey there, future forex trailblazer! Picture the forex market as a rubber band, stretching far before snapping back to its center. The Bollinger Bands EA, powered by John Bollinger’s legendary indicator, is your trusty guide, catching those snap-backs to trade mean-reversion with precision. This article is your roadmap to automating that bounce with MQL5 code on MetaTrader 5. We’ll explore the code with vivid detail, explaining every major function like you’re new to coding (no shade!), and weave it together with humor and flow, like a storyteller spinning a tale by a campfire. By the end, you’ll be ready to let this Expert Advisor (EA) trade market swings for you. Let’s get bouncing!

Strategy Blueprint

The Bollinger Bands EA leverages the Bollinger Bands indicator, which consists of:

  • Middle Band: A 20-period simple moving average (SMA), representing the market’s “normal” price.

  • Upper Band: Middle Band plus two standard deviations, signaling overbought conditions.

  • Lower Band: Middle Band minus two standard deviations, indicating oversold conditions.

The strategy buys when the price dips below the Lower Band, expecting a rebound to the Middle Band, and sells when the price climbs above the Upper Band, anticipating a drop. Trades close when the price hits the Middle Band, locking in profits. Buy trades use a 0.1-lot size with a 1000-pip stop loss and 500-pip take profit; sell trades mirror this setup. It’s like playing the market’s elastic nature, buying low and selling high. See below.

Code Implementation

Let’s dive into the MQL5 code like explorers chasing a market bounce, presenting each major section in full with a seamless narrative that flows like a river. We’ll explain every key function in detail, ensuring it’s clear for beginners, and quote variables (e.g., "upperBand") and functions (e.g., "OnInit()") for clarity. Our goal is to make the code as inviting as a sunny market day, guiding you from setup to trading with ease.

Setting the Foundation: Header, Includes, and Global Variables

We start by laying the groundwork, like stretching a rubber band before it snaps.

//+------------------------------------------------------------------+
//|                                                   B BANDS EA.mq5 |
//|                        Copyright 2025, Allan Munene Mutiiria      |
//|                            https://t.me/Forex_Algo_Trader         |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria"
#property link      "https://t.me/Forex_Algo_Trader"
#property version   "1.00"

#include <Trade/Trade.mqh>
CTrade obj_Trade;

int handleBB;
double upperBand[];
double middleBand[];
double lowerBand[];

datetime openTimeBuy = 0;
datetime openTimeSell = 0;

This opening act sets the stage. The header declares the EA as “B BANDS EA,” crafted by Allan in 2025, with a link to your Telegram channel and version 1.00. The #include <Trade/Trade.mqh> directive imports the MQL5 trade library, providing tools for executing trades. The "CTrade" class creates an object named "obj_Trade", your trading assistant for opening and closing positions.

Globally, we define:

  • "handleBB": An integer to store the Bollinger Bands indicator’s handle, like a key to access its data.

  • "upperBand[]", "middleBand[]", "lowerBand[]": Arrays to hold the Upper, Middle, and Lower Band values, ready to track market signals.

  • "openTimeBuy", "openTimeSell": Timestamps to ensure buy and sell trades only trigger once per candle, like a gatekeeper for trade timing.

These globals are like your trading toolkit, packed for the mean-reversion journey.

Preparing the Bands: OnInit Function

Next, we set up the Bollinger Bands indicator, like tuning the rubber band for the perfect snap.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   handleBB = iBands(_Symbol,_Period,20,0,2,PRICE_CLOSE);
   if (handleBB == INVALID_HANDLE) return (INIT_FAILED);
   Print("Handle BB = ",handleBB);
   
   ArraySetAsSeries(upperBand,true);
   ArraySetAsSeries(middleBand,true);
   ArraySetAsSeries(lowerBand,true);
   
   return(INIT_SUCCEEDED);
}

The "OnInit()" function is the EA’s pre-trade setup, running when you attach it to a chart. Let’s break down its key functions:

  • "iBands()": Creates the Bollinger Bands indicator for the current symbol ("_Symbol", e.g., EURUSD) and timeframe ("_Period", e.g., H1). It takes parameters: 20-period SMA, 0 shift, 2 standard deviations, and close price ("PRICE_CLOSE"). It returns a handle, stored in "handleBB", for accessing band data.

  • "Print()": Logs a message to the MetaTrader 5 journal, here showing the "handleBB" value for debugging, like a trail marker.

  • "ArraySetAsSeries()": Configures the "upperBand[]", "middleBand[]", and "lowerBand[]" arrays as time series, so index 0 holds the latest value, like sorting your market notes newest first.

  • "INVALID_HANDLE": A constant indicating a failed indicator creation. If "handleBB" equals this, the EA exits with INIT_FAILED.

If all goes well, it returns INIT_SUCCEEDED, signaling, “Bands are ready!” This function ensures the Bollinger Bands are set up to track market swings.

Cleaning Up: OnDeinit Function

When the trading session ends, this function tidies up.

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

The "OnDeinit()" function is the EA’s cleanup routine, called when you remove it from the chart. It’s empty here, like a trader who leaves no mess. No cleanup is needed since the Bollinger Bands indicator and trades are managed automatically by MetaTrader 5, keeping things lightweight.

Catching the Bounce: OnTick Function

Now we hit the EA’s core, where it trades mean-reversion on every price tick.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

   if (totalPos(POSITION_TYPE_BUY) > 0 && Bid >= middleBand[0]){
      closePos(POSITION_TYPE_BUY);
   }
   if (totalPos(POSITION_TYPE_SELL) > 0 && Ask <= middleBand[0]){
      closePos(POSITION_TYPE_SELL);
   }

   int currentbars = iBars(_Symbol,_Period);
   static int prevbars = 0;
   if (prevbars == currentbars) return;
   prevbars = currentbars;
   
   if (!CopyBuffer(handleBB,UPPER_BAND,0,2,upperBand)) return;
   if (!CopyBuffer(handleBB,BASE_LINE,0,2,middleBand)) return;
   if (!CopyBuffer(handleBB,LOWER_BAND,0,2,lowerBand)) return;

   if (totalPos(POSITION_TYPE_BUY)==0 && Ask <= lowerBand[0] &&
      openTimeBuy != iTime(_Symbol,_Period,0)
   ){
      double sl = Bid - 1000*_Point;
      double tp = Bid + 500*_Point;
      openTimeBuy = iTime(_Symbol,_Period,0);
      obj_Trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,Ask,sl,tp);
   }
   else if (totalPos(POSITION_TYPE_SELL)==0 && Bid >= upperBand[0]){
      double sl = Ask + 1000*_Point;
      double tp = Ask - 500*_Point;
      obj_Trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,0.1,Bid,sl,tp);
   }
}

The "OnTick()" function is the EA’s trading engine, running on every price tick to catch market bounces. It’s the heart of the strategy, so let’s unpack it with detail, explaining each major function:

  • "SymbolInfoDouble()": Retrieves real-time market data, grabbing the ask price ("SYMBOL_ASK") for buying and bid price ("SYMBOL_BID") for selling, stored in "Ask" and "Bid".

  • "NormalizeDouble()": Rounds prices (e.g., "Ask", "Bid") to the symbol’s decimal places ("_Digits", e.g., 5 for EURUSD), ensuring they’re trade-ready, like calibrating your trading tools.

  • "totalPos()": A custom function (defined below) that counts open positions of a given type ("POSITION_TYPE_BUY" or "POSITION_TYPE_SELL") for the current symbol. It’s used to check if buy or sell trades are open.

  • "closePos()": A custom function (defined below) that closes all positions of a given type, used here to close buy trades when "Bid" hits or exceeds "middleBand[0]" or sell trades when "Ask" hits or falls below "middleBand[0]".

  • "iBars()": Returns the number of bars (candles) on the chart, stored in "currentbars". This checks for new candles.

  • Bar Check Logic: A static "prevbars" variable tracks the previous bar count. If "prevbars" equals "currentbars", the EA skips to avoid reprocessing the same candle. When a new bar forms, "prevbars" updates.

  • "CopyBuffer()": Copies data from the Bollinger Bands indicator (via "handleBB") into arrays. It pulls two values (latest and previous) for the Upper Band ("UPPER_BAND"), Middle Band ("BASE_LINE"), and Lower Band ("LOWER_BAND") into "upperBand[]", "middleBand[]", and "lowerBand[]". If any fails, the EA exits to avoid bad data.

  • "iTime()": Gets the timestamp of the current candle (index 0), used to ensure trades only trigger once per candle by comparing with "openTimeBuy" or "openTimeSell".

  • Buy Signal Logic: If no buy positions exist ("totalPos(POSITION_TYPE_BUY)==0"), the ask price is at or below the Lower Band ("Ask <= lowerBand[0]"), and it’s a new candle ("openTimeBuy != iTime()", the EA opens a buy trade. It sets a stop loss ("sl") 1000 pips below "Bid", a take profit ("tp") 500 pips above, updates "openTimeBuy", and uses "obj_Trade.PositionOpen()" with 0.1 lots, "Ask" price, and the stop loss/take profit.

  • Sell Signal Logic: If no sell positions exist ("totalPos(POSITION_TYPE_SELL)==0") and the bid price is at or above the Upper Band ("Bid >= upperBand[0]"), the EA opens a sell trade. It sets a stop loss 1000 pips above "Ask", a take profit 500 pips below, and uses "obj_Trade.PositionOpen()" with 0.1 lots, "Bid" price, and the stop loss/take profit.

  • "PositionOpen()": A method of the "CTrade" class, opening trades with parameters like symbol ("_Symbol"), order type ("ORDER_TYPE_BUY" or "ORDER_TYPE_SELL"), lot size (0.1), price, stop loss, and take profit.

  • "_Point": A built-in variable for the symbol’s pip size, used to calculate stop loss and take profit distances.

This function flows from checking prices and positions to fetching band data, closing trades, and opening new ones, like a trader riding the market’s elastic swings.

Counting Positions: totalPos Function

This helper function counts open positions of a specific type.

int totalPos(ENUM_POSITION_TYPE pos_type){
   int totalType_pos = 0;
   for (int i = PositionsTotal()-1; i>=0; i--){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            if (PositionGetString(POSITION_SYMBOL)==_Symbol){
               if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
                  pos_type==POSITION_TYPE_BUY){
                  totalType_pos++;
               }
               else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
                  pos_type==POSITION_TYPE_SELL){
                  totalType_pos++;
               }
            }
         }
      }
   }
   return (totalType_pos);
}

The "totalPos()" function counts how many open positions match the input type ("pos_type", e.g., "POSITION_TYPE_BUY"). Key functions:

  • "PositionsTotal()": Returns the total number of open positions in the account.

  • "PositionGetTicket()": Retrieves the ticket number (unique ID) of a position at index i, stored in "ticket".

  • "PositionSelectByTicket()": Selects a position by its ticket for further queries, returning true if successful.

  • "PositionGetString()": Gets a string property of the selected position, here checking if the symbol ("POSITION_SYMBOL") matches the current symbol ("_Symbol").

  • "PositionGetInteger()": Gets an integer property, here checking the position type ("POSITION_TYPE") to match "pos_type".

The function loops through all positions, incrementing "totalType_pos" for matching buy or sell positions on the current symbol, and returns the count. It’s like a roll call for your trades.

Closing Positions: closePos Function

This function closes all positions of a specific type.

void closePos(ENUM_POSITION_TYPE pos_type){
   for (int i = PositionsTotal()-1; i>=0; i--){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            if (PositionGetString(POSITION_SYMBOL)==_Symbol){
               if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
                  pos_type==POSITION_TYPE_BUY){
                  obj_Trade.PositionClose(ticket);
               }
               else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
                  pos_type==POSITION_TYPE_SELL){
                  obj_Trade.PositionClose(ticket);
               }
            }
         }
      }
   }
}

The "closePos()" function closes all positions matching the input type ("pos_type"). It uses the same position-checking functions as "totalPos()", plus:

  • "PositionClose()": A method of the "CTrade" class, closing a position by its "ticket". It’s called for each matching buy or sell position on the current symbol.

The function loops through all positions, closing those that match the specified type, like clearing the deck when the market hits the Middle Band.

Putting It All Together

To launch this EA:

  1. Open MetaEditor in MetaTrader 5.

  2. Paste the code into a new Expert Advisor file.

  3. Compile (F5). If errors appear, double-check your copy-paste.

  4. Drag the EA onto your chart, enable AutoTrading, and watch for buy or sell trades.

  5. Trade smart—don’t bet your trading kit on one bounce!

Conclusion

The Bollinger Bands EA is your mean-reversion ally, using Bollinger Bands to catch market snap-backs. We’ve explored its MQL5 code with clear, detailed explanations, so you understand every move like a seasoned trader. Now you’re set to automate your trades and ride the market’s swings. Want to see it in action? Check our video tutorial on the website!

Disclaimer: Trading’s like bouncing on a trampoline—fun but risky. Losses can exceed deposits. Test on a demo account before going live.

Disclaimer: The ideas and strategies presented in this resource are solely those of the author and are intended for informational and educational purposes only. They do not constitute financial advice, and past performance is not indicative of future results. All materials, including but not limited to text, images, files, and any downloadable content, are protected by copyright and intellectual property laws and are the exclusive property of Forex Algo-Trader or its licensors. Reproduction, distribution, modification, or commercial use of these materials without prior written consent from Forex Algo-Trader is strictly prohibited and may result in legal action. Users are advised to exercise extreme caution, perform thorough independent research, and consult with qualified financial professionals before implementing any trading strategies or decisions based on this resource, as trading in financial markets involves significant risk of loss.

Recent Comments

Go to discussion to Comment or View other Comments

No comments yet. Be the first to comment!