Bollinger Band Indicator Color Coded

 

Hello guys,

This is my first time using MQL 5. But the goal for this indictor is just checking the `current value vs the previous` to determine the color coding for the BB Lines ( Middle, Upper and Lower ). 

Currently the only way I was able to make progress was using the COPYBUFFER to get some values. But the value compared from the Arrays does not match what is displayed on chart. I verify the values in the debugger are being compared correctly. Any inputs or directions on this would be appreciated.

//+------------------------------------------------------------------+
//|                                                           BB.mq5 |
//|                             Copyright 2000-2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2000-2023, MetaQuotes Ltd."
#property link        "https://www.mql5.com"
#property description "Cloud Bollinger Bands"
#include <MovingAverages.mqh>
//---
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_plots   3

//------end ColorLine
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrGreen,clrRed
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  clrGreen,clrWhiteSmoke
#property indicator_type3   DRAW_COLOR_LINE
#property indicator_color3  clrWhiteSmoke,clrRed
#property indicator_label1  "Bands middle"
#property indicator_label2  "Bands upper"
#property indicator_label3  "Bands lower"
//--- input parametrs
input int     InpBandsPeriod=5;       // Period
input int     InpBandsShift=0;         // Shift
input double  InpBandsDeviations=2.0;  // Deviation
//--- global variables
int           ExtBandsPeriod,ExtBandsShift;
double        ExtBandsDeviations;
int           ExtPlotBegin=0;
//--- indicator buffer
double        ExtMLBuffer[];
double        ExtTLBuffer[];
double        ExtBLBuffer[];
double        ExtStdDevBuffer[];
double        BBMiddle[],BBUp[],BBDown[];   // dynamic arrays for numerical values of Bollinger Bands
//--- indicator color buffers 
double         ColorBuffer1[];
double         ColorBuffer2[];
double         ColorBuffer3[];

int BolBandsHandle;                // Bolinger Bands handle
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {

   //--- check for input values
   if(InpBandsPeriod<2)
     {
      ExtBandsPeriod=5;
      PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.",InpBandsPeriod,ExtBandsPeriod);
     }
   else
      ExtBandsPeriod=InpBandsPeriod;
   if(InpBandsShift<0)
     {
      ExtBandsShift=0;
      PrintFormat("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.",InpBandsShift,ExtBandsShift);
     }
   else
      ExtBandsShift=InpBandsShift;
   if(InpBandsDeviations==0.0)
     {
      ExtBandsDeviations=2.0;
      PrintFormat("Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.",InpBandsDeviations,ExtBandsDeviations);
     }
   else
      ExtBandsDeviations=InpBandsDeviations;

   //--- define buffers
   //SetIndexBuffer(0,ExtMLBuffer);
   //SetIndexBuffer(1,ExtTLBuffer);
   //SetIndexBuffer(2,ExtBLBuffer);
   //SetIndexBuffer(3,ExtStdDevBuffer,INDICATOR_CALCULATIONS);
   
   //--- set index labels
    //PlotIndexSetString(0,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Middle");
    //PlotIndexSetString(1,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Upper");
    //PlotIndexSetString(2,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Lower");

   //--- indicator name
   IndicatorSetString(INDICATOR_SHORTNAME,"Cloud Bollinger Bands");

   //--- indexes draw begin settings
   //ExtPlotBegin=ExtBandsPeriod-1;
   //PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtBandsPeriod);
   //PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtBandsPeriod);
   //PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtBandsPeriod);

   //--- indexes shift settings
   //PlotIndexSetInteger(0,PLOT_SHIFT,ExtBandsShift);
   //PlotIndexSetInteger(1,PLOT_SHIFT,ExtBandsShift);
   //PlotIndexSetInteger(2,PLOT_SHIFT,ExtBandsShift);
   
   //--- define buffers
   SetIndexBuffer(0,ExtMLBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ColorBuffer1,INDICATOR_COLOR_INDEX); 
   Print("Indicator buffer after after SetIndexBuffer() is a timeseries = ",
         ArrayGetAsSeries(ExtBLBuffer));
   
   PlotIndexSetString(0,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Middle");
   
   SetIndexBuffer(2,ExtTLBuffer,INDICATOR_DATA); 
   SetIndexBuffer(3,ColorBuffer2,INDICATOR_COLOR_INDEX);
    
   SetIndexBuffer(4,ExtBLBuffer,INDICATOR_DATA);   
   SetIndexBuffer(5,ColorBuffer3,INDICATOR_COLOR_INDEX); 
   
   SetIndexBuffer(6,ExtStdDevBuffer,INDICATOR_CALCULATIONS); //Not rendered
   
   //--- get handle of the Bollinger Bands and DEMA indicators
   BolBandsHandle=iBands(Symbol(),PERIOD_CURRENT,ExtBandsPeriod,ExtBandsShift,ExtBandsDeviations,PRICE_CLOSE);

   ArraySetAsSeries(BBMiddle,false);
   Print("Indicator buffer after ArraySetAsSeries (BBMiddle, true); is a timeseries = ", 
         ArrayGetAsSeries(BBMiddle));
         
   ArraySetAsSeries(BBUp,true);
   ArraySetAsSeries(BBDown,true);
   
   //--- number of digits of indicator value
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
  }

//+------------------------------------------------------------------+
//| Bollinger Bands                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
  
   int epb = ExtPlotBegin;
   if(rates_total<ExtPlotBegin)
      return(0);
   
   //--- indexes draw begin settings, when we've recieved previous begin
   int ebp1= ExtBandsPeriod+begin;
   if(ExtPlotBegin!=ExtBandsPeriod+begin)
     {
      ExtPlotBegin=ExtBandsPeriod+begin;
      PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPlotBegin);
      PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtPlotBegin);
      PlotIndexSetInteger(4,PLOT_DRAW_BEGIN,ExtPlotBegin);
     }
   
   //--- starting calculation
   int pos;
   if(prev_calculated>1)
      pos=prev_calculated-1;
   else
      pos=0;
      
   //--- check data
   int calculated=BarsCalculated(BolBandsHandle);
   if(calculated<rates_total) {
      Print("Not all data of BolBandsHandle is calculated (",calculated," bars). Error ",GetLastError());
      return(0);
   }
   
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<=0) to_copy=rates_total;
   else
      {
         to_copy=rates_total-prev_calculated;
         //--- last value is always copied
         to_copy++;
      }  
      
   if(CopyBuffer(BolBandsHandle,0,0,to_copy,BBMiddle)<0 || CopyBuffer(BolBandsHandle,1,0,to_copy,BBUp)<0
      || CopyBuffer(BolBandsHandle,2,0,to_copy,BBDown)<0)   
      return(0);  
      
   //--- main cycle
   for(int i=pos; i<rates_total && !IsStopped(); i++) {
   
      //--- middle line
      ExtMLBuffer[i] = SimpleMA(i,ExtBandsPeriod,price);
      
      //--- calculate and write down StdDev
      ExtStdDevBuffer[i] = StdDev_Func(i,price,ExtMLBuffer,ExtBandsPeriod);
      
      //--- upper line
      ExtTLBuffer[i] = ExtMLBuffer[i]+ExtBandsDeviations*ExtStdDevBuffer[i];
      
      //--- lower line
      ExtBLBuffer[i] = ExtMLBuffer[i]-ExtBandsDeviations*ExtStdDevBuffer[i];
      
      double mlCurr = BBMiddle[i];
      double mlPrev = BBMiddle[i+1];
      Print("BBMiddle Values: ", BBMiddle.Size());
      Print("i: ", i);
      Print("Curr: ",mlCurr);
      Print("Prev: ", mlPrev);
      bool v = mlCurr > mlPrev;
      Print("Valid: ", v);
      ColorBuffer1[i]=getIndexOfColor(mlCurr,mlPrev);
      double upCurr = BBUp[i];
      double upPrev = BBUp[i+1] ;        
      ColorBuffer2[i]=getIndexOfColor(upCurr,upPrev);
      double downCurr = BBDown[i];
      double downPrev = BBDown[i+1];       
      ColorBuffer3[i]=getIndexOfColor(downCurr,downPrev);         
      
     }
   
   //--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }      

int getIndexOfColor(double curr, double prev) {
   if(curr > prev) {
      return 0;
   } else {
      return 1;
   }
}
  
//+------------------------------------------------------------------+
//| Calculate Standard Deviation                                     |
//+------------------------------------------------------------------+
double StdDev_Func(const int position,const double &price[],const double &ma_price[],const int period)
  {
   double std_dev=0.0;
//--- calcualte StdDev
   if(position>=period)
     {
      for(int i=0; i<period; i++)
         std_dev+=MathPow(price[position-i]-ma_price[position],2.0);
      std_dev=MathSqrt(std_dev/period);
     }
//--- return calculated value
   return(std_dev);
  }
//+------------------------------------------------------------------+

Another issue I saw was debugging/testing. Array out of range (195,33)rror message, I used `to_copy` as the array size.

//--- check data
   int calculated=BarsCalculated(BolBandsHandle);
   if(calculated<rates_total) {
      Print("Not all data of BolBandsHandle is calculated (",calculated," bars). Error ",GetLastError());
      return(0);
   }
   
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<=0) to_copy=rates_total;
   else
      {
         to_copy=rates_total-prev_calculated;
         //--- last value is always copied
         to_copy++;
      }  
      
   if(CopyBuffer(BolBandsHandle,0,0,to_copy,BBMiddle)<0 || CopyBuffer(BolBandsHandle,1,0,to_copy,BBUp)<0
      || CopyBuffer(BolBandsHandle,2,0,to_copy,BBDown)<0)   
      return(0);  

Again thanks to the community for all the knowledge sharing.

Files:
BBCloud.mq5  9 kb
 
Added some screenshots showing what it looks like in Meta5 vs my working solution using ThinkScripts in ThinkOrSwim.
Files:
Meta5_BB.png  26 kb
TOS_BB.png  113 kb
 
I've been working on something like this for a while and cannot figure it out too. This will make things easier to see the direction of the bands.
 
Tony N #:
Added some screenshots showing what it looks like in Meta5 vs my working solution using ThinkScripts in ThinkOrSwim.

There was so much wasteful processing and mistakes that I had to reprogram.

//+------------------------------------------------------------------+
//|                                                        BB v2.mq5 |
//|                                                    Naguisa Unada |
//|                    https://www.mql5.com/en/users/unadajapon/news |
//+------------------------------------------------------------------+
#property copyright "Naguisa Unada"
#property link      "https://www.mql5.com/en/users/unadajapon/news"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   3
//--- plot ExtML_
#property indicator_label1  "ExtML_"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrRed,clrLimeGreen
#property indicator_style1  STYLE_DASH
#property indicator_width1  1
//--- plot ExtTL_
#property indicator_label2  "ExtTL_"
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  clrLimeGreen,clrWhite
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot ExtBL_
#property indicator_label3  "ExtBL_"
#property indicator_type3   DRAW_COLOR_LINE
#property indicator_color3  clrRed,clrWhite
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- input parameters
input int      InpBandsPeriod      = 20;    // Period
input int      InpBandsShift       = 0;     // Shift
input double   InpBandsDeviations  = 2.0;   // Deviation
//--- indicator buffers
double         ExtML_Buffer[];
double         ExtML_Colors[];
double         ExtTL_Buffer[];
double         ExtTL_Colors[];
double         ExtBL_Buffer[];
double         ExtBL_Colors[];

int            BolBandsHandle;             // Bolinger Bands handle
int            ExtBandsPeriod, ExtBandsShift;
double         ExtBandsDeviations;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- indicator buffers mapping
   SetIndexBuffer(0, ExtML_Buffer, INDICATOR_DATA);
   SetIndexBuffer(1, ExtML_Colors, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, ExtTL_Buffer, INDICATOR_DATA);
   SetIndexBuffer(3, ExtTL_Colors, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4, ExtBL_Buffer, INDICATOR_DATA);
   SetIndexBuffer(5, ExtBL_Colors, INDICATOR_COLOR_INDEX);

   //--- check for input values
   if(InpBandsPeriod < 2)
   {
      ExtBandsPeriod = 5;
      PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.", InpBandsPeriod, ExtBandsPeriod);
   }
   else
      ExtBandsPeriod = InpBandsPeriod;

   if(InpBandsShift < 0)
   {
      ExtBandsShift = 0;
      PrintFormat("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.", InpBandsShift, ExtBandsShift);
   }
   else
      ExtBandsShift = InpBandsShift;

   if(InpBandsDeviations == 0.0)
   {
      ExtBandsDeviations = 2.0;
      PrintFormat("Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.", InpBandsDeviations, ExtBandsDeviations);
   }
   else
      ExtBandsDeviations = InpBandsDeviations;

   IndicatorSetString(INDICATOR_SHORTNAME, "Cloud Bollinger Bands");
   BolBandsHandle = iBands(Symbol(), PERIOD_CURRENT, ExtBandsPeriod, ExtBandsShift, ExtBandsDeviations, PRICE_CLOSE);
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1);
   //---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   //---
   int i, limit, to_copy;

   if (prev_calculated < 0)
      return (-1);
   if (prev_calculated == 0)
   {
      limit = ExtBandsPeriod;
      to_copy = rates_total;
   }
   else
   {
      limit = prev_calculated - 1;
      to_copy = rates_total - prev_calculated + 1;
   }

   if(CopyBuffer(BolBandsHandle, 0, 0, to_copy, ExtML_Buffer) < 0 ||
      CopyBuffer(BolBandsHandle, 1, 0, to_copy, ExtTL_Buffer) < 0 ||
      CopyBuffer(BolBandsHandle, 2, 0, to_copy, ExtBL_Buffer) < 0)
      return(0);

   for (i = limit; i < rates_total && !IsStopped(); i++)
   {
      if (ExtML_Buffer[i] < ExtML_Buffer[i - 1])
         ExtML_Colors[i] = 0;
      else
         ExtML_Colors[i] = 1;

      if (ExtTL_Buffer[i] > ExtTL_Buffer[i - 1])
         ExtTL_Colors[i] = 0;
      else
         ExtTL_Colors[i] = 1;

      if (ExtBL_Buffer[i] < ExtBL_Buffer[i - 1])
         ExtBL_Colors[i] = 0;
      else
         ExtBL_Colors[i] = 1;
   }
   //--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
 
Nagisa Unada #:

There was so much wasteful processing and mistakes that I had to reprogram.

Thank you Nagisa Unada for the quick response and solution. This is pretty Awesome! Hopefully I can learn from your approach on the next indicator. How can I give you kudos?