Indicator buffers fill with strange values

 

hi everyone

i have an issue with my indicator, the arrow buffer is filling with some strange values that draws wrong signals on charts

here is the issue picture


and here is the code:

#property strict
#property indicator_chart_window
#property indicator_buffers   5
#property indicator_plots     2

#property indicator_type1     DRAW_ARROW
#property indicator_style1    STYLE_SOLID
#property indicator_color1    clrLime
#property indicator_width1    2
#property indicator_label1    "Buy Signal"

#property indicator_type2     DRAW_ARROW
#property indicator_style2    STYLE_SOLID
#property indicator_color2    clrTomato
#property indicator_width2    2
#property indicator_label2    "Sell Signal"

#define   EMPTY               0.0

// Indicator input parameters
input double               SellPercent                   =  100.0;                                       // Sell Low Percent (%)
input double               BuyPercent                    =  0.0;                                         // Buy High Percent (%)

input int                  BBPeriod                      =  20;                                          // Period
input double               BBDeviation                   =  2.0;                                         // Deviations
input ENUM_APPLIED_PRICE   BBPrice                       =  PRICE_CLOSE;                                 // Price
input int                  BBShift                       =  0;                                           // Shift

input bool                 TimeFilter                    =  true;                                        // Time Filter (on/off)
input string               TimeFilterStart               =  "01:00";                                     // Time Filter Start (Broker Time)
input string               TimeFilterEnd                 =  "22:00";                                     // Time Filter End (Broker Time)

// Indicator variables
string   Prefix               =  "Ind1_";
string   IndName              =  "Ind1";
int      Space                =  20;
int      MaxPeriod            =  0;
bool     ValidBuy             =  false;
double   BuyPrice             =  0.0;
double   BuySL                =  0.0;
bool     ValidSell            =  false;
double   SellPrice            =  0.0;
double   SellSL               =  0.0;

double   BuyBuffer[];
double   SellBuffer[];

double   BBUpper[];
double   BBMiddle[];
double   BBLower[];
int      BBHandle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   IndicatorSetString(INDICATOR_SHORTNAME, IndName);
   IndicatorSetInteger(INDICATOR_DIGITS, (int) SymbolInfoInteger(Symbol(), SYMBOL_DIGITS)+ 1);

   MaxPeriod   =  BBPeriod;

   int   bufferIndex    =  0;
   SetIndexBuffer(bufferIndex, BuyBuffer, INDICATOR_DATA);
   PlotIndexSetInteger(bufferIndex, PLOT_ARROW, 233);
   PlotIndexSetInteger(bufferIndex, PLOT_ARROW_SHIFT, Space);
   PlotIndexSetInteger(bufferIndex, PLOT_DRAW_BEGIN, MaxPeriod);
   PlotIndexSetDouble(bufferIndex, PLOT_EMPTY_VALUE, EMPTY);

   bufferIndex++;
   SetIndexBuffer(bufferIndex, SellBuffer, INDICATOR_DATA);
   PlotIndexSetInteger(bufferIndex, PLOT_ARROW, 234);
   PlotIndexSetInteger(bufferIndex, PLOT_ARROW_SHIFT, -Space);
   PlotIndexSetInteger(bufferIndex, PLOT_DRAW_BEGIN, MaxPeriod);
   PlotIndexSetDouble(bufferIndex, PLOT_EMPTY_VALUE, EMPTY);

   ArraySetAsSeries(BuyBuffer, true);
   ArraySetAsSeries(SellBuffer, true);

   ArrayInitialize(BuyBuffer, EMPTY);
   ArrayInitialize(SellBuffer, EMPTY);

   BBHandle    =  iBands(Symbol(), Period(), BBPeriod, BBShift, BBDeviation, BBPrice);
   if(BBHandle < 0)
      {
       Alert("Error Creating Handles for Bollinger Bands indicator - error: ", GetLastError(), "!!");
       return(INIT_FAILED);
      }

   bufferIndex++;
   SetIndexBuffer(bufferIndex, BBUpper, INDICATOR_CALCULATIONS);
   bufferIndex++;
   SetIndexBuffer(bufferIndex, BBMiddle, INDICATOR_CALCULATIONS);
   bufferIndex++;
   SetIndexBuffer(bufferIndex, BBLower, INDICATOR_CALCULATIONS);

   ArraySetAsSeries(BBUpper, true);
   ArraySetAsSeries(BBMiddle, true);
   ArraySetAsSeries(BBLower, true);

   ArrayInitialize(BBUpper, EMPTY);
   ArrayInitialize(BBMiddle, EMPTY);
   ArrayInitialize(BBLower, EMPTY);

