[SERVICE DESK] Fehler beim Abrufen der Zeit der älteren TF im Timer!

 

Ziel: Beim Starten des Indikators die aktuellen Daten im Timer abrufen: die Öffnungszeit des Wochen-, Tages- und Stundenbalkens. Dann schreiben Sie sie zur weiteren Verwendung in globale Variablen. Der aktuelle Zeitrahmen ist М1.

Umsetzung: Wir erhalten die Taktzeiten mit der Funktion 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 );
  }

Ergebnis: Wenn das Terminal mehrere Stunden gelaufen ist, z. B. weil es über Nacht ausgeschaltet war, erhalten wir ein solches Ergebnis bei seinem ersten Start (an einem Tag):

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

Wie Sie sehen können, ist der Zeitpunkt des Datenabrufs 2018.09.21 11:11, und für diese Zeit erhalten wir die Öffnungszeit des Tages = 2018.09.20 (obwohl es 2018.09.21 sein sollte) und die Öffnungszeit der Stunde = 2018.09.20 16:00 (obwohl es 2018.09.21 11:00 sein sollte). Und die vom Terminal zurückgegebene Zeit ist nichts anderes als die Daten zum Zeitpunkt des letzten Schließens. D.h. die Daten werden zwischengespeichert und unabhängig davon zurückgegeben, dass das Terminal heruntergefahren wurde. Und ich verstehe, wenn Fehler # 4066 würde jedes Mal zurückgegeben werden (angeforderte historische Daten in Update-Status), bis die Daten aktualisiert wird, aber nein, es ist ERROR Daten, die zurückgegeben wird! Dieser Fehler tritt nur einmal auf, und dann kann man damit leben. Es liegt ein eindeutiger Caching-Fehler vor. Ich bitte die Entwickler(@Slava), dies zu beachten!

Ich wiederhole. Fehlerhafte Daten werden angezeigt, wenn sie im Timer angefordert werden!

Terminal-Version: x64, 1090.

 
Der Fehler 4066 ist also ein typisches Problem für MTF-Indizes, das Terminal hat die Daten anderer TFs nicht eingespeist, die Datenintegrität anderer TFs muss überprüft werden.
 
Vitaly Gorbunov:
Nun, der Fehler 4066 ist ein typisches Problem für MTF-Benutzer, das Terminal hat die Daten anderer TFs nicht gepumpt und muss die Integrität der Daten anderer TFs überprüfen.

Schauen Sie sich den Code und das, was ich geschrieben habe, genauer an, bevor Sie Ratschläge geben.

Der Code enthält eine Prüfung auf Fehler und eine Prüfung auf leere Daten. Und wenn eine Funktion falsche Daten zurückgibt, ohne dass ein Fehler auftritt, dann ist das ein Fehler!

 
Alexey Kozitsyn:

Schauen Sie sich den Code und das, was ich geschrieben habe, genauer an, bevor Sie Ratschläge geben.

Der Code enthält eine Prüfung auf Fehler und eine Prüfung auf leere Daten. Und wenn eine Funktion falsche Daten zurückgibt, ohne dass ein Fehler vorliegt, ist das ein Fehler!

Vielleicht habe ich etwas übersehen, zeigen Sie mir, wo Sie die Integrität des Verlaufs prüfen, zum Beispiel in der ProzedurCheckCurrentHourOpenTime()
 
Vitaly Gorbunov:
Vielleicht habe ich etwas übersehen, und zeigen Sie mir, wo Sie die Integrität des Verlaufs prüfen, zum Beispiel in der ProzedurCheckCurrentHourOpenTime()

Was verstehen Sie unter Integrität der Geschichte?

Ich spreche von der Tatsache, dass beim Abrufen von Verlaufswerten eine Fehlerprüfung durchgeführt wird. In jeder Funktion gibt es eine Kontrolle. Hier ist sie:

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

D.h. wenn der Wert Null oder ein Fehler empfangen wird, wird die Zeit nicht in die globale Variable geschrieben. Glauben Sie, dass das nicht ausreicht?

Der Punkt ist, dass die Funktion SeriesInfoInteger() zunächst einen Fehler zurückgibt, aber beim nächsten Durchlauf NO! Und es gibt auch nicht den richtigen Wert zurück!
 

SeriesInfoInteger() gibt nur Informationen für eine bestimmte Abfrage zurück. In diesem Fall wollen wir die letzte bekannte Bar-Eröffnungszeit in der Historie nach Symbol und Periode zurückgeben. Hier liegt kein Fehler vor, sondern es wird das zurückgegeben, was im Moment das Neueste ist. Ich werde Ihnen zeigen, wie Sie die Integrität des Verlaufs überprüfen können.

 
Vitaly Gorbunov:

SeriesInfoInteger() gibt nur Informationen für eine bestimmte Abfrage zurück. In diesem Fall wollen wir die letzte bekannte Bar-Eröffnungszeit in der Historie nach Symbol und Periode zurückgeben. Hier liegt kein Fehler vor, sondern es wird das zurückgegeben, was im Moment das Neueste ist. Ich werde zum PC gehen und Ihnen zeigen, wie Sie die Integrität des Verlaufs überprüfen können.

Sie meinen, hier liegt kein Fehler vor? Warum gibt es dann "gefälschte" Fehlercodes aus? Es heißt, die Geschichte sei in Ordnung, wo sie es nicht ist...

 
Alexey Kozitsyn:

Was soll das heißen, hier liegt kein Fehler vor? Warum gibt er dann "falsche" Fehlercodes aus? Es heißt, die Geschichte sei in Ordnung, wo sie es nicht ist...

Noch einmal: Diese Funktion prüft nicht die Integrität der Historie! Er gibt die Informationen zurück, die er darin finden konnte. In diesem speziellen Fall wurde der Stundenbalken gefunden, der beim Abschalten des Terminals angefordert wurde. Der Rest der Geschichte ist noch nicht geladen worden.

 

Um zu prüfen, ob die Historie einer bestimmten TF vollständig durchgeblättert ist, verwenden Sie einfach eine Funktion:

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

Gibt die Funktion false zurück, sind die Daten für die angeforderte TF unvollständig. Ansonsten ist sie vollständig.

 
Vitaly Gorbunov:

Noch einmal: Diese Funktion prüft nicht die Integrität der Geschichte! Er gibt die Informationen zurück, die er darin finden konnte. In diesem Fall wurde der Stundenbalken gefunden, der beim Herunterfahren des Terminals angefordert wurde. Der Rest der Geschichte ist noch nicht geladen worden.

Noch einmal. Es wird nirgendwo erwähnt. Das ist das Wichtigste. Zweitens, warum ist es dann irreführend, wenn zuerst der Fehlercode 4066 angezeigt wird und dann nicht mehr?

 
Ihor Herasko:

Um zu prüfen, ob der Verlauf einer bestimmten TF vollständig durchgeblättert ist, verwenden Sie einfach eine Funktion:

Gibt die Funktion false zurück, sind die Daten für die angeforderte TF unvollständig. Ansonsten ist sie vollständig.

Haben Sie es in der Zeitschaltuhr überprüft? Sehen Sie, dass ich Zeilen auskommentiert habe? Ich habe diese Funktion überprüft, sie zeigte keinerlei Fehler an und zeigte auch falsche Daten an. Ich werde es noch einmal überprüfen.

Grund der Beschwerde: