'ExtUpperBuffer being set to 0.0 on new bar even though hard coded in If Else statement in OnCalc. Set to EMPTY_VALUE in Oninit

There are 2 buffers behaving the same way so to keep simple just mentioning ExtUpperBuffer and when I drop this onto the chart the datawindow/print values are as expected with the hard coded values im using for troubleshooting purposes. On a new bar the data window and print are showing 0.00 and 0.0 respectively, even though set to EMPTY_VALUE in the Oninit and either 420000 or 220000 in the OnCalc If Else statement. Trying to understand the HOW/WHY for this in MQL5. Thanks in advance.

//+------------------------------------------------------------------+
//|                                                OBV & Fractal.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#property indicator_separate_window

#property indicator_buffers 3
#property indicator_plots   3

//--- plot OBV
#property indicator_label1  "OBV"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2


// Fractals
#property indicator_type2   DRAW_ARROW
#property indicator_type3   DRAW_ARROW
#property indicator_color2  clrGreen
#property indicator_color3  clrRed
#property indicator_label2  "Fractal Up"
#property indicator_label3  "Fractal Down"


//--- input parameters
input ENUM_APPLIED_VOLUME     InpVolumeType=VOLUME_TICK; // Volumes

//--- indicator buffers
double OBVBuffer[];

double ExtUpperBuffer[]; // Up Fractal
double ExtLowerBuffer[]; // Down Fractal

//--- 10 pixels upper from high price for Fractals
int    ExtArrowShift = -10;

//---OBV Handle
int    obv_handle = INVALID_HANDLE;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
    int size = ArraySize(OBVBuffer);
    
//--- indicator buffers mapping
   SetIndexBuffer(0, OBVBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, ExtUpperBuffer, INDICATOR_DATA); // Up Fractal. Maps to #property indicator_type2
   SetIndexBuffer(2, ExtLowerBuffer, INDICATOR_DATA); // Down Fractal. Maps to #property indicator_type3

//--- set indicator digits
   IndicatorSetInteger(INDICATOR_DIGITS, 2); 

// Taken from Fractals. // 
//--- sets first bar from what index will be drawn 
   PlotIndexSetInteger(1,PLOT_ARROW,217);
   PlotIndexSetInteger(2,PLOT_ARROW,218);
//--- arrow shifts when drawing
   //PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,ExtArrowShift);
   //PlotIndexSetInteger(2,PLOT_ARROW_SHIFT,-ExtArrowShift);
//--- sets drawing line empty value--
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);

//---ArraySeries Setting
   ArraySetAsSeries(OBVBuffer, true);
   ArraySetAsSeries(ExtUpperBuffer, true);
   ArraySetAsSeries(ExtLowerBuffer, true);
   
//---Create Indicator
   obv_handle = iOBV(Symbol(), Period(), InpVolumeType);
   
//---Check if Indicator was Created
   if(obv_handle == INVALID_HANDLE)
     {
      printf("Failed To Create OBV Indicator: [%d]", GetLastError());
      return INIT_FAILED;
     }
     
//---Set Indicator Name for Data WIndow
   IndicatorSetString(INDICATOR_SHORTNAME, "OBV ");
   
//---
   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[])
  {
  
//---Array Set To Series True
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(open, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   ArraySetAsSeries(tick_volume, true);
   ArraySetAsSeries(volume, true);
   ArraySetAsSeries(spread, true);
   
//---Refresh Indicators // From SMA v2 Framework, updated for OBV.
   int calculatedBars = BarsCalculated(obv_handle);
   
//Check If Indicators are refreshed
   if(calculatedBars < 2) // For SMA was using InpPeriod which was 14 for the SMA, OBV requires 2.
      return prev_calculated; 
      
//---Create Control Value to Stop recalculation of Closed candles
   int limit;
   
   if(prev_calculated <= 3){}
      //limit = rates_total - (3); // These were taken from the SMA which uses an InpPeriod. Using 2 for OBV "input"
   else
      limit = rates_total - prev_calculated;
      
//---Assign Created Indicator Values to our Plotting Buffer
   CopyBuffer(obv_handle, 0, 0, limit + 1, OBVBuffer);

//---End of OBV If statements etc. 

// If statements from Fractals.    
   if(rates_total<5) // Could change this to be EMA input. Leaving 2 for now. // Fractals wants 5. Changing from 2 to 5. 
      return(prev_calculated);

   if (rates_total==prev_calculated)   
      return (rates_total); 
       
   int start; // Variable from Fractals
   
//--- clean up arrays and sets start variable // Taken From Fractals Code
   if(prev_calculated<7)
     {
      start=2;
      ArrayInitialize(ExtUpperBuffer,EMPTY_VALUE);
      ArrayInitialize(ExtLowerBuffer,EMPTY_VALUE);
     }
   else
      start=rates_total - 5; 
      
// Dropping in Fractals IF statements here //

//--- main cycle of calculations // Changing counter from i to j
//   for(int j=start; j<rates_total-3 && !IsStopped(); j++)

int fractalUpCounter = 0;
int fractalDnCounter = 0;


// TODO: FIX Fractals going to 0 on the new bar. 

   for(int j = start; j < ((rates_total-prev_calculated)-3) && !IsStopped(); j++) 
   {
      // if (OBVBuffer[j] == 0)
      if (ExtLowerBuffer[j-1] == 0 || ExtUpperBuffer[j-1] == 0){
         Print("I BROKE!!");
         break;
      }
      
      //--- Lower Fractal
      if(OBVBuffer[j]>OBVBuffer[j+1] && OBVBuffer[j]>OBVBuffer[j+2] && OBVBuffer[j]>=OBVBuffer[j-1] && OBVBuffer[j]>=OBVBuffer[j-2]){ // For OBV Div swap high[i] with ExtOBVBuffer[i]
         if(OBVBuffer[j] != 0){
            //ExtLowerBuffer[j] = OBVBuffer[j];
            ExtLowerBuffer[j] = 421000;
            //fractalDnCounter++;
         }
         //else{
         //  ExtLowerBuffer[j]=EMPTY_VALUE;
         //}
      }
      else{
         ExtLowerBuffer[j]=221000;
      }

      //--- Upper Fractal
      if(OBVBuffer[j]<OBVBuffer[j+1] && OBVBuffer[j]<OBVBuffer[j+2] && OBVBuffer[j]<=OBVBuffer[j-1] && OBVBuffer[j]<=OBVBuffer[j-2]){
         if(OBVBuffer[j] != 0){
            //ExtUpperBuffer[j]=OBVBuffer[j];
            ExtUpperBuffer[j] = 420000;
            //fractalUpCounter++;
         }
         //else{
         //   ExtUpperBuffer[j]=EMPTY_VALUE;
         //}
      }
      else{
         ExtUpperBuffer[j]=220000;    
      }  
  
   //Print(" j: " + j + " OBVBuffer value: " + OBVBuffer[j] + " prev_calc: " + prev_calculated + " rates_total: " + rates_total);
   //Print(" ExtUpperBuffer value: " + ExtUpperBuffer[j] + " ExtLowerBuffer value: " + ExtLowerBuffer[j]);
   }
   //Print("********* I AM DONE *************");
   
   
   int length = sizeof(ExtUpperBuffer)/sizeof(ExtUpperBuffer[0]);

   Print("ExtUpperBuffer: 0 " + ExtUpperBuffer[0] + " OBVBuffer: " + OBVBuffer[0]);
   Print("ExtUpperBuffer: 1 " + ExtUpperBuffer[1] + " OBVBuffer: " + OBVBuffer[1]);
   Print("ExtUpperBuffer: 2 " + ExtUpperBuffer[2] + " OBVBuffer: " + OBVBuffer[2]);
   Print("ExtUpperBuffer: 3 " + ExtUpperBuffer[3] + " OBVBuffer: " + OBVBuffer[3]);
   Print("ExtUpperBuffer: 4 " + ExtUpperBuffer[4] + " OBVBuffer: " + OBVBuffer[4]);
   Print("ExtUpperBuffer: 5 " + ExtUpperBuffer[5] + " OBVBuffer: " + OBVBuffer[5]);
   Print("ExtUpperBuffer: 6 " + ExtUpperBuffer[6] + " OBVBuffer: " + OBVBuffer[6]);
   Print("ExtUpperBuffer: 7 " + ExtUpperBuffer[7] + " OBVBuffer: " + OBVBuffer[7]);
   //Print("Start: " + start);
         
   for (int i = 0; i < length; i++) {
      //Print("OBVBuffer: " + OBVBuffer[i]);
      
      
   
   }

/*   for(int i = 0; i < length; i++){
      Print("! ExtUpperBuffer: " + ExtUpperBuffer[i]);
   }
   
   int length2 = sizeof(ExtUpperBuffer)/sizeof(ExtUpperBuffer[0]);


   for(int i = 0; i < length2; i++){
      Print("! ExtLowerBuffer: " + ExtLowerBuffer[i]);
   }
*/   
//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+

void OnDeinit(const int reason)
{

   
}


Solution 1:[1]

A solution was provided in the MQL forums by Vladimir Karputov. Cheers to him taking the time. I still need to compare the two to see what was incorrect in my code but his solution works perfectly.

//+------------------------------------------------------------------+
//|                                              Fractals On OBV.mq5 |
//|                              Copyright © 2022, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2022, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   3
//--- plot OOBV
#property indicator_label1  "OOBV"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkOrange
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Fractal Up
#property indicator_label2  "Fractal Up"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrGray
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Fractal Down
#property indicator_label3  "Fractal Down"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrGray
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- input parameters
input group             "OBV"
input ENUM_APPLIED_VOLUME  Inp_OBV_applied_volume        = VOLUME_TICK;    // OBV: volume type for calculation
//--- indicator buffers
double   OBVBuffer[];
double   Fractal_Up_Buffer[];
double   Fractal_Down_Buffer[];
//---
int      handle_iOBV;                           // variable for storing the handle of the iOBV indicator
int      bars_calculated            = 0;        // we will keep the number of values in the On Balance Volume indicator
bool     m_init_error               = false;    // error on InInit
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,OBVBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,Fractal_Up_Buffer,INDICATOR_DATA);
   SetIndexBuffer(2,Fractal_Down_Buffer,INDICATOR_DATA);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   PlotIndexSetInteger(1,PLOT_ARROW,217);
   PlotIndexSetInteger(2,PLOT_ARROW,218);
//--- arrow shifts when drawing
   PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,10);
   PlotIndexSetInteger(2,PLOT_ARROW_SHIFT,-10);
//--- sets drawing line empty value
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//--- create handle of the iOBV indicator
   handle_iOBV=iOBV(Symbol(),Period(),Inp_OBV_applied_volume);
//--- if the handle is not created
   if(handle_iOBV==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iOBV indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   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[])
  {
//---
   if(m_init_error)
      return(0);
   if(rates_total<5)
      return(0);
//--- number of values copied from the iOBV indicator
   int values_to_copy;
//--- determine the number of values calculated in the indicator
   int calculated=BarsCalculated(handle_iOBV);
   if(calculated<=0)
     {
      PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError());
      return(0);
     }
//--- if it is the first start of calculation of the indicator or if the number of values in the iOBV indicator changed
//---or if it is necessary to calculated the indicator for two or more bars (it means something has changed in the price history)
   if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1)
     {
      //--- if the iOBVBuffer array is greater than the number of values in the iOBV indicator for symbol/period, then we don't copy everything
      //--- otherwise, we copy less than the size of indicator buffers
      if(calculated>rates_total)
         values_to_copy=rates_total;
      else
         values_to_copy=calculated;
     }
   else
     {
      //--- it means that it's not the first time of the indicator calculation, and since the last call of OnCalculate()
      //--- for calculation not more than one bar is added
      values_to_copy=(rates_total-prev_calculated)+1;
     }
//--- fill the arrays with values of the iOBV indicator
//--- if FillArrayFromBuffer returns false, it means the information is nor ready yet, quit operation
   if(!FillArrayFromBuffer(OBVBuffer,handle_iOBV,values_to_copy))
      return(0);
//--- memorize the number of values in the On Balance Volume indicator
   bars_calculated=calculated;
//--- Fractals
   int start;
//--- clean up arrays
   if(prev_calculated<7)
     {
      start=2;
      ArrayInitialize(Fractal_Up_Buffer,EMPTY_VALUE);
      ArrayInitialize(Fractal_Down_Buffer,EMPTY_VALUE);
     }
   else
      start=rates_total-5;
//--- main cycle of calculations
   for(int i=start; i<rates_total-3 && !IsStopped(); i++)
     {
      //--- Upper Fractal
      if(OBVBuffer[i]>OBVBuffer[i+1] && OBVBuffer[i]>OBVBuffer[i+2] && OBVBuffer[i]>=OBVBuffer[i-1] && OBVBuffer[i]>=OBVBuffer[i-2])
         Fractal_Up_Buffer[i]=OBVBuffer[i];
      else
         Fractal_Up_Buffer[i]=EMPTY_VALUE;
      //--- Lower Fractal
      if(OBVBuffer[i]<OBVBuffer[i+1] && OBVBuffer[i]<OBVBuffer[i+2] && OBVBuffer[i]<=OBVBuffer[i-1] && OBVBuffer[i]<=OBVBuffer[i-2])
         Fractal_Down_Buffer[i]=OBVBuffer[i];
      else
         Fractal_Down_Buffer[i]=EMPTY_VALUE;
     }
//---
   for(int i=rates_total-3; i<rates_total; i++) 
     {
      Fractal_Up_Buffer[i]=EMPTY_VALUE;
      Fractal_Down_Buffer[i]=EMPTY_VALUE;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Filling indicator buffers from the iOBV indicator                |
//+------------------------------------------------------------------+
bool FillArrayFromBuffer(double &obv_buffer[],  // indicator buffer of OBV values
                         int ind_handle,        // handle of the iOBV indicator
                         int amount             // number of copied values
                        )
  {
//--- reset error code
   ResetLastError();
//--- fill a part of the iOBVBuffer array with values from the indicator buffer that has 0 index
   if(CopyBuffer(ind_handle,0,0,amount,obv_buffer)<0)
     {
      //--- if the copying fails, tell the error code
      PrintFormat("Failed to copy data from the iOBV indicator, error code %d",GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
//--- everything is fine
   return(true);
  }
//+------------------------------------------------------------------+
//| Indicator deinitialization function                              |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(handle_iOBV!=INVALID_HANDLE)
      IndicatorRelease(handle_iOBV);
  }
//+------------------------------------------------------------------+

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 TheJoshuamcgowan