//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(BBHandle);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   if(IsStopped())
      return(0);

   if(rates_total <= MaxPeriod)
      return(0);

   if(BarsCalculated(BBHandle) < rates_total)
      return(0);

   if(prev_calculated > rates_total || prev_calculated <= 0)
     {
      ArrayInitialize(BuyBuffer, EMPTY);
      ArrayInitialize(SellBuffer, EMPTY);
      ArrayInitialize(BBUpper, EMPTY);
      ArrayInitialize(BBMiddle, EMPTY);
      ArrayInitialize(BBLower, EMPTY);
     }
   
   int   count          =  0;
   
   if(prev_calculated <= 0)
      count             =  rates_total- MaxPeriod;

   else
      count             =  rates_total- prev_calculated+ 1;

   int   upperCount     =  CopyBuffer(BBHandle, 1, 0, count, BBUpper);
        
   if(upperCount <= 0)
      return(0);

   int   middleCount    =  CopyBuffer(BBHandle, 0, 0, count, BBMiddle);
       
   if(middleCount <= 0)
      return(0);

   int   lowerCount     =  CopyBuffer(BBHandle, 2, 0, count, BBLower);
        
   if(lowerCount <= 0)
      return(0);

   for(int i=count-1; i>=0 && !IsStopped(); i--)
     {
      if(BBUpper[i] <= 0.0 || BBUpper[i] == EMPTY_VALUE || BBMiddle[i] <= 0.0 || BBMiddle[i] == EMPTY_VALUE || BBLower[i] <= 0.0 || BBLower[i] == EMPTY_VALUE)
         return(0);

      // Signal invalidation
      if(ValidBuy && BuySL != 0.0 && iLow(Symbol(), PERIOD_CURRENT, i) < BuySL)
        {
         ValidBuy                =  false;
         BuySL                   =  0.0;
         BuyPrice                =  0.0;
        }

      if(ValidSell && SellSL != 0.0 && iHigh(Symbol(), PERIOD_CURRENT, i) > SellSL)
        {
         ValidSell               =  false;
         SellSL                  =  0.0;
         SellPrice               =  0.0;
        }

      // Step 1 buy candle
      if(i != 0 && !ValidBuy && Step1(0, i))
        {
         ValidBuy       =  true;
         BuyPrice       =  iHigh(Symbol(), PERIOD_CURRENT, i);
         BuySL          =  iLow(Symbol(), PERIOD_CURRENT, i);
        }

      // Step 1 sell candle
      if(i != 0 && !ValidSell && Step1(1, i))
        {
         ValidSell      =  true;
         SellPrice      =  iLow(Symbol(), PERIOD_CURRENT, i);
         SellSL         =  iHigh(Symbol(), PERIOD_CURRENT, i);
        }
      
      // Signals
      if(ValidBuy && BuyPrice != 0.0 && iHigh(Symbol(), PERIOD_CURRENT, i) > BuyPrice)
        {
         BuyBuffer[i]            =  EMPTY;

         if(!OnSession(i))
           {
            ValidBuy             =  false;
            BuySL                =  0.0;
            BuyPrice             =  0.0;
           }
         
         if(ValidBuy)
           {
            BuyBuffer[i]         =  iLow(Symbol(), PERIOD_CURRENT, i);
            ValidBuy             =  false;
            BuySL                =  0.0;
            BuyPrice             =  0.0;
           }
        }
      
      if(ValidSell && SellPrice != 0.0 && iLow(Symbol(), PERIOD_CURRENT, i) < SellPrice)
        {
         SellBuffer[i]           =  EMPTY;

         if(!OnSession(i))
           {
            ValidSell            =  false;
            SellSL               =  0.0;
            SellPrice            =  0.0;
           }
         
         if(ValidSell)
           {
            SellBuffer[i]        =  iHigh(Symbol(), PERIOD_CURRENT, i);
            ValidSell            =  false;
            SellSL               =  0.0;
            SellPrice            =  0.0;
           }
        }
     }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Step 1                                                           |
//+------------------------------------------------------------------+
bool Step1(int type, int bar)
   {
    double  bandHeight        =  BBUpper[bar]- BBLower[bar];
    double  step1BuyMax       =  BBLower[bar]+ (BuyPercent* bandHeight/ 100.0);
    double  step1SellMin      =  BBLower[bar]+ (SellPercent* bandHeight/ 100.0);
    
    if(type == 0)
      {
       if(iHigh(Symbol(), PERIOD_CURRENT, bar) < step1BuyMax)
          return true;
      }
    
    if(type == 1)
      {
       if(iLow(Symbol(), PERIOD_CURRENT, bar) > step1SellMin)
          return true;
      }
    
    return false;
   }

//+------------------------------------------------------------------+
//| Time Filter                                                      |
//+------------------------------------------------------------------+
bool OnSession(int bar)
   {
    if(!TimeFilter)
       return true;
    
    int  startHour      =  (int) StringToInteger(StringSubstr(TimeFilterStart, 0, 2));
    int  startMin       =  (int) StringToInteger(StringSubstr(TimeFilterStart, 3, 2));
    int  endHour        =  (int) StringToInteger(StringSubstr(TimeFilterEnd, 0, 2));
    int  endMin         =  (int) StringToInteger(StringSubstr(TimeFilterEnd, 3, 2));

    MqlDateTime   candleTime;
    TimeToStruct(iTime(Symbol(), PERIOD_CURRENT, bar), candleTime);
    
    int  brokerHour     =  candleTime.hour;
    int  brokerMin      =  candleTime.min;
    
    int  startAll       =  startHour* 60+ startMin;
    int  endAll         =  endHour* 60+ endMin;
    int  passedAll      =  brokerHour* 60+ brokerMin;
    
    if(passedAll >= startAll && passedAll < endAll)
       return  true;
    
    return false;
   }


thanks in advance

 

You should initialize every arrow buffer to EMPTY_VALUE per iteration.

 for(int i=count-1; i>=0 && !IsStopped(); i--)
     {
        SellBuffer[i]=EMPTY_VALUE;
        BuyBuffer[i]=EMPTY_VALUE;
//...
 
Yashar Seyyedin #:

You should initialize every arrow buffer to EMPTY_VALUE per iteration.

thanks Yashar for replying


and about initialization buffers, i afraid not!

because the signal is sent by breaking the high/low of the step 1 candle which happened some candles ago, this step 1 confirmation is checked with Boolean flags (ValidBuy // ValidSell)

// Step 1 buy candle
      if(i != 0 && !ValidBuy && Step1(0, i))
        {
         ValidBuy       =  true;
         BuyPrice       =  iHigh(Symbol(), PERIOD_CURRENT, i);
         BuySL          =  iLow(Symbol(), PERIOD_CURRENT, i);
        }

      // Step 1 sell candle
      if(i != 0 && !ValidSell && Step1(1, i))
        {
         ValidSell      =  true;
         SellPrice      =  iLow(Symbol(), PERIOD_CURRENT, i);
         SellSL         =  iHigh(Symbol(), PERIOD_CURRENT, i);
        }



once sending the signal, it turns those flags to false and searches for new cycles

if(ValidBuy)
           {
            BuyBuffer[i]         =  iLow(Symbol(), PERIOD_CURRENT, i);
            ValidBuy             =  false;
            BuySL                =  0.0;
            BuyPrice             =  0.0;
           }


if(ValidSell)
           {
            SellBuffer[i]        =  iHigh(Symbol(), PERIOD_CURRENT, i);
            ValidSell            =  false;
            SellSL               =  0.0;
            SellPrice            =  0.0;
           }


if a signal is correctly sent and the arrow is printed on the currently open candle, then the Boolean changes to false but

on next tick, it again sets the buffers to empty value, and removes the arrow, and the signal disappears!!

 
Yashar Seyyedin #:

You should initialize every arrow buffer to EMPTY_VALUE per iteration.

apart from this special case i explained above


out of curiosity, why should we initialize the buffers to empty value?! (However i do it myself too!)


every time a new bar is opened, the indicator increases the buffers by one cell, and it allocates zero to it, while i have set that 0 value to indicator empty value

#define   EMPTY               0.0
   PlotIndexSetDouble(bufferIndex, PLOT_EMPTY_VALUE, EMPTY);


so even with not initializing arrow buffers to empty values, it should draw nothing, not strange arrows on strange places!!

 
Mohammadmahmood Pirayeh #:

once sending the signal, it turns those flags to false and searches for new cycles

If that is the case you have to define buffers for ValidBuy and ValidSell and reinitialize them to the previous bar value at every iteration...

 for(int i=count-1; i>=0 && !IsStopped(); i--)
     {
        SellBuffer[i]=EMPTY_VALUE;
        BuyBuffer[i]=EMPTY_VALUE;
        ValidBuy[i] = ValidBuy[i+1];
        ValidSell[i] = ValidSell[i+1];
...
 
Mohammadmahmood Pirayeh #:

out of curiosity, why should we initialize the buffers to empty value?! (However i do it myself too!)

Use of uninitialized variables is prohibited as you cannot know what value they are holding at start. The piece of code to initialize those values does not run on every bar during execution. Other than that the value may change several times during the current bar evolution. All these can cause unwanted data to be stored.

 
Yashar Seyyedin #:

If that is the case you have to define buffers for ValidBuy and ValidSell and reinitialize them to the previous bar value at every iteration...

great idea! i will check

thank you