[Les indicateurs ne sont pas correctement instanciés lorsqu'ils sont appelés/créés à partir d'un indicateur d'une période de travail différente.

 

MISE À JOUR : voir la solution de contournement ci-dessous.

CopyBuffer() jette une erreur de 4806 (Données de l'indicateur non accessibles) lors de l'appel d'un indicateur avec un Time-Frame différent depuis le code d'un indicateur. Cela se produit lors de l'appel d'un indicateur valide avec un Time-Frame différent du Time-Frame de travail actuel. Le bug n'apparaît que pendant l'initialisation et le premier appel à OnCalculate() AVANT le premier tick de données. Afin d'isoler le bug, les méthodes suivantes ont été appliquées :

Voici le bloc de code utilisé pour tester la sortie de CopyBuffer() lorsqu'il est appelé depuis un script, un EA et un indicateur.

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

Code complet de l'indicateur :

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

La seule façon de ne pas recevoir d'erreur est de le lancer sur des graphiques H1 (même TF).

Liens vers le post du forum avec le même problème :

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

SOLUTION :

La solution consistait à créer l'indicateur dans OnInit() et à définir EventSetMillisecondTimer à 1ms. Cela a permis à OnCalculate() de revenir après son premier passage et d'appeler rapidement OnTimer pour un second passage. Un seul appel à l'événement OnTimer a été nécessaire pour le fixer et aucune autre temporisation n'a été requise pour les calculs.

//+------------------------------------------------------------------+
//|                                                    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.
 
Quelqu'un connaît-il une solution de contournement ?
 

Je crains qu'il ne s'agisse pas d'un bug de MT5 mais d'un bug dans votre code. D'ailleurs, comme tous les sujets que vous avez signalés. Vous devez faire face à la plateforme/langage telle qu'elle a été conçue, et non comme vous pensez qu'elle est ou voudriez qu'elle soit.

Pourquoi utilisez-vous ima.Create() dans OnCalculate() ? Vous obtenez un handle mais les données ne sont pas encore disponibles, vous obtenez une erreur et votre code n'est plus jamais appelé.

P.S : Quelle est la signification de "Fonctionne sans accès aux données". ?
 
Alain Verleyen:

Je crains qu'il ne s'agisse pas d'un bug dans MT5 mais d'un bug dans votre code. D'ailleurs, comme tous les sujets que vous avez signalés. Vous devez faire face à la plate-forme/langage telle qu'elle a été conçue, et non comme vous pensez qu'elle est ou voudriez qu'elle soit.

Pourquoi utilisez-vous ima.Create() dans OnCalculate() ? Vous obtenez un handle mais les données ne sont pas encore disponibles, vous obtenez une erreur puis votre code n'est plus jamais appelé.

P.S : Quelle est la signification de "Fonctionne sans accès aux données". ?
J'ai bien peur qu'il s'agisse d'un bug de la plateforme. J'exécute exactement le même bloc de code dans le OnInit() de l'expert et je n'obtiens aucune erreur, alors que le OnInit() de l'indicateur génère des erreurs. Fonctionner sans accès aux données signifie qu'il fonctionne hors ligne, dans le testeur, ou en dehors des heures de marché. Un appel à un indicateur devrait l'instancier de n'importe où et à n'importe quel moment, et le fait que la plateforme soit incohérente à cet égard signifie qu'il ne s'agit pas d'une fonctionnalité mais d'un bug. Le fait d'avoir ima.Create à l'intérieur de oncalculate n'est qu'un exemple, car il ne parvient pas non plus à instancier l'indicateur sur un cadre temporel différent - à partir de n'importe quel endroit où vous l'appelez dans l'indicateur, avant le premier tick (mise à jour des données). Vous pouvez le rafraîchir une infinité de fois, mais il n'accédera pas aux données de l'indicateur avant que oncalculate ne s'exécute exactement une fois et ne revienne. Il fonctionne lors du passage suivant lorsqu'un nouveau tick arrive. Bogue.

Encore une fois, je tiens à souligner que cela fonctionne correctement à partir de n'importe où dans les experts et les scripts, mais que cela ne fonctionne pas dans les indicateurs.

 
nicholishen:
J'ai bien peur qu'il s'agisse en fait d'un bug de la plateforme. J'exécute exactement le même bloc de code dans le OnInit() de l'expert et je n'obtiens aucune erreur, alors que le OnInit() de l'indicateur génère des erreurs. Fonctionner sans accès aux données signifie qu'il fonctionne hors ligne, dans le testeur, ou en dehors des heures de marché. Un appel à un indicateur devrait l'instancier de n'importe où et à n'importe quel moment, et le fait que la plateforme soit incohérente à cet égard signifie qu'il ne s'agit pas d'une fonctionnalité mais d'un bug. Le fait d'avoir ima.Create à l'intérieur de oncalculate n'est qu'un exemple, car cela ne permet pas non plus d 'instancier l 'indicateur sur un cadre temporel différent - à partir de n'importe quel endroit où vous l'appelez dans l'indicateur, avant le premier tick (mise à jour des données). Encore une fois, je tiens à souligner que cela fonctionne correctement dans les experts et les scripts, mais que cela ne fonctionne pas dans les indicateurs.

Ok, vous ne me croyez pas, c'est votre droit, mais vous avez tort.

Je ne peux que vous suggérer d'écrire au ServiceDesk, et de rapporter leur réponse ici.

 
Alain Verleyen:

Ok, vous ne me croyez pas, c'est votre droit, mais vous avez tort.

Je ne peux que vous suggérer d'écrire au ServiceDesk, et de rapporter leur réponse ici.

Merci, je le ferai. Si je me trompe, alors pourquoi exactement cela fonctionne-t-il dans les experts et les scripts, mais pas à partir des indicateurs ?
 
nicholishen:
Merci, je le ferai. Si je me trompe, alors pourquoi exactement cela fonctionne-t-il dans les experts et les scripts, mais pas à partir des indicateurs ?

Parce que tous les indicateurs d'un symbole fonctionnent sur le même fil. Strategy Tester, EA et script sont des situations différentes.

Mais voyons la réponse du ServiceDesk. Peut-être ai-je tort :-)

 
Alain Verleyen:

Parce que tous les indicateurs d'un symbole fonctionnent sur le même fil. Strategy Tester, EA et script sont des situations différentes.

Mais voyons la réponse de ServiceDesk. Peut-être que je me trompe :-)

Considérons que c'est le cas...

  • Pourquoi pouvez-vous instancier un indicateur de la même trame temporelle et accéder à ses données immédiatement, mais pas une trame temporelle différente ?
 
nicholishen:
  • Pourquoi pouvez-vous instancier un indicateur du même cadre temporel et accéder à ses données immédiatement ?

Cela signifie en fait que vous avez de la chance que les données soient déjà disponibles. Ce n'est pas garanti. Cela peut aussi échouer.
 
Stanislav Korotky:
Cela signifie en fait, que vous avez de la chance que les données soient déjà disponibles. Ce n'est pas garanti. Cela peut aussi échouer.

Cela signifie que si les données sont immédiatement disponibles pour un script ou un EA, elles seront également disponibles pour l'indicateur (ce n'est donc pas un problème de disponibilité des données). L'indicateur ne parvient tout simplement pas à s'instancier avant le deuxième passage de OnCalculate() (c'est-à-dire le premier tick).

J'ai pris cela en considération lors du diagnostic. J'ai même incorporé des boucles et une période d'attente, juste au cas où. Comme tout le monde avant moi, j'ai les mêmes problèmes avec ce bug particulier.

 
nicholishen:

Cela signifie que si les données sont immédiatement disponibles pour un script ou un EA, elles seront également disponibles pour l'indicateur (ce n'est donc pas un problème de disponibilité des données). L'indicateur ne parvient tout simplement pas à s'instancier avant le deuxième passage de OnCalculate() (c'est-à-dire le premier tick).

J'ai pris cela en considération lors du diagnostic. J'ai même incorporé des boucles et une période d'attente, juste au cas où. Comme tout le monde avant moi, j'ai les mêmes problèmes avec ce bug particulier.

Vous répétez "failing to instantiate", mais ce n'est pas exact. L'indicateur est instancié dans tous les cas.

Le problème est que les données ne sont pas disponibles de manière synchrone, vous devez faire avec. Ce n'est PAS un bug de MT5, c'est une FONCTION.

Je propose d'arrêter la discussion et d'attendre la réponse de SD.