[Erreur dans la récupération de l'heure du senior TF dans le chronomètre !

 

Objectif : Au démarrage de l'indicateur, obtenir les données actuelles dans le timer : l'heure d'ouverture de la barre hebdomadaire, quotidienne et horaire. Ensuite, écrivez-les dans des variables globales pour une utilisation ultérieure. La période actuelle est М1.

Mise en œuvre : Nous obtenons les heures des barres en utilisant la fonction SeriesInfoInteger().

#property version   "1.00"
#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Запускаем таймер
   if(!EventSetMillisecondTimer(20))
     {
      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 ms не установлен!");
      return( INIT_FAILED );
     }
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//---
   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[])
  {

   return( rates_total );
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Проверяем, записано ли время открытия текущей недели
   if(!CheckCurrentWeekOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего дня
   if(!CheckCurrentDayOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего часа
   if(!CheckCurrentHourOpenTime())                        // Если время не записано
      return;                                                // Выходим
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
bool CheckCurrentWeekOpenTime()
  {
//--- Проверяем, записано ли время
   if(_weekOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия недельного бара
      ResetLastError();
      const datetime weekBarOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия недельного бара = "+TimeToString(weekBarOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //ResetLastError();
      //const datetime weekBarOpenTime2 = iTime( _Symbol, PERIOD_W1, 0 );
      //const int err2 = GetLastError();
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //const datetime weekOpenTime2 = weekBarOpenTime2+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия недели ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего дня                  |
//+------------------------------------------------------------------+
bool CheckCurrentDayOpenTime()
  {
//--- Проверяем, записано ли время
   if(_dayOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия дневного бара
      ResetLastError();
      const datetime tempDayOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //ResetLastError();
      //const datetime dayOpenTime2 = iTime( _Symbol, PERIOD_D1, 0 );
      //const int err2 = GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего дня iTime = "+TimeToString( dayOpenTime2 )+". Err2 #",err2 );
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия дня ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего часа              |
//+------------------------------------------------------------------+
bool CheckCurrentHourOpenTime()
  {
//--- Проверяем, записано ли время
   if(_hourOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия часового бара
      ResetLastError();
      const datetime tempHourOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //const datetime hourOpenTime2 = iTime( _Symbol, PERIOD_H1, 0 );
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }

Résultat : si le terminal a fonctionné pendant plusieurs heures, par exemple s'il était éteint pour la nuit, nous obtenons un tel résultat lors de son premier démarrage (un jour) :

2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.280 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #4066
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.265 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #4066
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущей недели = 2018.09.17 00:00. Ошибка #0
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #0
2018.09.21 11:11:27.233 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #4066
2018.09.21 11:11:27.066 test_isNewDayInTimer USDCHF.e,M1: initialized
2018.09.21 11:11:27.055 Custom indicator test_isNewDayInTimer USDCHF.e,M1: loaded successfully

Comme vous pouvez le constater, l'heure de récupération des données est 2018.09.21 11:11, et pour cette heure, nous obtenons l'heure d'ouverture du jour = 2018.09.20 (alors qu'elle devrait être 2018.09.21) et l'heure d'ouverture de l'heure = 2018.09.20 16:00 (alors qu'elle devrait être 2018.09.21 11:00). Et l'heure renvoyée par le terminal n'est rien d'autre que les données au moment de sa dernière fermeture. C'est-à-dire que les données sont mises en cache et renvoyées indépendamment du fait que le terminal a été fermé. Et je comprendrais que l'erreur #4066 soit retournée à chaque fois (données historiques demandées en état de mise à jour) jusqu'à ce que les données soient mises à jour, mais non, ce sont les données ERROR qui sont retournées ! Cette erreur n'est renvoyée qu'une seule fois et vous pouvez ensuite vous en accommoder. Il y a une erreur manifeste de mise en cache. Je demande aux développeurs(@Slava) d'y prêter attention !

Je répète. Des données erronées apparaîtront si elles sont demandées dans le timer !

Version du terminal : x64, 1090.

 
L'erreur 4066 est donc un problème typique des indices MTF, le terminal n'a pas alimenté les données des autres TF, l'intégrité des données des autres TF doit être vérifiée.
 
Vitaly Gorbunov:
L'erreur 4066 est un problème typique pour les utilisateurs de MTF, le terminal n'a pas pompé les données des autres TFs, il faut vérifier l'intégrité des données des autres TFs.

Regardez de plus près le code et ce que j'ai écrit avant de donner des conseils.

Le code comporte une vérification des erreurs et une vérification des données vides. Et lorsqu'une fonction renvoie des données incorrectes sans erreur, il s'agit d'une erreur !

 
Alexey Kozitsyn:

Regardez de plus près le code et ce que j'ai écrit avant de donner des conseils.

Le code comporte une vérification des erreurs et une vérification des données vides. Et lorsqu'une fonction renvoie des données incorrectes sans erreur, il s'agit d'une erreur !

Peut-être ai-je manqué quelque chose, montrez-moi où vous vérifiez l'intégrité de l'historique, par exemple, dans la procédureCheckCurrentHourOpenTime()
 
Vitaly Gorbunov:
Peut-être ai-je manqué quelque chose et montrez-moi où vous vérifiez l'intégrité de l'historique, par exemple, dans la procédureCheckCurrentHourOpenTime()

Qu'entendez-vous par intégrité de l'histoire ?

Je parle du fait qu'il y a une vérification des erreurs lors de la récupération des valeurs de l'historique. Il y a un contrôle dans chaque fonction. C'est ici :

//--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь

C'est-à-dire que si la valeur zéro ou une erreur est reçue - le temps n'est pas écrit dans la variable globale. Vous pensez que ce n'est pas suffisant ?

Le fait est que la fonction SeriesInfoInteger() renvoie d'abord une erreur, mais qu'à l'exécution suivante, elle renvoie NON ! Et il ne renvoie pas non plus la bonne valeur !
 

SeriesInfoInteger() renvoie uniquement les informations pour une certaine requête, dans ce cas nous demandons de renvoyer le dernier temps d'ouverture de barre connu dans l'historique par symbole et période. Il n'y a pas d'erreur ici, ce qui était le plus récent à ce moment-là est ce qu'il a retourné. Je vais vous montrer comment vérifier l'intégrité de l'historique.

 
Vitaly Gorbunov:

SeriesInfoInteger() renvoie uniquement les informations pour une certaine requête, dans ce cas nous demandons de renvoyer le dernier temps d'ouverture de barre connu dans l'historique par symbole et période. Il n'y a pas d'erreur ici, ce qui était le plus récent à ce moment-là est ce qu'il a retourné. Je vais me rendre sur le PC et vous montrer comment vérifier l'intégrité de l'historique.

Comment ça, il n'y a pas d'erreur ici ! ? Alors pourquoi donne-t-il de "faux" codes d'erreur ? Il dit que l'histoire est correcte alors qu'elle ne l'est pas...

 
Alexey Kozitsyn:

Comment ça, il n'y a pas d'erreur ici ! ? Alors pourquoi donne-t-il de 'faux' codes d'erreur ? Il dit que l'histoire est correcte alors qu'elle ne l'est pas...

Encore une fois, cette fonction ne vérifie pas l'intégrité de l'historique ! Il renvoie les informations qu'il a pu y trouver. Dans ce cas particulier, il a trouvé la barre d'heure qui avait été demandée lors de la fermeture du terminal. Le reste de l'historique n'a pas encore été chargé.

 

Pour vérifier si l'historique d'un TF donné est complètement paginé, il suffit d'utiliser une fonction :

bool IsTFDataReady(ENUM_TIMEFRAMES eTF)
{
   ResetLastError();
   iTime(NULL, eTF, 1);
   return GetLastError() == ERR_NO_ERROR;
}

Si la fonction renvoie false, les données pour le TF demandé sont incomplètes. Sinon, il est complet.

 
Vitaly Gorbunov:

Encore une fois, cette fonction ne vérifie pas l'intégrité de l'histoire ! Il renvoie les informations qu'il a pu y trouver. Dans ce cas, il a trouvé la barre d'heure qui a été demandée lors de l'arrêt du terminal. Le reste de l'historique n'a pas encore été chargé.

Encore une fois. Ce n'est mentionné nulle part. C'est la première chose. Deuxièmement, pourquoi est-il trompeur en affichant d'abord le code d'erreur 4066 et ensuite non ?

 
Ihor Herasko:

Pour vérifier si l'historique d'un TF donné est complètement paginé, il suffit d'utiliser une fonction :

Si la fonction renvoie false, les données pour le TF demandé sont incomplètes. Sinon, il est complet.

L'avez-vous vérifié dans le minuteur ? Vous voyez que j'ai commenté des lignes ? J'ai vérifié cette fonction, elle n'a montré aucune erreur du tout et a également montré des données incorrectes. Je vais vérifier à nouveau.