[SERVICE DESK] Errore nell'ottenere il tempo del TF senior nel timer!

 

Obiettivo: quando si avvia l'indicatore, ottenere i dati attuali nel timer: il tempo di apertura della barra settimanale, giornaliera e oraria. Poi scriveteli in variabili globali per un uso successivo. L'orizzonte temporale attuale è М1.

Attuazione: otteniamo i tempi delle barre utilizzando la funzione 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 );
  }

Risultato: come risultato, se il terminale è rimasto in funzione per diverse ore, per esempio, era spento per la notte, otteniamo un tale risultato al suo primo avvio (un giorno):

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

Come puoi vedere, l'ora di recupero dei dati è 2018.09.21 11:11, e per quell'ora otteniamo l'ora di apertura del giorno = 2018.09.20 (anche se dovrebbe essere 2018.09.21) e l'ora di apertura dell'ora = 2018.09.20 16:00 (anche se dovrebbe essere 2018.09.21 11:00). E il tempo restituito dal terminale non è altro che il dato dell'ultima volta che è stato chiuso. Cioè i dati vengono memorizzati nella cache e restituiti indipendentemente dal fatto che il terminale sia stato chiuso. E capisco se l'errore #4066 sarebbe restituito ogni volta (dati storici richiesti in stato di aggiornamento) fino a quando i dati vengono aggiornati, ma no, sono i dati ERROR che vengono restituiti! Questo errore viene restituito solo una volta e poi ci si può convivere. C'è un chiaro errore di caching. Chiedo agli sviluppatori(@Slava) di prestarvi attenzione!

Ripeto. I dati errati appariranno se sono richiesti nel timer!

Versione del terminale: x64, 1090.

 
Quindi l'errore 4066 è un problema tipico degli indici MTF, il terminale non ha alimentato i dati di altri TF, l'integrità dei dati di altri TF deve essere controllata.
 
Vitaly Gorbunov:
Bene, quindi l'errore 4066 è un problema tipico per gli utenti MTF, il terminale non ha pompato i dati di altri TF ha bisogno di controllare l'integrità dei dati di altri TF.

Guardate bene il codice e quello che ho scritto prima di dare consigli.

Il codice ha un controllo degli errori e un controllo dei dati vuoti. E quando una funzione restituisce dati errati senza un errore, è un errore!

 
Alexey Kozitsyn:

Guardate bene il codice e quello che ho scritto prima di dare consigli.

Il codice ha un controllo degli errori e un controllo dei dati vuoti. E quando una funzione restituisce dati errati senza un errore, è un errore!

Forse mi sono perso qualcosa, mostratemi dove controllate l'integrità della storia, per esempio, nella proceduraCheckCurrentHourOpenTime()
 
Vitaly Gorbunov:
Forse mi sono perso qualcosa e mostratemi dove controllate l'integrità della storia, per esempio, nella proceduraCheckCurrentHourOpenTime()

Cosa intende per integrità della storia?

Sto parlando del fatto che c'è un controllo degli errori quando si recuperano i valori della storia. C'è un controllo in ogni funzione. Ecco qui:

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

Cioè se viene ricevuto un valore zero o un errore - il tempo non viene scritto nella variabile globale. Pensi che non sia abbastanza?

Il punto è che la funzione SeriesInfoInteger() prima restituisce un errore ma all'esecuzione successiva restituisce NO! E non restituisce nemmeno il valore corretto!
 

SeriesInfoInteger() restituisce solo informazioni per una certa query, in questo caso stiamo chiedendo di restituire l'ultimo tempo di apertura della barra conosciuto nella storia per simbolo e periodo. Non c'è nessun errore qui, quello che era l'ultimo al momento è quello che ha restituito. Vi mostrerò come controllare l'integrità della storia.

 
Vitaly Gorbunov:

SeriesInfoInteger() restituisce solo informazioni per una certa query, in questo caso stiamo chiedendo di restituire l'ultimo tempo di apertura della barra conosciuto nella storia per simbolo e periodo. Non c'è nessun errore qui, quello che era l'ultimo al momento è quello che ha restituito. Arriverò al PC e vi mostrerò come controllare l'integrità della cronologia.

Cosa vuol dire che non c'è nessun errore qui? Allora perché dà dei codici di errore "falsi"? Dice che la storia è OK dove non lo è...

 
Alexey Kozitsyn:

Cosa vuol dire che non c'è nessun errore qui? Allora perché dà dei codici di errore "falsi"? Dice che la storia è OK dove non lo è...

Ancora una volta, questa funzione non controlla l'integrità della storia! Restituisce le informazioni che ha potuto trovare in esso. In questo caso particolare, ha trovato la barra delle ore che è stata richiesta quando il terminale è stato chiuso. Il resto della storia non è stato ancora caricato.

 

Per controllare se la storia di un dato TF è completamente impaginata, basta usare una funzione:

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

Se la funzione restituisce false, i dati per il TF richiesto sono incompleti. Altrimenti è completo.

 
Vitaly Gorbunov:

Ancora una volta, questa funzione non controlla l'integrità della storia! Restituisce le informazioni che ha potuto trovare in esso. In questo caso, ha trovato la barra delle ore che è stata richiesta quando il terminale è stato chiuso. Il resto della storia non è stato ancora caricato.

Ancora una volta. Non è menzionato da nessuna parte. Questo è prima di tutto. In secondo luogo, allora perché è fuorviante mostrando prima il codice di errore 4066 e poi no?

 
Ihor Herasko:

Per controllare se la storia di un dato TF è completamente impaginata, basta usare una funzione:

Se la funzione restituisce false, i dati per il TF richiesto sono incompleti. Altrimenti è completo.

L'hai controllato nel timer? Vedete che ho commentato le righe? Ho controllato questa funzione, non ha mostrato alcun errore e ha anche mostrato dati errati. Lo controllerò di nuovo.