[SERVICE DESK] ¡Error al obtener la hora de la TF superior en el temporizador!

 

Objetivo: Al iniciar el indicador, obtener los datos actuales en el temporizador: la hora de apertura de la barra semanal, diaria y horaria. A continuación, escríbalos en variables globales para su uso posterior. El marco temporal actual es М1.

Implementación: Obtenemos los tiempos de las barras utilizando la función 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 );
  }

Resultado: Si el terminal duró varias horas en funcionamiento, por ejemplo, estuvo apagado durante la noche, obtenemos ese resultado en su primer arranque (un día):

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

Como puedes ver, la hora de recuperación de datos es 2018.09.21 11:11, y para esa hora obtenemos la hora de apertura del día = 2018.09.20 (aunque debería ser 2018.09.21) y la hora de apertura de la hora = 2018.09.20 16:00 (aunque debería ser 2018.09.21 11:00). Y la hora que devuelve el terminal no es más que el dato de la última vez que se cerró. Es decir, los datos se almacenan en la caché y se devuelven independientemente del hecho de que el terminal se haya cerrado. Y entiendo que si se devolviera el error #4066 cada vez (datos históricos solicitados en estado de actualización) hasta que se actualicen los datos, pero no, ¡lo que se devuelve son datos de ERROR! Este error sólo se devuelve una vez y luego se puede vivir con él. Hay un claro error de caché. ¡Pido a los desarrolladores(@Slava) que le presten atención!

Repito. ¡Los datos erróneos aparecerán si se solicitan en el temporizador!

Versión del terminal: x64, 1090.

 
Así que el error 4066 es un problema típico de los índices MTF, el terminal no ha alimentado los datos de otros TF, es necesario comprobar la integridad de los datos de otros TF.
 
Vitaly Gorbunov:
Pues bien, el error 4066 es un problema típico de los usuarios de MTFs, el terminal no ha bombeado los datos de otros TFs necesita comprobar la integridad de los datos de otros TFs.

Mira bien el código y lo que he escrito antes de dar consejos.

El código tiene una comprobación de errores y una comprobación de datos vacíos. Y cuando una función devuelve datos incorrectos sin error, ¡es un error!

 
Alexey Kozitsyn:

Mira bien el código y lo que he escrito antes de dar consejos.

El código tiene una comprobación de errores y una comprobación de datos vacíos. Y cuando una función devuelve datos incorrectos sin error, ¡es un error!

Tal vez me he perdido algo, muéstrame dónde compruebas la integridad de la historia, por ejemplo, en el procedimientoCheckCurrentHourOpenTime()
 
Vitaly Gorbunov:
Tal vez me he perdido algo y muéstrame dónde compruebas la integridad del historial, por ejemplo, en el procedimientoCheckCurrentHourOpenTime()

¿Qué quiere decir con integridad de la historia?

Me refiero al hecho de que haya una comprobación de errores al recuperar los valores del historial. Hay un control en cada función. Aquí está:

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

Es decir, si se recibe un valor cero o un error, el tiempo no se escribe en la variable global. ¿Crees que no es suficiente?

La cuestión es que la función SeriesInfoInteger() primero devuelve un error pero en la siguiente ejecución devuelve ¡NO! Y tampoco devuelve el valor correcto.
 

SeriesInfoInteger() devuelve sólo información para una determinada consulta, en este caso estamos pidiendo que nos devuelva la última hora de apertura de la barra conocida en el histórico por símbolo y periodo. No hay ningún error aquí, lo que era lo último en el momento es lo que devolvió. Le mostraré cómo comprobar la integridad del historial.

 
Vitaly Gorbunov:

SeriesInfoInteger() devuelve sólo información para una determinada consulta, en este caso estamos pidiendo que nos devuelva la última hora de apertura de la barra conocida en el histórico por símbolo y periodo. No hay ningún error aquí, lo que era lo último en el momento es lo que devolvió. Llegaré al PC y te mostraré cómo comprobar la integridad del historial.

¿Quieres decir que no hay ningún error aquí? Entonces, ¿por qué da códigos de error "falsos"? Dice que la historia está bien donde no lo está...

 
Alexey Kozitsyn:

¿Qué quieres decir con que no hay ningún error aquí? Entonces, ¿por qué da códigos de error "falsos"? Dice que la historia está bien donde no lo está...

Una vez más, esta función no comprueba la integridad del historial. Devuelve la información que pudo encontrar en él. En este caso concreto, ha encontrado la barra de horas que se solicitó cuando se cerró el terminal. El resto de la historia aún no se ha cargado.

 

Para comprobar si el historial de un determinado TF está paginado por completo, basta con utilizar una función

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

Si la función devuelve false, los datos de la TF solicitada están incompletos. Por lo demás, está completo.

 
Vitaly Gorbunov:

Una vez más, esta función no comprueba la integridad de la historia. Devuelve la información que pudo encontrar en él. En este caso, se encontró la barra de horas que se solicitó cuando se apagó el terminal. El resto de la historia aún no se ha cargado.

Una vez más. No se menciona en ninguna parte. Eso es lo primero. En segundo lugar, ¿por qué se engaña al mostrar primero el código de error 4066 y luego no?

 
Ihor Herasko:

Para comprobar si el historial de un determinado TF está paginado por completo, basta con utilizar una función

Si la función devuelve false, los datos de la TF solicitada están incompletos. Por lo demás, está completo.

¿Lo has comprobado en el temporizador? ¿Ves que he comentado líneas? He comprobado esta función, no muestra ningún error y además muestra datos incorrectos. Lo comprobaré de nuevo.