[SOLVED] Gli indicatori non vengono istanziati correttamente quando vengono chiamati/creati da un indicatore di un diverso time-frame di lavoro.

 

AGGIORNAMENTO: Vedi il workaround qui sotto

CopyBuffer() lancia un errore di 4806 (Dati dell'indicatore non accessibili) quando si chiama un indicatore con un Time-Frame diverso dall'interno del codice di un indicatore. Succede quando si chiama un manico di indicatore valido a un Time-Frame diverso dal time-frame di lavoro corrente. Il bug appare solo durante l'inizializzazione e la prima chiamata a OnCalculate() PRIMA del primo tick di dati. Per isolare il bug sono stati applicati i seguenti metodi:

Questo è il blocco di codice usato per testare l'output di CopyBuffer() quando chiamato da uno script, EA e indicatore.

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

Codice completo dell'indicatore:

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

L'unico modo per non ricevere un errore è lanciarlo su grafici H1 (stesso TF).

Link al post del forum con lo stesso problema:

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

RISOLUZIONE:

Il workaround era creare l'indicatore in OnInit() e impostare EventSetMillisecondTimer a 1ms. Questo ha permesso a OnCalculate() di tornare dopo il suo primo passaggio e chiamare rapidamente OnTimer per un secondo passaggio. Era necessaria solo una chiamata all'evento OnTimer per fissarlo e non era necessario un ulteriore ritardo per i calcoli.

//+------------------------------------------------------------------+
//|                                                    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.
 
Qualcuno conosce un workaround?
 

Temo che questo non sia un bug in MT5 ma un bug nel tuo codice. A proposito, come tutti gli argomenti che hai riportato. Devi avere a che fare con la piattaforma/linguaggio come è stato progettato, non come tu pensi che sia o vorresti che fosse.

Perché stai usando ima.Create() in OnCalculate()? Ottieni un handle ma i dati non sono ancora disponibili, ottieni un errore e poi il tuo codice non viene più chiamato.

P.S: Qual è il significato di "Funziona senza accesso ai dati". ?
 
Alain Verleyen:

Temo che questo non sia un bug in MT5 ma un bug nel tuo codice. A proposito, come tutti gli argomenti che hai riportato. Devi avere a che fare con la piattaforma/linguaggio come è stato progettato, non come tu pensi che sia o vorresti che fosse.

Perché stai usando ima.Create() in OnCalculate()? Ottieni un handle ma i dati non sono ancora disponibili, ottieni un errore e poi il tuo codice non viene più chiamato.

P.S: Qual è il significato di "Funziona senza accesso ai dati". ?
Temo che questo sia effettivamente un bug nella piattaforma. Sto eseguendo lo stesso identico blocco di codice in OnInit() in expert e non ottengo alcun errore, mentre OnInit() nell'indicatore lancia errori. Funziona senza accesso ai dati significa che funziona offline, in tester, o fuori dagli orari di mercato. Una chiamata a qualsiasi indicatore dovrebbe istanziarlo da qualsiasi luogo e in qualsiasi momento, e il fatto che la piattaforma sia incoerente in questo senso significa che questa non è una caratteristica ma un bug. Avere ima.Create all'interno di oncalculate è solo un esempio perché non riesce a istanziare l'indicatore su qualsiasi diverso time frame - da qualsiasi parte lo chiamiate all'interno dell'indicatore, prima del primo tick (aggiornamento dati). Puoi aggiornarlo infinite volte ma non accederà ai dati dell'indicatore fino a quando oncalculate non verrà eseguito esattamente una volta e poi ritornerà. Funziona al passaggio successivo quando arriva un nuovo tick. Bug.

Ancora una volta vorrei sottolineare che funziona correttamente da qualsiasi punto negli esperti e negli script, solo rotto in qualche modo negli indicatori.

 
nicholishen:
Temo che questo sia effettivamente un bug nella piattaforma. Sto eseguendo lo stesso identico blocco di codice in OnInit() in expert e non ottengo alcun errore, mentre OnInit() nell'indicatore lancia errori. Funziona senza accesso ai dati significa che funziona offline, in tester, o fuori dagli orari di mercato. Una chiamata a qualsiasi indicatore dovrebbe istanziarlo da qualsiasi luogo e in qualsiasi momento, e il fatto che la piattaforma sia incoerente in questo senso significa che questa non è una caratteristica ma un bug. Avere ima.Create all'interno di oncalculate è solo un esempio perché non riesce a istanziare l'indicatore su qualsiasi altro time frame - da qualsiasi parte lo si chiami all'interno dell'indicatore, prima del primo tick (aggiornamento dati). Ancora una volta vorrei sottolineare che funziona correttamente da qualsiasi punto negli esperti e negli script, solo rotto in qualche modo negli indicatori.

Ok, non mi credete, è un vostro diritto, ma vi sbagliate

Posso solo suggerirti di scrivere al ServiceDesk, e per favore riporta qui la loro risposta.

 
Alain Verleyen:

Ok, non mi credi, è un tuo diritto, ma ti sbagli

Posso solo suggerirti di scrivere al ServiceDesk, e per favore riporta qui la loro risposta.

Grazie, lo farò. Se mi sbaglio allora perché esattamente funziona negli esperti e negli script, ma non dagli indicatori?
 
nicholishen:
Grazie, lo farò. Se mi sbaglio allora perché esattamente funziona negli esperti e negli script, ma non dagli indicatori?

Perché tutti gli indicatori per un simbolo girano sullo stesso thread. Strategy Tester, EA e script sono situazioni diverse.

Anche se vediamo la risposta del ServiceDesk. Forse mi sbaglio :-)

 
Alain Verleyen:

Perché tutti gli indicatori per un simbolo girano sullo stesso thread. Strategy Tester, EA e script sono situazioni diverse.

Vediamo la risposta di ServiceDesk. Forse mi sbaglio :-)

Consideriamo questo caso...

  • Perché si può istanziare un indicatore dello stesso time-frame e accedere immediatamente ai suoi dati, ma non un time-frame diverso?
 
nicholishen:
  • Perché potete istanziare un indicatore dello stesso time-frame e accedere immediatamente ai suoi dati?

Questo significa effettivamente che siete fortunati che i dati siano già disponibili. Questo non è garantito. Può anche fallire.
 
Stanislav Korotky:
Questo significa effettivamente che sei fortunato che i dati siano già disponibili. Questo non è garantito. Può anche fallire.

Questo significa che se i dati sono immediatamente disponibili per uno script o un EA, allora sarebbero ugualmente disponibili per l'indicatore (non è un problema di disponibilità dei dati). L'indicatore semplicemente non riesce a istanziarsi prima del secondo passaggio di OnCalculate() (ovvero il primo tick)

Ho preso in considerazione questo durante la diagnostica. Ho anche incorporato i loop e il periodo di attesa, per sicurezza. Come tutti quelli prima di me, sto avendo gli stessi problemi con questo particolare bug.

 
nicholishen:

Questo significa che se i dati sono immediatamente disponibili per uno script o un EA, allora sarebbero ugualmente disponibili per l'indicatore (non è un problema di disponibilità dei dati). L'indicatore semplicemente non riesce a istanziarsi prima del secondo passaggio di OnCalculate() (ovvero il primo tick)

Ho preso in considerazione questo durante la diagnostica. Ho anche incorporato i loop e il periodo di attesa, per sicurezza. Come tutti prima di me, sto avendo gli stessi problemi con questo particolare bug.

Stai ripetendo "non riuscendo a istanziare", ma non è esatto. L'indicatore viene istanziato in tutti i casi.

Il problema è che i dati non sono disponibili in modo sincrono, devi occupartene tu. Non è un bug di MT5, è una caratteristica.

Propongo di fermare la discussione e aspettare la risposta di SD.

Motivazione: