Having issues making my indicator behave

 

In MQL5 I have written this indicator, or more accurately, three indicators in one. It is two 4-period moving averages (one positive and one negative) and a histogram of the difference between those two moving averages. When debugging in MetaEditor, for the most part it works right. However, when I attach it to a chart in MetaTrader, it just gives me a flat red line at zero. I know it needs some polishing, and probably has some poor programming technique, but I just taught myself to write in MQL 3 days ago. This particular issue doesn't seem to be one I can figure out alone. Anyone have an idea? For initial testing purposes I have optimized it for the EUR/USD one minute chart. I will later go in and add functionality to be able to adjust the indicator to work for other timeframes and symbols.

 

You forgot to enclose your code. 

NOTE: there are no crystal-balls on the forum (cannot magically diagnose the issue).

 
//+------------------------------------------------------------------+
//|                                              Volume_Analyzer.mq5 |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   3
#property indicator_maximum   6700000
#property indicator_minimum   -6700000

#property indicator_type1   DRAW_HISTOGRAM
#property indicator_style1  STYLE_SOLID
#property indicator_color1  clrYellow
#property indicator_width1  4
#property indicator_label1  "Volume Average Balance"

#property indicator_type2   DRAW_LINE
#property indicator_style2  STYLE_SOLID
#property indicator_color2  clrGreen
#property indicator_width2  3
#property indicator_label2  "Poitive Volume Average"

#property indicator_type3   DRAW_LINE
#property indicator_style3  STYLE_SOLID
#property indicator_color3  clrRed
#property indicator_width3  3
#property indicator_label3  "Negative Volume Average"


//---
double CloseHolding[300000];
double LowHolding[300000];
double HighHolding[300000];

double PosVolHolding1[300000];
double PosVolHolding2[300000];
double PosVolAvgHolding1[300000];
double PosVolAvgHolding2[300000];
double PosVolAvgBuff[];

double NegVolHolding1[300000];
double NegVolHolding2[300000];
double NegVolAvgHolding1[300000];
double NegVolAvgHolding2[300000];
double NegVolAvgBuff[];

long VolumeHolding1[300000];
long VolumeHolding2[300000];

double VolAvgBalHolding1[300000];
double VolAvgBalHolding2[300000];
double VolAvgBalBuff[];

//---

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ArraySetAsSeries(VolAvgBalBuff,true);
   SetIndexBuffer(0,VolAvgBalBuff);
   IndicatorSetString(INDICATOR_SHORTNAME,"Volume Average Balance");
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   ArraySetAsSeries(PosVolAvgBuff,true);
   SetIndexBuffer(1,PosVolAvgBuff);
   IndicatorSetString(INDICATOR_SHORTNAME,"Positive Volume Average");
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   ArraySetAsSeries(NegVolAvgBuff,true);
   SetIndexBuffer(2,NegVolAvgBuff);
   IndicatorSetString(INDICATOR_SHORTNAME,"Negative Volume Average");
//--- digits
   IndicatorSetInteger(INDICATOR_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[])
  {
//---

      if(prev_calculated==rates_total) return(0);   

      int newbars=rates_total-prev_calculated;                             //--- Calculate how many new bars
      if(newbars>299997) newbars=299997;
       
      if(newbars>0)
        {
         CopyTickVolume(_Symbol,PERIOD_CURRENT,0,newbars,VolumeHolding1);     //---   Copy only the new bars into
                                                                              //---   VolumeHolding1
         CopyHigh(_Symbol,PERIOD_CURRENT,0,newbars,HighHolding);              //---   Copy only the new bars into
                                                                              //---   HighHolding
         CopyLow(_Symbol,PERIOD_CURRENT,0,newbars,LowHolding);                //---   Copy only the new bars into
                                                                              //---   LowHolding
         CopyClose(_Symbol,PERIOD_CURRENT,0,newbars,CloseHolding);            //---   Copy only the new bars into
                                                                              //---   CloseHolding
        } 
      
      for(int i=0;i<newbars;i++)
        {
         VolumeHolding1[i]=VolumeHolding1[i]*1000;                //--- Multiply volumes by 1000 to make them mathematically viable
         PosVolHolding1[i]=(CloseHolding[i]-LowHolding[i])*100000;                        //---     Math the positive pips with the total
         PosVolHolding1[i]=PosVolHolding1[i]*(HighHolding[i]-LowHolding[i])*100000;     //---       pips and the volume to get
         PosVolHolding1[i]=PosVolHolding1[i]*VolumeHolding1[i];                  //---       the positive volume percentage
         double mine1=NegVolHolding1[i];
         NegVolHolding1[i]=(CloseHolding[i]-HighHolding[i])*100000;                        //---     Math the negative pips with the total
         NegVolHolding1[i]=NegVolHolding1[i]*(HighHolding[i]-LowHolding[i])*100000;     //---       pips and the volume to get
         NegVolHolding1[i]=NegVolHolding1[i]*VolumeHolding1[i];                  //---       the negative volume percentage
        }
        

      if(newbars>0)
        {
         ArraySetAsSeries(VolAvgBalBuff,true);
         ArraySetAsSeries(PosVolAvgBuff,true);
         ArraySetAsSeries(NegVolAvgBuff,true);
 
         ArrayInsert(PosVolHolding2,PosVolHolding1,0,0,newbars);
         ArrayInsert(NegVolHolding2,NegVolHolding1,0,0,newbars);

         for(int i=0;i<newbars;i++)       //---  Average the 4 most recent pos and neg volumes and store them
           {
            PosVolAvgHolding1[i]=(PosVolHolding2[i]+PosVolHolding2[i+1]+PosVolHolding2[i+2]+PosVolHolding2[i+3])/4;
            NegVolAvgHolding1[i]=(NegVolHolding2[i]+NegVolHolding2[i+1]+NegVolHolding2[i+2]+NegVolHolding2[i+3])/4;
            VolAvgBalHolding1[i]=PosVolAvgHolding1[i]+NegVolAvgHolding1[i];
           }


         ArrayInsert(PosVolAvgHolding2,PosVolAvgHolding1,0,0,newbars);    //--- Combine the new bars with the old bars
         ArrayInsert(NegVolAvgHolding2,NegVolAvgHolding1,0,0,newbars);
         ArrayInsert(VolAvgBalHolding2,VolAvgBalHolding1,0,0,newbars);
         
         ArrayCopy(PosVolAvgBuff,PosVolAvgHolding2,0,0,WHOLE_ARRAY);       //--- Put the combined pos avg volumes into the indicator buffer
         ArrayCopy(NegVolAvgBuff,NegVolAvgHolding2,0,0,WHOLE_ARRAY);       //--- Put the combined neg avg volumes into the indicator buffer
         ArrayCopy(VolAvgBalBuff,VolAvgBalHolding2,0,0,WHOLE_ARRAY);       //--- Put the combined avg vol bal into the indicator buffer
        }

//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
 
Oleksandr Medviediev #:

You forgot to enclose your code. 

NOTE: there are no crystal-balls on the forum (cannot magically diagnose the issue).

I tried to attach the file. Must have messed that up somehow. Anyhow, there's the code. Thank you for looking.
 
Jeremy Corcoran #:
   ArraySetAsSeries(VolAvgBalBuff,true);    SetIndexBuffer(0,VolAvgBalBuff);

You are trying to use ArraySetAsSeries before creating the buffer array. That is not correct.

Jeremy Corcoran #:
if(newbars>299997) newbars=299997;

I cannot realize why you are restricting the other arrays to 300000 length while you can use buffers to auto-manage those arrays. No need for ArrayInsert, ArrayCopy etc.

Jeremy Corcoran #:
         ArraySetAsSeries(VolAvgBalBuff,true);          ArraySetAsSeries(PosVolAvgBuff,true);          ArraySetAsSeries(NegVolAvgBuff,true);

The as series flag cannot be applied to statically allocated arrays. While your buffers/plots can have that. 

 
Yashar Seyyedin #:

You are trying to use ArraySetAsSeries before creating the buffer array. That is not correct.

I cannot realize why you are restricting the other arrays to 300000 length while you can use buffers to auto-manage those arrays. No need for ArrayInsert, ArrayCopy etc.

The as series flag cannot be applied to statically allocated arrays. While your buffers/plots can have that.

I originally went about it in the same direction that you described: using all dynamically allocated buffer arrays. However, I ran into trouble when I needed to get volume data into a buffer array. The copytickvolume function requires a long array. However, the setindexbuffer function requires a double array. So, my solution, as you see here, was to use static arrays to gather all the data and perform all the calculations, then transfer the finished product from the static arrays into the dynamic arrays for the plotting. My understanding from the documentation was that any transfer from long to double would be adjusted by the compiler, and I assumed that the compiler would also be able to figure out how to adjust the size of the dynamic array to accommodate the size of a static array. As far as specifying the particular size of the static array, when I did not specify it, I ran into the 'array out of range' error when the program first tried to access it.

I suppose another way I could do it is to have just the one array that gets the volume data be the static array, and have all others be dynamic arrays. But that only narrrows down the problem from many arrays to one array, and doesn't really address the problem that the data I need access to is of long type and the array I need that data to be in is of double type. I'm open to a solution to this issue if you know of something I'm not thinking of.

Thank you for your help!

 

I went ahead and rewrote it as I indicated at the end of my previous comment with all arrays as dynamic buffers with the exception of the one array that is necessarily not buffered to retrieve the volume data. So, now it displays mostly correctly when attached to a chart in MetaTrader. The issue that I have now is that the indicator flickers. I noticed while tracing through that it does this when it goes through oncalculate without any new bar data. I'm not sure why there would be a calculate event triggered when there's no new data, but it causes my indicator to go blank when it does this.




//+------------------------------------------------------------------+
//|                                              Volume_Analyzer.mq5 |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   3
#property indicator_maximum   100000000
#property indicator_minimum   -100000000
#property indicator_label1  "Volume Analyzer"

#property indicator_type1   DRAW_HISTOGRAM
#property indicator_style1  STYLE_SOLID
#property indicator_color1  clrYellow
#property indicator_width1  4

#property indicator_type2   DRAW_LINE
#property indicator_style2  STYLE_SOLID
#property indicator_color2  clrGreen
#property indicator_width2  3

#property indicator_type3   DRAW_LINE
#property indicator_style3  STYLE_SOLID
#property indicator_color3  clrRed
#property indicator_width3  3


//---
double CloseHolding[];
double LowHolding[];
double HighHolding[];

double PosVolBuff[];
double PosVolAvgBuff[];

double NegVolBuff[];
double NegVolAvgBuff[];

long VolumeHolding[];
double VolumeBuff[];

double VolAvgBalHolding1[];
double VolAvgBalHolding2[];
double VolAvgBalBuff[];

//---

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,VolAvgBalBuff,INDICATOR_DATA);
   ArraySetAsSeries(VolAvgBalBuff,true);
   IndicatorSetString(INDICATOR_SHORTNAME,"Volume Average Balance");
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   SetIndexBuffer(1,PosVolAvgBuff,INDICATOR_DATA);
   ArraySetAsSeries(PosVolAvgBuff,true);
   IndicatorSetString(INDICATOR_SHORTNAME,"Positive Volume Average");
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   SetIndexBuffer(2,NegVolAvgBuff,INDICATOR_DATA);
   ArraySetAsSeries(NegVolAvgBuff,true);
   IndicatorSetString(INDICATOR_SHORTNAME,"Negative Volume Average");
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   SetIndexBuffer(3,VolumeBuff,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(VolumeBuff,true);
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   SetIndexBuffer(4,PosVolBuff,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(PosVolBuff,true);
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,1);

   SetIndexBuffer(5,NegVolBuff,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(NegVolBuff,true);
//--- digits
   IndicatorSetInteger(INDICATOR_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[])
  {
//---

      if(prev_calculated==rates_total) return(0);   

      int newbars=rates_total-prev_calculated;                             //--- Calculate how many new bars
       
      if(newbars>0)
        {
         CopyTickVolume(_Symbol,PERIOD_CURRENT,0,newbars,VolumeHolding);     //---   Copy only the new bars into
                                                                              //---   VolumeHolding
         CopyHigh(_Symbol,PERIOD_CURRENT,0,newbars,HighHolding);              //---   Copy only the new bars into
                                                                              //---   HighHolding
         CopyLow(_Symbol,PERIOD_CURRENT,0,newbars,LowHolding);                //---   Copy only the new bars into
                                                                              //---   LowHolding
         CopyClose(_Symbol,PERIOD_CURRENT,0,newbars,CloseHolding);            //---   Copy only the new bars into
         
         for(int i=0;i<newbars;i++)
         {
            VolumeBuff[i]=VolumeHolding[i]*1000;                //--- Multiply volumes by 1000 to make them mathematically viable
            PosVolBuff[i]=(CloseHolding[i]-LowHolding[i])*100000;                        //---     Math the positive pips with the total
            PosVolBuff[i]=PosVolBuff[i]*(HighHolding[i]-LowHolding[i])*100000;     //---       pips and the volume to get
            PosVolBuff[i]=PosVolBuff[i]*VolumeBuff[i];                  //---       the positive volume percentage
            NegVolBuff[i]=(CloseHolding[i]-HighHolding[i])*100000;                        //---     Math the negative pips with the total
            NegVolBuff[i]=NegVolBuff[i]*(HighHolding[i]-LowHolding[i])*100000;     //---       pips and the volume to get
            NegVolBuff[i]=NegVolBuff[i]*VolumeBuff[i];                  //---       the negative volume percentage
         }
        

         for(int i=0;i<(newbars-3);i++)       //---  Average the 4 most recent pos and neg volumes and store them
         {
            PosVolAvgBuff[i]=(PosVolBuff[i]+PosVolBuff[i+1]+PosVolBuff[i+2]+PosVolBuff[i+3])/4;
            NegVolAvgBuff[i]=(NegVolBuff[i]+NegVolBuff[i+1]+NegVolBuff[i+2]+NegVolBuff[i+3])/4;
            VolAvgBalBuff[i]=PosVolAvgBuff[i]+NegVolAvgBuff[i];
         }

        }

//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
 

I would avoid using the "prev_calculated" parameter entirely. It will just cause issues. Think of rates_total-1 as the current (newest) bar

and for your code

 int newbars=rates_total;
 
Jeremy Corcoran #:
if(prev_calculated==rates_total) return(0); 
return rates_total;
 
All the issues have been resolved thanks to your collective efforts. I appreciate your help.
Reason: