Bollinger bands: can't find upper and lower.

 

for the life of me, I cannot accurately get the upper and lower bollinger bands. I apply my code and when referencing with the same input settings on the real-time chart, they don't align! The upper is in sync with the middle bollinger line (average).

Here's my code:

- CopyBuffer function should be handling this and I've read the documentation a thousand times. Can someone guide me on where I'm going wrong? I'm printing and drawing on the chart to get to the bottom of my error but I can't piece it together.

//+------------------------------------------------------------------+
//|                                                      ExpertAdvisor.mq5 |
//|                        Copyright 2021, MetaQuotes Ltd.            |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>

input int    InpBollingerPeriod    = 12;     // Bollinger Bands Period
input double InpBollingerDeviations= 2.00;      // Bollinger Bands Deviations
input bool   InpEnablePush         = false;  // Enable Push Notifications
datetime     lastCandleCloseTime   = 0;      // Time of the last closed candle
double       upperBand, lowerBand;
int          bandsHandle;                    // Handle for the Bollinger Bands indicator
CTrade       trade;
CSymbolInfo  symbolInfo;

//+------------------------------------------------------------------+
//| Expert initialization function                                  |
//+------------------------------------------------------------------+
int OnInit()
{
    // Initialize Bollinger Bands indicator
    bandsHandle = iBands(_Symbol, _Period, InpBollingerPeriod, 0, InpBollingerDeviations, PRICE_CLOSE);
    if(bandsHandle == INVALID_HANDLE)
    {
        Print("Failed to initialize Bollinger Bands indicator");
        return(INIT_FAILED);
    }
    symbolInfo.Name(_Symbol);
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Remove all graphical objects when the EA is removed from the chart
    ObjectsDeleteAll(0, 0, 0); // Correct usage without specific object name filter
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // Fetch the time of the last closed (completed) candle
    datetime currentCandleTime = iTime(_Symbol, _Period, 0);  // Current candle time
    datetime lastCandleTime = iTime(_Symbol, _Period, 1);     // Last closed candle time

    // Check if a new candle has formed since the last tick
    if (lastCandleCloseTime != lastCandleTime)
    {
        // Arrays to hold Bollinger Bands data for the last closed candle
        double upperBandData[1];
        double lowerBandData[1];

        // Fetch the latest data for the Bollinger Bands upper and lower bands
        if(CopyBuffer(bandsHandle, 0, 1, 1, upperBandData) <= 0) // Fetch the upper band value of the last closed candle
        {
            Print("Error fetching Bollinger Bands upper band data.");
            return;  // Exit if there's an error
        }

        if(CopyBuffer(bandsHandle, 2, 1, 1, lowerBandData) <= 0) // Fetch the lower band value of the last closed candle
        {
            Print("Error fetching Bollinger Bands lower band data.");
            return;  // Exit if there's an error
        }

        // Update the upper and lower bands with the most recent data
        upperBand = upperBandData[0];
        lowerBand = lowerBandData[0];

        // Determine the trade direction based on the last closed candlestick
        string tradeDirection = "no bias";
        if (iHigh(_Symbol, _Period, 1) > upperBand)
        {
            tradeDirection = "short bias";
            // Draw a down arrow at the upper band level
            ObjectCreate(0, "UpperBandArrow", OBJ_ARROW_DOWN, 0, lastCandleTime, upperBand);
            ObjectSetInteger(0, "UpperBandArrow", OBJPROP_COLOR, clrRed);
        }
        else if (iLow(_Symbol, _Period, 1) < lowerBand)
        {
            tradeDirection = "long bias";
            // Draw an up arrow at the lower band level
            ObjectCreate(0, "LowerBandArrow", OBJ_ARROW_UP, 0, lastCandleTime, lowerBand);
            ObjectSetInteger(0, "LowerBandArrow", OBJPROP_COLOR, clrBlue);
        }

        // Print the bias and relevant information for the last closed candle
        Print("Last closed candle - High: ", iHigh(_Symbol, _Period, 1), ", Low: ", iLow(_Symbol, _Period, 1), 
              ", U Band: ", upperBand, ", L Band: ", lowerBand, 
              ", Trade Direction: ", tradeDirection);

        // Update the last processed candle's close time
        lastCandleCloseTime = lastCandleTime;
    }
}



//+------------------------------------------------------------------+
//| Send alert and push notification if enabled                      |
//+------------------------------------------------------------------+
void SendAlert(string message)
{
    Alert(message);
    if(InpEnablePush)
    {
        SendNotification(message);
    }
}
//+------------------------------------------------------------------+
 
  // Fetch the latest data for the Bollinger Bands upper and lower bands
        if(CopyBuffer(bandsHandle, 0, 1, 1, upperBandData) <= 0) // Fetch the upper band value of the last closed candle

 What you are doing here is getting the information for the middle(baseline) band as that is buffer 0.
See iBands documentation in MQL5 reference  under Technical Indicators.

 
Argh that is so trivial and frustrating! Thank you Douglas, great spot!
Reason: