Indicator signal won't draw

 

I'm coding a volume-based custom indicator with two signals and for some reason that I just can't figure out the second line won't draw.  The name of the buffer that won't draw is relVolumeMA in the code below.  I'm not a programming expert by any stretch, but have done quite a few indicators and I'm just not seeing why this signal won't draw in the indicator window.  A second set of eyes would be awesome.


//+------------------------------------------------------------------+
//|                                             jtRelativeVolume.mq4 |
//|                                      Copyright 2020, John Turner |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, John Turner"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_separate_window
//#property indicator_minimum -3
//#property indicator_maximum 3
#property indicator_buffers 2
#property indicator_plots   2

//--- input parameters
input int      RelativePeriod = 10;
input int      MA_Period = 20;

//--- plot Volume Change
#property indicator_label1  "Volume Change"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrMagenta
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Volume Change MA
#property indicator_label2  "Volume Change MA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- indicator buffers
double      relVolume[];
double      relVolumeMA[];


//--- variables
long tempVolSum;
long volumeAvg;
int i, j, k;
static int limit;
datetime baseBarTime;
datetime compBarTime;
MqlDateTime baseBarTimeStruct;
MqlDateTime compBarTimeStruct;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
      SetIndexBuffer(0,relVolume);
      SetIndexBuffer(1,relVolumeMA);

      ArraySetAsSeries(relVolume,true);
      ArraySetAsSeries(relVolumeMA,true);
      
      ObjectsDeleteAll();
      
      IndicatorSetInteger(INDICATOR_LEVELS,2);
      IndicatorSetDouble(INDICATOR_LEVELVALUE,0,1);
      IndicatorSetDouble(INDICATOR_LEVELVALUE,1,2);
//---
   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((rates_total <= RelativePeriod) || (rates_total <= MA_Period))
   {
      return 0; 
   }
        
   //--- last counted bar will be recounted
   limit=rates_total-prev_calculated;
      
   if(prev_calculated>0)
      limit++;   
      
   for(i=0; i<limit; i++)
   {
      baseBarTime = iTime(NULL, 0, i); // Get time value of bar being evaluated
      TimeToStruct(baseBarTime, baseBarTimeStruct);
   
      tempVolSum = 0;
      j = 0;
      k = 1;
      while(j<RelativePeriod)
      {
         if((k+i) >= Bars)
         {
            break;
         }
         else
         {
            compBarTime = iTime(NULL, 0, (k+i));
            TimeToStruct(compBarTime, compBarTimeStruct);
            
            switch(_Period)
            {
               case 1:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     if(compBarTimeStruct.min == baseBarTimeStruct.min)
                     {
                        tempVolSum += Volume[k+i];
                        j++;
                     }
                  }
               break;
               
               case 5:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     if(compBarTimeStruct.min == baseBarTimeStruct.min)
                     {
                        tempVolSum += Volume[k+i];
                        j++;
                     }
                  }
               break;
               
               case 15:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     if(compBarTimeStruct.min == baseBarTimeStruct.min)
                     {
                        tempVolSum += Volume[k+i];
                        j++;
                     }
                  }
               break;
               
               case 30:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     if(compBarTimeStruct.min == baseBarTimeStruct.min)
                     {
                        tempVolSum += Volume[k+i];
                        j++;
                     }
                  }
               break;
            
               case 60:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     tempVolSum += Volume[k+i];
                     j++;
                  }
               break;
               
               case 240:
                  if(compBarTimeStruct.hour == baseBarTimeStruct.hour)   // Find the next bar that matches the current bar's time
                  {
                     tempVolSum += Volume[k+i];
                     j++;
                  }
               break;
               
               case 1440:
                  if(compBarTimeStruct.day == baseBarTimeStruct.day)   // Find the next bar that matches the current bar's time
                  {
                     tempVolSum += Volume[k+i];
                     j++;
                  }
               break;
               
               default:
                  tempVolSum = 0;
               break;
            }   
            k++;
         }
      }
            
      volumeAvg = tempVolSum / RelativePeriod;
      
      relVolume[i] = (double)Volume[i] / volumeAvg;  
   }
   
   for(i=0; i<limit; i++)
   {
      relVolumeMA[i] = iMAOnArray(relVolume,0,MA_Period,0,MODE_SMA,i);
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
 
jt27:

 why this signal won't draw in the indicator window.  

A division by zero error will occur.

relVolume[i] = (double)Volume[i] / volumeAvg; 
 
Nagisa Unada:

A division by zero error will occur.

Good call, I've fixed that in case of a zero.  Unfortunately that doesn't appear to be the issue.

 
jt27:

Good call, I've fixed that in case of a zero.  Unfortunately that doesn't appear to be the issue.

Why?

I have find division by zero errors there, and have confirmed that there is no problem after the fix.

What symbols/timeframe are you testing for?

Documentation on MQL5: MQL5 programs / Runtime Errors
Documentation on MQL5: MQL5 programs / Runtime Errors
  • www.mql5.com
Runtime Errors - MQL5 programs - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
Nagisa Unada:

Why?

I have find division by zero errors there, and have confirmed that there is no problem after the fix.

What symbols/timeframe are you testing for?

I added the following to make sure there would never be a divide by zero:

volumeAvg = tempVolSum / RelativePeriod;
      
if(volumeAvg == 0)
   volumeAvg = 0.001;
         
relVolume[i] = (double)Volume[i] / volumeAvg; 
      
        

Not a pretty fix, but something to test with.  Even with this I'm still not seeing the second buffer draw.  Testing on the M15 chart primarily on GBPUSD and a few others.  Are you saying it's been working for you?

 
jt27:

I added the following to make sure there would never be a divide by zero:

Not a pretty fix, but something to test with.  Even with this I'm still not seeing the second buffer draw.  Testing on the M15 chart primarily on GBPUSD and a few others.  Are you saying it's been working for you?

The "volumeAvg" is long, so even if you put 0.001, it will end up being 0. You should make this part as follows.

volumeAvg = tempVolSum / RelativePeriod;
//relVolume[i] = (double)Volume[i] / volumeAvg;
if (volumeAvg > 0)
   relVolume[i] = (double)Volume[i] / volumeAvg;
else
   relVolume[i] = 0.0;

But the root cause of this problem is as follows.

At startup, "prev_calculated" is 0, so "limit = rates_total".

Therefore, the baseBarTime and compBarTime when "i == limit - 1" are as follows.

baseBarTime = iTime(NULL, 0, rates_total - 1);
compBarTime = iTime(NULL, 0, (k + rates_total - 1));

At this point, there are no more datetimes to compare, so "tempVolSum" becomes 0.

As a result, "volumeAvg" is also set to 0.

With this in mind, you should modify it as follows.

limit = rates_total - prev_calculated;
//if(prev_calculated > 0)
    //limit++;
if(prev_calculated == 0)
  limit = rates_total - RelativePeriod;

for(i = 0; i <= limit; i++)
{
 
Nagisa Unada:

The "volumeAvg" is long, so even if you put 0.001, it will end up being 0. You should make this part as follows.

But the root cause of this problem is as follows.

At startup, "prev_calculated" is 0, so "limit = rates_total".

Therefore, the baseBarTime and compBarTime when "i == limit - 1" are as follows.

At this point, there are no more datetimes to compare, so "tempVolSum" becomes 0.

As a result, "volumeAvg" is also set to 0.

With this in mind, you should modify it as follows.

Nagisa, thank you very much for taking the time to help me out!  That was indeed the issue and I greatly appreciate your input!