[SOLVED] Indicators are not properly instantiated when called/created from an Indicator of different working time-frame.

 

UPDATE: See the workaround below

 

CopyBuffer() throws an error of 4806 (Indicator data not accessible) when calling an indicator with a different Time-Frame from within the code of an indicator. It happens when calling a valid Indicator handle to a different Time-Frame from the current working time-frame. The bug only appears during initialization and the first call to OnCalculate() BEFORE the first tick data. In order to isolate the bug the following methods were applied:

 

This is the block of code used to test the output of CopyBuffer() when called from a script, EA, and indicator.

#include <Indicators\Trend.mqh>


 

   CiMA ima;
   ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
   ima.Refresh();
  
   CIndicatorBuffer *buff = ima.At(0);
   int total = buff.Total();
   Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",total);
   for(int i=0;i<total;i++){
      if(i>2) break;
      else{
         Print(__LINE__," ",__FUNCSIG__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));  
      }
   }

 Full indicator code:

#property indicator_chart_window

#include <Indicators\Trend.mqh>
#include <errordescription.mqh>

CiMA ima;
int m_bufferSize = -1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   static int iCnt = 0;
//--- indicator buffers mapping
      Print("-----------------------",TimeCurrent(),"--------------------------");
//---
   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 != prev_calculated || m_bufferSize < 1 ){
      ResetLastError();
      ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
      ima.Refresh();
      
      CIndicatorBuffer *buff = ima.At(0);
      m_bufferSize = buff.Total();
      Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",m_bufferSize);
      if(m_bufferSize < 1){
         Print(ErrorDescription(GetLastError()));
      } else {
         for(int i=0;i<m_bufferSize;i++){
            if(i>2) break;
            else{
               Print(__LINE__," ",__FUNCTION__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));  
            }
         }
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+

 The only way to not receive an error is to launch this on H1 charts (same TF).

 

Links to forum post with same issue:

https://www.mql5.com/en/forum/73274

https://www.mql5.com/en/forum/13676

https://www.mql5.com/en/forum/30958

https://www.mql5.com/en/forum/16614

 

WORKAROUND: 

The workaround was to Create the indicator in OnInit() and set EventSetMillisecondTimer to 1ms. This allowed the OnCalculate() to return after its first pass and quickly call OnTimer for a second pass. Only one call to the OnTimer event was necessary to fix it and no further time delay was required for calculations. 

 

//+------------------------------------------------------------------+
//|                                                    THROWAWAY.mq5 |
//|                                                      nicholishen |
//|                                   www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link      "www.reddit.com/u/nicholishenFX"
#property version   "1.00"
#property indicator_chart_window

#include <Indicators\Trend.mqh>
#include <errordescription.mqh>

CiMA ima;
int m_bufferSize = -1;
bool timedEvent = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
      int waitMS = 1;
      Print("-----------------------",TimeCurrent(),"--------------------------");
  
      ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
      EventSetMillisecondTimer(waitMS);
      Print("OnTimer set to ",waitMS," ms");
      
//---
   return(INIT_SUCCEEDED);
  }

void OnTimer()
  {
//---
   ima.Refresh();
   EventKillTimer();
   timedEvent = true;
  
  }
//+------------------------------------------------------------------+
//| 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[])
  {

   static int tickCnt = 0;
   tickCnt++;
  
   if(!timedEvent)return rates_total;
//---
   if(rates_total != prev_calculated || m_bufferSize < 1 ){
      ResetLastError();
      CIndicatorBuffer *buff = ima.At(0);
      m_bufferSize = buff.Total();
      if(m_bufferSize <=0) ima.Refresh();
      // try wait with looping  
      
      if(m_bufferSize < 1){
         Print(ErrorDescription(GetLastError()));
        
      } else {
         for(int i=0;i<m_bufferSize;i++){
            if(i>2) break;
            else{
               Print(__LINE__," ",__FUNCTION__,buff.Name(),
                     " Buffer size = ",m_bufferSize,
                     " | ",ima.PeriodDescription()," iMA(",i,") value = ",
                     DoubleToString(ima.Main(i),_Digits),
                     " | Tick-count = ",tickCnt
                     );  
            }
         }
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
Error 4806 while copying buffers
Error 4806 while copying buffers
  • www.mql5.com
com/en/articles/100, but tried to change it to use the CCI indicator only.
 
Does anyone know of a workaround? 
 

I am afraid this is not a bug in MT5 but a bug in your code. By the way, like all topics your reported. You have to deal with the platform/language as it was designed, not like you think it is or would like it to be.

Why are you using ima.Create() in OnCalculate() ? You get an handle but the data are not yet available, you get an error then your code is never called again. 

P.S: What's the meaning of "Works without data access." ?
 
Alain Verleyen:

I am afraid this is not a bug in MT5 but a bug in your code. By the way, like all topics your reported. You have to deal with the platform/language as it was designed, not like you think it is or would like it to be.

Why are you using ima.Create() in OnCalculate() ? You get an handle but the data are not yet available, you get an error then your code is never called again. 

P.S: What's the meaning of "Works without data access." ?
I'm afraid this is actually a bug in the platform. I'm running the same exact code block in the OnInit() in expert and not getting any errors, while OnInit() in the indicator throws errors. Works without data access means it works offline, in tester, or off market hours. A call to any indicator should instantiate it from anywhere at anytime, and the fact that the platform is inconsistent in those regards means that this is not a feature but a bug. Having ima.Create inside oncalculate is just an example because it also fails to instantiate the indicator on any different time frame  -from anywhere you call it within indicator, before the first tick (data update). You can refresh it infinite times but it will not access indicator data until after oncalculate runs exactly once and then returns. It's works on the subsequent pass when a new tick comes in. Bug.

Again I'd like to emphasize that it does work correctly from anywhere in experts and scripts, just broken somehow in indicators.

 
nicholishen:
I'm afraid this is actually a bug in the platform. I'm running the same exact code block in the OnInit() in expert and not getting any errors, while OnInit() in the indicator throws errors. Works without data access means it works offline, in tester, or off market hours. A call to any indicator should instantiate it from anywhere at anytime, and the fact that the platform is inconsistent in those regards means that this is not a feature but a bug. Having ima.Create inside oncalculate is just an example because it also fails to instantiate the indicator on any different time frame  -from anywhere you call it within indicator, before the first tick (data update). Again I'd like to emphasize that it does work correctly from anywhere in experts and scripts, just broken somehow in indicators.

Ok you don't believe me, that's your right, but you are wrong

I can only suggest you to write to ServiceDesk, and please report their answer here.

 
Alain Verleyen:

Ok you don't believe me, that's your right, but you are wrong

I can only suggest you to write to ServiceDesk, and please report their answer here.

Thanks, I will. If I'm wrong then why exactly does it work in experts and scripts, but not from indicators? 
 
nicholishen:
Thanks, I will. If I'm wrong then why exactly does it work in experts and scripts, but not from indicators? 

Because all indicators for a symbol run on the same thread. Strategy Tester, EA and script are different situations.

Though let's see ServiceDesk answer. Maybe I am wrong :-)

 
Alain Verleyen:

Because all indicators for a symbol run on the same thread. Strategy Tester, EA and script are different situations.

Though let's see ServiceDesk answer. Maybe I am wrong :-)

Let's consider this to be the case...

  • Why can you instantiate an indicator of the same time-frame and access its data immediately, but not a different time-frame? 
 
nicholishen:
  • Why can you instantiate an indicator of the same time-frame and access its data immediately? 

This does actually mean, that you're lucky that the data is already available. This is not guaranteed. It may fail as well.
 
Stanislav Korotky:
This does actually mean, that you're lucky that the data is already available. This is not guaranteed. It may fail as well.

This means that if the data is immediately available to a script or EA then it would be equally available to Indicator (as in this is not a data availability issue). The indicator is simply failing to instantiate before the second pass of OnCalculate() (aka the first tick)

 

I took this into consideration during the diagnostics. I even incorporated loops and waiting period, just in case. Like everyone before me, I'm having the same issues with this particular bug. 

 
nicholishen:

This means that if the data is immediately available to a script or EA then it would be equally available to Indicator (as in this is not a data availability issue). The indicator is simply failing to instantiate before the second pass of OnCalculate() (aka the first tick)

 

I took this into consideration during the diagnostics. I even incorporated loops and waiting period, just in case. Like everyone before me, I'm having the same issues with this particular bug. 

You are repeating "failing to instantiate", but that's not exact. The indicator is instantiated in all cases.

The problem is the data are not available synchronously, you have to deal with it. It's NOT an MT5 bug, it's a FEATURE.

I propose to stop the discussion and wait SD answer.