Why my indicator keeps disappearing?

 

From time to time, my indicator simply disappears. And it's not simple to put it back.

Can someone help me understand why it is happening?


//+------------------------------------------------------------------+
//|                                                  SpreadRatio.mq5 |
//|                                                               GC |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "GC"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum 0.9
#property indicator_maximum 1.5
#property indicator_buffers 1
#property indicator_plots   1
//--- plot SD
#property indicator_label1  "SpreadRatio"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrOrange
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1


//--- input parameters
input string   iptSymbol="PETR3";

//--- indicator buffers
double SDBuffer[];
double razao;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,SDBuffer,INDICATOR_DATA);

//---
   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[])
  {
//---

   ArraySetAsSeries(time,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(SDBuffer,true);

   MqlRates rates1[]; ArraySetAsSeries(rates1,true);
   MqlRates rates2[]; ArraySetAsSeries(rates2,true);

   if(prev_calculated<rates_total)
     {
      for(int i=0;i<rates_total;i++)
        {
         CopyRates(_Symbol,_Period,time[i],1,rates1);
         CopyRates(iptSymbol,_Period,time[i],1,rates2);

         razao=rates2[0].close/rates1[0].close;
         SDBuffer[i]=razao;
        }
     }


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

From time to time, my indicator simply disappears. And it's not simple to put it back.

Can someone help me understand why it is happening?


Most probably you have an "array out of range" or eventually a "divide by 0" critical error. Check your log (Experts tab).

CopyRates() is a function, you need to check the returned value and act accordingly (see documentation).

 
Alain Verleyen:

Most probably you have an "array out of range" or eventually a "divide by 0" critical error. Check your log (Experts tab).

CopyRates() is a function, you need to check the returned value and act accordingly (see documentation).

You are right!

The error is an  "array out of range".

I read the documentation in the link and the function documentation, but I still did not get it!

Why sometimes I got this error and sometimes not? Since is the same number of bars, and nothing that I am aware changed...

I am researching it, but is there any known way to prevent this error?


Thank you, very much for you kindness replying this post

 
gucrepaldi:

From time to time, my indicator simply disappears. And it's not simple to put it back.

Can someone help me understand why it is happening?


Obviously you have failed to get data by CopyRates(). Probably your "iptSymbol" has less Bars than "_Symbol". You have to deal with it.
 
gucrepaldi:

You are right!

The error is an  "array out of range".

I read the documentation in the link and the function documentation, but I still did not get it!

Why sometimes I got this error and sometimes not? Since is the same number of bars, and nothing that I am aware changed...

I am researching it, but is there any known way to prevent this error?


Thank you, very much for you kindness replying this post

Not only one of the symbol can have less bars than the other as pointed by @Petr Nosek but it could also happen that a symbol has a bar for a given time and the other not. You NEED to check the returned value of CopyRates() as I already advised you. You asked 1 value so it should return 1 value, otherwise you have to deal with it.

That being said your way to request 1 value at a time for both symbols is very inefficient, but that's an other matter.

 

is there #property strict on MT5? it helps me a lot on MT4

 
Petr Nosek:
Obviously you have failed to get data by CopyRates(). Probably your "iptSymbol" has less Bars than "_Symbol". You have to deal with it.

Thank you! You helped me a lot with the "array out of range" error. I will show how dealt with it.


Alain Verleyen:

Not only one of the symbol can have less bars than the other as pointed by @Petr Nosek but it could also happen that a symbol has a bar for a given time and the other not. You NEED to check the returned value of CopyRates() as I already advised you. You asked 1 value so it should return 1 value, otherwise you have to deal with it.

That being said your way to request 1 value at a time for both symbols is very inefficient, but that's an other matter.

Thanks again. Although I am studying the documentation,  I still can not understand what you mean by "You NEED to check the returned value".

I used an "If" operator... but I don't think that's what you meant.

Also, I'd be glad if you tell your thoughts about a more efficient way to achieve the same results.

This is the new code:

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[])
  {
//---

   ArraySetAsSeries(time,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(SDBuffer,true);

   MqlRates rates1[]; ArraySetAsSeries(rates1,true);
   MqlRates rates2[]; ArraySetAsSeries(rates2,true);

   double razao;
   int TotalBarsIptSymbol;

   TotalBarsIptSymbol=iBars(iptSymbol,_Period);

   if(prev_calculated<rates_total)
     {
      for(int i=0;i<MathMin(rates_total,TotalBarsIptSymbol)-1;i++)
        {
         if (CopyRates(_Symbol,_Period,time[i],1,rates1)) {} else return(rates_total); 
         if (CopyRates(iptSymbol,_Period,time[i],1,rates2)) {} else return(rates_total);

         razao=rates2[0].close/rates1[0].close;
         SDBuffer[i]=razao;
        }
     }

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

Thank you! You helped me a lot with the "array out of range" error. I will show how dealt with it.


Thanks again. Although I am studying the documentation,  I still can not understand what you mean by "You NEED to check the returned value".

I used an "If" operator... but I don't think that's what you meant.

Also, I'd be glad if you tell your thoughts about a more efficient way to achieve the same results.

This is the new code:

Read the documentation of CopyRates(). If it's a matter of language, the documentation also exists in Portuguese.

Return Value

Returns the number of copied elements or -1 in case of  an error.

That doesn't seem hard to understand. Is it ?

 
Alain Verleyen:

Read the documentation of CopyRates(). If it's a matter of language, the documentation also exists in Portuguese.

That doesn't seem hard to understand. Is it ?

I've already read it. But i was unable to deal with it. At least, now, I think i got it. Thanks!

   if(prev_calculated<rates_total)
     {
      for(int i=0;i<MathMin(rates_total,TotalBarsIptSymbol)-2;i++)
        {
         if(CopyRates(_Symbol,_Period,time[i],1,rates1)<0)
           {
            Print("Erro: ",GetLastError());
           }

         if(CopyRates(iptSymbol,_Period,time[i],1,rates2)<0)
           {
            Print("Erro: ",GetLastError());
           }

         razao=rates2[0].close/rates1[0].close;
         SDBuffer[i]=razao;
        }
     }

 Could you tell me something to be more efficient?

 
gucrepaldi:

I've already read it. But i was unable to deal with it. At least, now, I think i got it. Thanks!

 Could you tell me something to be more efficient?

//+------------------------------------------------------------------+
//| 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 limit,toCopy;
//---
   if(prev_calculated==0)
     {
      ArrayInitialize(SDBuffer,EMPTY_VALUE);
      int iptBars = iBars(iptSymbol,_Period);
      toCopy      = (iptBars>rates_total || iptBars==0 ? rates_total : iptBars);
      limit       = rates_total-toCopy;
     }
   else
     {
      //--- update only on new bar
      if(prev_calculated==rates_total) return(rates_total);
      limit       = prev_calculated-1;
      toCopy      = rates_total-limit;
     }
   int copied=CopyRates(iptSymbol,_Period,0,toCopy,rates);
   if(copied==-1) { /* error ... */ return(0); };

   for(int i=limit,iptIndex=0;i<rates_total;i++)
     {
      while(iptIndex<copied-1 && rates[iptIndex].time<time[i])
        {
         ++iptIndex;
        }
      //---
      if(rates[iptIndex].time==time[i])
         SDBuffer[i]=rates[iptIndex].close/close[i];
      else
         SDBuffer[i]=EMPTY_VALUE;
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
 
Alain Verleyen:

Wow! That's very impressive! And I am very grateful!

I will take my time to understand it completely and improve my skills based on your example.

And I still can use your way of thinking to adapt it for another indicators.

Thanks A LOT!!!