[Os indicadores não são devidamente instanciados quando chamados/criados a partir de um Indicador de tempo de trabalho diferente.

 

ATUALIZAÇÃO: Veja abaixo a solução

CopyBuffer() lança um erro de 4806 (Dados do indicador não acessíveis) ao chamar um indicador com um Prazo diferente de dentro do código de um indicador. Acontece quando se chama um indicador válido para um Período de tempo diferente do período de trabalho atual. O bug só aparece durante a inicialização e a primeira chamada para OnCalculate() ANTES dos dados do primeiro tick. A fim de isolar o bug, os seguintes métodos foram aplicados:

Este é o bloco de código usado para testar a saída do CopyBuffer() quando chamado a partir de um script, EA e indicador.

#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));  
      }
   }

Código indicador completo:

#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);
}
//+------------------------------------------------------------------+

A única maneira de não receber um erro é lançá-lo nos gráficos H1 (mesmo TF).

Links para postagens no fórum com o mesmo assunto:

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

FUNDAMENTO DE TRABALHO:

A solução foi criar o indicador no OnInit() e definir o EventSetMillisecondTimer para 1ms. Isto permitiu ao OnCalculate() retornar após seu primeiro passe e chamar rapidamente o OnTimer para um segundo passe. Apenas uma chamada para o evento OnTimer foi necessária para corrigi-lo e não foi necessário mais nenhum atraso para os cálculos.

//+------------------------------------------------------------------+
//|                                                    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.
 
Alguém sabe de uma solução?
 

Receio que isto não seja um bug no MT5, mas um bug em seu código. A propósito, como todos os tópicos que você relatou. Você tem que lidar com a plataforma/idioma como ela foi projetada, não como você pensa que é ou gostaria que fosse.

Por que você está usando ima.Create() na OnCalculate() ? Você recebe um controle, mas os dados ainda não estão disponíveis, você recebe um erro e seu código nunca mais é chamado novamente.

P.S: Qual é o significado de "Funciona sem acesso aos dados". ?
 
Alain Verleyen:

Receio que isto não seja um bug no MT5, mas um bug em seu código. A propósito, como todos os tópicos que você relatou. Você tem que lidar com a plataforma/idioma como ela foi projetada, não como você pensa que é ou gostaria que fosse.

Por que você está usando ima.Create() na OnCalculate() ? Você recebe um controle, mas os dados ainda não estão disponíveis, você recebe um erro e seu código nunca mais é chamado novamente.

P.S: Qual o significado de "Trabalha sem acesso aos dados". ?
Receio que isto seja na verdade um bug na plataforma. Estou executando o mesmo bloco de código exato no OnInit() em expert e não estou recebendo nenhum erro, enquanto o OnInit() no indicador lança erros. Funciona sem acesso aos dados significa que funciona offline, em horas de teste, ou fora do mercado. Uma chamada para qualquer indicador deve instanciá-lo de qualquer lugar e a qualquer momento, e o fato de que a plataforma é inconsistente nesses aspectos significa que isto não é um recurso, mas um bug. Ter ima.Create inside oncalculate é apenas um exemplo porque também falha em instanciar o indicador em qualquer período de tempo diferente - de qualquer lugar que você chamar dentro do indicador, antes do primeiro tick (atualização de dados). Você pode atualizá-lo infinitas vezes, mas ele não acessará os dados do indicador até que depois de oncalculado funcione exatamente uma vez e depois retorne. Funciona na passagem subseqüente, quando um novo tick chega. Bug.

Mais uma vez, gostaria de enfatizar que funciona corretamente de qualquer lugar em especialistas e scripts, apenas quebrado de alguma forma em indicadores.

 
nicholishen:
Receio que isto seja na verdade um bug na plataforma. Estou executando o mesmo bloco de código exato no OnInit() em expert e não estou recebendo nenhum erro, enquanto o OnInit() no indicador joga os erros. Funciona sem acesso aos dados significa que funciona offline, em horas de teste, ou fora do mercado. Uma chamada para qualquer indicador deve instanciá-lo de qualquer lugar e a qualquer momento, e o fato de que a plataforma é inconsistente nesses aspectos significa que isto não é uma característica, mas um bug. Ter ima.Create inside oncalculate é apenas um exemplo porque também falha em instanciar o indicador em qualquer período de tempo diferente - de qualquer lugar que você chamar dentro do indicador, antes do primeiro tick (atualização de dados). Mais uma vez, eu gostaria de enfatizar que ele funciona corretamente de qualquer lugar em especialistas e scripts, apenas quebrado de alguma forma nos indicadores.

Ok, você não acredita em mim, isso é seu direito, mas está errado.

Posso apenas sugerir que você escreva para o ServiceDesk, e por favor informe a resposta deles aqui.

 
Alain Verleyen:

Ok, você não acredita em mim, isso é seu direito, mas está errado.

Posso apenas sugerir que você escreva para o ServiceDesk, e por favor informe aqui a resposta deles.

Obrigado, eu o farei. Se eu estiver errado, por que exatamente funciona em especialistas e roteiros, mas não a partir de indicadores?
 
nicholishen:
Obrigado, eu vou. Se eu estiver errado, por que exatamente isso funciona em especialistas e scripts, mas não a partir de indicadores?

Porque todos os indicadores para um símbolo funcionam na mesma linha. Testador de estratégia, EA e roteiro são situações diferentes.

Embora vejamos a resposta do ServiceDesk. Talvez eu esteja errado :-)

 
Alain Verleyen:

Porque todos os indicadores para um símbolo funcionam na mesma linha. Testador de estratégia, EA e roteiro são situações diferentes.

Embora vejamos a resposta do ServiceDesk. Talvez eu esteja errado :-)

Vamos considerar este caso...

  • Por que você pode instanciar um indicador do mesmo período de tempo e acessar seus dados imediatamente, mas não um período de tempo diferente?
 
nicholishen:
  • Por que você pode instanciar um indicador do mesmo período de tempo e acessar seus dados imediatamente?

Isto significa, na verdade, que você tem sorte de os dados já estarem disponíveis. Isto não é garantido. Também pode falhar.
 
Stanislav Korotky:
Isto significa, na verdade, que você tem sorte de os dados já estarem disponíveis. Isto não é garantido. Também pode falhar.

Isto significa que se os dados estiverem imediatamente disponíveis para um script ou EA, então eles estariam igualmente disponíveis para o Indicator (como neste não se trata de um problema de disponibilidade de dados). O Indicador simplesmente não está instanciando antes da segunda passagem do OnCalculate() (também conhecido como o primeiro tick)

Levei isto em consideração durante o diagnóstico. Inclusive incorporei loops e período de espera, só por precaução. Como todos antes de mim, eu estou tendo os mesmos problemas com este bug em particular.

 
nicholishen:

Isto significa que se os dados estiverem imediatamente disponíveis para um script ou EA, então eles estariam igualmente disponíveis para o Indicator (como neste caso não é uma questão de disponibilidade de dados). O Indicador simplesmente não está instanciando antes da segunda passagem do OnCalculate() (também conhecido como o primeiro tick)

Levei isto em consideração durante o diagnóstico. Inclusive incorporei loops e período de espera, só por precaução. Como todos antes de mim, eu estou tendo os mesmos problemas com este bug em particular.

Você está repetindo "falhar em instanciar", mas isso não é exato. O indicador é instanciado em todos os casos.

O problema é que os dados não estão disponíveis sincronicamente, você tem que lidar com eles. NÃO é um bug MT5, é uma CARACTERÍSTICA.

Proponho parar a discussão e esperar a resposta SD.