[SERVICE DESK] ¡Error al obtener la hora de la TF superior en el temporizador! - página 15

 
Taras Slobodyanik:

Su indicador no sigue la actualización de los datos.
Llegan nuevas barras del corredor y no las compruebas.
He añadido un par de líneas para mostrar que cuando se comprueba, todo se muestra correctamente.

Es una situación de trabajo - comprobando el nuevo bar.

¡No me digas! ¿Qué te hace pensar que tengo que llevar la cuenta de los bares nuevos? ¿Está escrito en la documentación? Me refiero a que DEBO obtener el valor de la función, y luego necesariamente debo compararlo con el valor anterior? Hay una función, la función está diseñada para trabajar con plazos altos. La función puede devolver un error cuando no tiene datos, o devolver un valor incorrecto (igual a 0 en este caso). Eso es todo. Los programadores no tienen que hacer nada para obtener un valor 100% correcto.

Pero mira lo que he encontrado en la documentación de SeriesInfoInteger():

Para obtener más información sobre el error, es necesario llamar a la función GetLastError().

En mi código, ver GetLastError()? Aquí está el cheque. ¡Esta comprobación debe ser necesaria y REALMENTE necesaria! Todo lo demás son soluciones de muleta.
 
Alexey Kozitsyn:

Y mira mi primer post. ¿Ves ahí el error 4066? Entonces el error es 0 y devuelve datos incorrectos. ¿Por qué la función (en este caso, SeriesInfoInteger()) no comprueba la relevancia antes de enviar los datos? ¿Por qué no pone el indicador de error? Verás, prefiero esperar un poco más a que pasen las comprobaciones internas que buscar errores después.

Pero después me han dado muchos consejos, con los que todavía no he conseguido ningún resultado. Y resultó que ni siquiera se trataba del temporizador.

Ok, lee la ayuda)

SeriesInfoInteger

Devuelve información sobre el estado de los datos históricos.

¿Qué significa la palabra "histórico"?
Si el historial está cargado, no hay ningún error.


Alexey Kozitsyn:

¡No puede ser! ¿Y qué te hace pensar que debo seguir necesariamente nuevos bares? ¿Está escrito en la documentación? Es decir, ¿debo obtener el valor de la función, y luego debo necesariamente compararlo con el anterior? Hay una función, la función está diseñada para trabajar con plazos altos. La función puede devolver un error cuando no tiene datos, o devolver un valor incorrecto (igual a 0 en este caso). Eso es todo. Los programadores no tienen que hacer nada para obtener un valor 100% correcto.

Pero mira lo que he encontrado en la documentación de SeriesInfoInteger():

En mi código ver GetLastError()? Aquí hay una comprobación. Esta comprobación debe ser necesaria y REAL. Todo lo demás son soluciones de muleta.

No tienes que hacer nada).
...el corredor le envía datos actualizados - si quiere, úselos para el cálculo, si no - no hay problema, use el historial existente).


ps. es fin de semana, el mercado está cerrado, ¡tiene datos incorrectos en su terminal!
y no hay ningún error!!!)

 
Taras Slobodyanik:

ok, lee la ayuda)

¿Qué significa la palabra historia?
Si el historial está cargado, no hay ningún error.


No debes nada).
...el broker te envía datos actualizados - si quieres usarlos para calcular, si no - no hay problema, usa el Historial)

Cada garrapata que entra en el terminal es ya una historia. Y quiero obtener sus valores reales o el error. Si eso le conviene, está bien.

 
Alexey Kozitsyn:

Cada garrapata que entra en el terminal es ya una historia. Y quiero recibir sus valores reales o el error. Si eso te conviene, está bien.

Sí, el historial es lo que ya se ha descargado o lo que se está descargando en el pasado.
Y lo que se actualiza sólo ahora (después de la última cita) no es la historia, son los nuevos datos en bruto.

 
Taras Slobodyanik:

Comprueba el tiempo de la vela, no el cálculo de las barras.
Así se actualizará correctamente (comprobado).

Taras, aquí está el resultado de tu código:

2018.10.08 11:11:39.080 test_isNewDayInOnCalculate GBPUSD,M1: initialized
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия недельного бара = 2018.09.30 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущей недели = 2018.10.01 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: OnCalculate: Данные старших ТФ загружены!
 
Alexey Kozitsyn:

Taras, aquí está el resultado de tu código:

Sí, es la primera garrapata, la que produce la historia terminada, la que está disponible.
Después de este tick (si hay nuevas barras), inmediatamente viene el segundo tick, en el que mi código actualiza sus variables y muestran los datos correctos.

ps. puedes insertar tu propia función para comprobar la nueva barra, será la misma.

Yo mismo compruebo constantemente el número de barras, si el número ha cambiado en más de 1, significa que hay que recalcular todo de nuevo, si el número ha cambiado en 1, significa simplemente una nueva barra. Y compruebo sólo los errores más críticos, y no veo este error de retraso.

 
Taras Slobodyanik:

Sí, este es el primer tic, el que da la historia lista.
Después de este tick (si hay nuevas barras), inmediatamente viene el segundo tick, en el que mi código actualiza sus variables y muestran los datos correctos.

Pc. puede insertar su propia función para comprobar la nueva barra, será la misma.

Yo mismo compruebo constantemente el número de barras, si el número ha cambiado en más de 1, significa que hay que recalcular todo de nuevo, si el número ha cambiado en 1, significa simplemente una nueva barra. Y compruebo sólo los errores más críticos, y no veo este error de retraso.

Y aquí, por cierto, hay otro argumento a favor de que el error se produzca. Es un error de cálculo en el indicador. Escribí un Asesor Experto:

#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//--- Флаг работоспособности индикатора
bool _isWorking=true;
//--- Флаг соединения с торговым сервером (для таймера, получаем в OnCalculate())
bool _isConnected=false;
//---
bool _firstLaunch = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Устанавливаем флаг первого запуска
   _firstLaunch = true;
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//--- Устанавливаем флаг работоспособности
   _isWorking=true;
//--- Сбрасываем флаг установки соединения
   _isConnected=false;
////--- Запускаем таймер
//   if(!EventSetMillisecondTimer(20))
//     {
//      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 не установлен!");
//      //--- Устанавливаем флаг неработоспособности индикатора
//      _isWorking=false;
//     }
//--- Запрос данных
   SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
//---
   return( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//|                                                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
////--- Выключаем таймер
//   EventKillTimer();
  }
////+------------------------------------------------------------------+
////|                                                                  |
////+------------------------------------------------------------------+
//void OnTimer()
//  {
////---
//   if(!_isWorking)
//      return;
////---
//   if(!_isConnected)
//      return;
////---
//   Print(__FUNCTION__,": Данные старших ТФ загружены!");
////--- Отключаем таймер
//   EventKillTimer();
//  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Проверяем связь с сервером
   if(!IsConnected())                              // Если не удалось установить связь с сервером
     {
      //--- Сбрасываем флаг соединения с сервером
      _isConnected=false;
      //--- Выходим
      return;
     }
        //--- Проверяем первый запуск эксперта
        if( _firstLaunch )
                {
            //--- Проверяем, записано ли время открытия текущей недели
            if(!CheckCurrentWeekOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего дня
            if(!CheckCurrentDayOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего часа
            if(!CheckCurrentHourOpenTime())                              // Если время не записано
              return;                                                // Выходим
            ////--- Устанавливаем флаг соединения с сервером для запуска таймера
            //_isConnected=true;
            //---
            Print(__FUNCTION__,": Данные старших ТФ загружены!");
            //--- Сбрасываем флаг первого запуска
            _firstLaunch = false;
                }
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
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);
        }
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      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();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      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();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+

Se ejecuta desde el mismo gráfico que el indicador. Veamos los resultados:

2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: OnTick: Данные старших ТФ загружены!
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущей недели = 2018.10.08 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия недельного бара = 2018.10.07 00:00. Ошибка #0
2018.10.09 08:45:41.479 test_isNewDayInOnTick GBPUSD,M1: initialized

2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentHourOpenTime: Время открытия текущего часа = 2018.10.08 11:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentDayOpenTime: Время открытия текущего дня = 2018.10.08 00:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentWeekOpenTime: Время открытия текущей недели = 2018.10.08 00:00
2018.10.09 08:45:40.064	GBPUSD,M1: initialized

2018.10.09 08:45:40.022 Expert Other\test_isNewDayInOnTick GBPUSD,M1: loaded successfully

Lo que vemos. Vemos que todo está bien. Todo cargado, y fíjate que no hay errores, ¡los datos se actualizan inmediatamente! La pregunta principal es ¿por qué los datos del GMT se pueden obtener normalmente, mientras que el indicador debe "jugar con los diamantes"? ¿No deberían funcionar los programas por igual? ¿Por qué el mismo código funciona de forma diferente en un indicador y en un Asesor Experto? Este no debería ser el caso.

 
Alexey Kozitsyn:

Y aquí, por cierto, hay otro argumento a favor de que se produzca un error. ¡Es el ERROR en el cálculo en el indicador! He escrito un Asesor Experto:

Se ejecuta desde el mismo gráfico que el indicador. Veamos los resultados:

Lo que vemos. Vemos que todo está bien. Todo cargado, y fíjate que no hay errores, ¡los datos se actualizan inmediatamente! La pregunta principal es ¿por qué los datos del GMT se pueden obtener normalmente, mientras que el indicador debe "jugar con los diamantes"? ¿No deberían funcionar los programas por igual? ¿Por qué el mismo código funciona de forma diferente en un indicador y en un Asesor Experto? Este no debería ser el caso.

Todos los indicadores están en un solo hilo, y no ocurrirá nada nuevo hasta el final del flujo (de hecho, hasta la siguiente llamada de OpsulCalcuter). El Asesor Experto está en su propio hilo separado, por lo que cuando se inicia, se le permite posponer su inicio para las actualizaciones de datos, actualizar los datos - todo lo demás en el terminal no se ve afectado. Lleva así desde su nacimiento y no hay forma de arreglarlo, ya que el entorno de metatrader4 ha sido enterrado.

 
Unicornis:

Dado que es el terminal el que se conecta y hace algo con la carga, la comprobación, etc., todos los indicadores están en un hilo, y no ocurre nada nuevo hasta que todo en el hilo termina (de hecho, hasta la siguiente llamada de OpCalculate), es decir, estando en este hilo, no obtendrá nada más rápido que el final del hilo de todos modos. El Asesor Experto está en su propio hilo separado, por lo que cuando se inicia, se le permite retrasar su inicio para las actualizaciones de datos, actualizar los datos - todo lo demás en el terminal no se ve afectado. Lleva así desde su nacimiento y no hay forma de arreglarlo, porque el entorno de metatrader4 ha sido enterrado.

Soy consciente de que todos los indicadores de un símbolo están en un hilo mientras que cada experto tiene su propio hilo. Pero este no es el caso. Los desarrolladores son los mismos que corrigen los errores de sus creaciones. Los programas no deberían funcionar de forma diferente. Si los indicadores se han saltado algo, es un error y no hay problema. ¡El Asesor Experto ha recibido de alguna manera los datos correctos sin errores! Así que podemos ponerlo en práctica. @Slava, ¿puedes dar tu opinión sobre si se corregirá el comportamiento obviamente erróneo? ¿O, al menos, la adición de documentación (que con prev_calculated = 0 no se pueden obtener datos correctos de los TF superiores)?

 
Alexey Kozitsyn:

Sí, soy consciente de que todos los indicadores de un símbolo están en un hilo, y se asigna un hilo diferente a cada experto. Pero este no es el caso. Los desarrolladores son los que corrigen los errores de sus creaciones. Los programas no deberían funcionar de forma diferente. Si los indicadores se han saltado algo, es un error y no hay problema. ¡El Asesor Experto ha recibido de alguna manera los datos correctos sin errores! Así que podemos ponerlo en práctica. @Slava, ¿puedes dar tu opinión sobre si se corregirá el comportamiento obviamente erróneo? O al menos, ¿es un añadido a la documentación (que no podemos obtener datos correctos de TF alta cuando prev_calculated = 0)?

En la documentación había algo que decía que el Asesor Experto tiene 5 segundos enteros antes de empezar a recibir datos y durante este tiempo el terminal intenta recibir datos para el Asesor Experto. Al indicador no se le da esa posibilidad y de la misma manera no debe solicitar el refresco del historial, no es crítico para él, si es crítico, entonces debe ser calculado en un Asesor Experto. La idea principal es que la situación deseada no es posible en la aplicación actual. Esencialmente, los TFs son temporizadores y hay periodos en los que estos múltiples temporizadores coinciden en un mismo momento - esto es un proceso sincrónico 100% coincidente (excepto la hora de apertura/cierre), porque el primer tick del minuto del TF actual coincide con el primer minuto de cinco minutos, hora, etc. - es sólo escribir el mismo valor en varias variables, y es lógico establecer un conjunto de TFs necesarios y obtener todos los datos necesarios a la vez. Por qué los desarrolladores lo han hecho y no a la inversa, no lo sé. Tal vez, no se puede (no se quiere) hacer en el modelo de funcionamiento del terminal existente debido a la división cliente-servidor, ya que si ahora permitimos que los expertos usen indicadores, colgarán el terminal.

Al final, si te interesa, podrás ver cómo funciona la llamada de indicadores, el indicador llama a otro indicador, el experto(_asktfexp) llama al indicador(_asktf_sample) llamando al indicador(_asktf). Cuando se llama a un indicador desde un experto, el temporizador en el indicador no se iniciará, por lo que las soluciones con un temporizador en el indicador son sólo para los casos en los que este indicador sólo se colgará en el gráfico y no se llamará (lo cual es lógico en general).

Archivos adjuntos:
Razón de la queja: