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

 
Ihor Herasko:

Sí, exactamente. En OnInit() simplemente llama a los TFs requeridos sin comprobar el resultado (no se puede confiar ahí), y en OnCalculate llama a la función IsTFDataReady(). Una vez que se devuelve true para todos los TFs solicitados, se puede empezar a ejecutar el algoritmo del indicador.

Bien, lo hemos solucionado. Pero debemos añadir claramente la documentación, de lo contrario el temporizador rápido causará muchas preguntas a los desarrolladores.

 
Ihor Herasko:

En general, ¿qué tipo de problema se está resolviendo para el que la presencia de una conexión terminal es tan crucial? Según tengo entendido, el indicador es una herramienta de visualización de datos. Los datos que están disponibles. Cuando lleguen nuevos datos, se actualizará la visualización. No debería exigirse la comprobación de la pertinencia de los datos. Esta es la tarea del terminal.

La tarea consiste en obtener los datos de la TF superior lo antes posible.Vitaly Gorbunov me ha recordado lo de IsConnected().

 
Alexey Kozitsyn:

Oh, hombre... Ya hemos superado ese punto. Vea su propio registro:

Secuencia. Primero comprobamos la conexión. Una vez establecida la conexión, obtenemos la hora. Explícame, por favor, ¿por qué el error 4066 se devuelve primero y luego no se devuelve? ¿Qué ha cambiado en 20ms desde la última llamada?

El error 4066 dice que no hay datos, solicitud de actualización enviada.

Una vez enviada la solicitud, ya no se envía otra, por lo que el error 4066 no tiene efecto. Esto ya se ha discutido muchas veces.

¿Por qué se inicia un temporizador en el indicador? Es muy pequeño. Hay que entender que en MT4 los indicadores se ejecutan en un hilo de interfaz. El hilo de la interfaz es donde van todos los mensajes de viento

 
Slava:

El error 4066 indica que no hay datos, se ha enviado una solicitud de actualización.

Una vez que se ha enviado una solicitud, ya no se envía otra, por lo que no se produce el error 4066. Esto ya se ha discutido muchas veces.

¿Por qué se inicia un temporizador en un indicador? Es muy pequeño. Debes entender que en MT4 los indicadores funcionan en el hilo de la interfaz. Todos los mensajes de viento pasan por el hilo de la interfaz

Me alegro de que te hayas unido a la discusión.

No es mi primer día en el foro + varias personas han comentado aquí que tampoco son el primer día en el foro. Nadie ha dicho nada al respecto:

Una vez que se ha enviado una solicitud, ya no se envía otra, por lo que no se produce el error 4066. Esto ya se ha discutido muchas veces.

Gracias, lo sabremos. Me gustaría ver esto en la ayuda. Entonces, seguramente el error se "levanta" sólo cuando se produce el evento OnTick()/OnCalculate().

¿Por qué se pone en marcha el temporizador en el indicador? Es muy pequeño.

Necesitas obtener datos de algunos personajes. Lo más rápido posible. Desgraciadamente, ni MT4 ni MT5 han implementado la recepción de eventos de llegada de cotizaciones de ningún símbolo (es imposible suscribirse a dicha actualización), por lo que la única salida (hasta donde yo sé) es interrogar a los símbolos requeridos en el temporizador.

Debes entender que en MT4 los indicadores funcionan en el hilo de la interfaz. Todos los mensajes de viento pasan por el hilo de la interfaz

Vale, ya vienen, pero ¿entonces qué? ¿Puede explicar en qué medida esto es malo/bueno/cómo afecta al funcionamiento del temporizador?
 

Se ha discutido muchas veces. 12 páginas por solicitud "error 4066".

Y te han aconsejado correctamente que envíes la solicitud en OnInit y la analices en OnCalculate.

¿Para qué necesitasun temporizador de milisegundos? Está impidiendo que el terminal del cliente se inicie normalmente. No son los mensajes de viento los que interfieren con tu temporizador, es tu temporizador el que interfiere con todos. Una vez más: LOS INDICADORES EN EL TERMINAL MT4 DEL CLIENTE TRABAJAN EN POTENCIA DE INTERFAZ.

 
Slava:

Se ha discutido muchas veces. 12 páginas en "error 4066".

Léalo, gracias. Sólo con el trabajo en OnCalculate() o OnTick() no hay problema, el problema está en OnTimer(). Y en la petición "error 4066 timer" sólo obtuve resultados de esta rama :(

Y se le aconsejó correctamente que enviara una solicitud a OnInit y la analizara en OnCalculate.

He escuchado el consejo, pero no cambia las peculiaridades del manejo de los temporizadores que no se mencionan en la documentación.

¿Por qué necesitas un temporizador de milisegundos? Estás impidiendo que el terminal del cliente se levante normalmente con tus acciones. No son los mensajes de viento los que interfieren con tu temporizador, es tu temporizador el que interfiere con el de los demás. Una vez más: LOS INDICADORES DEL TERMINAL MT4 DEL CLIENTE FUNCIONAN EN LA BOLSA DE INTERFAZ.

Una vez más, el temporizador de milisegundos sirve para obtener información de múltiples símbolos lo más rápido posible. Es decir, el algoritmo es el siguiente: el indicador se carga, obtiene los datos de los TFs altos tan pronto como sea posible, luego monitorea los bits de los símbolos necesarios en el temporizador de milisegundos. ¿Hay alguna otra forma de resolver el problema de la monitorización que no sea el uso del temporizador?

Vamos aresumir todo lo que se ha escrito aquí, corregidme si me equivoco:

1. Tarea: obtener cotizaciones de varios símbolos a través de un temporizador:

Implementación: Cuando se trabaja con un temporizador de alta frecuencia, hay que esperar a que se establezca IsConnected() con el servidor en OnCalculate() al cargar el terminal, sólo entonces se puede acceder al temporizador;

2. Objetivo: obtener los datos de los TFs más altos tan pronto como el indicador se inicie (el indicador utiliza un temporizador rápido);

Implementación: primero solicitamos los datos necesarios en OnInit(), luego esperamos la conexión IsConnected() en OnCalculate(), luego obtenemos los datos de los TFs superiores también en OnCalculate();

3. ¿El inicio de un temporizador de alta frecuencia ralentiza el hilo de la interfaz, y en consecuencia el ordenador, y es mejor no iniciarlo? ¿Cómo resolver entonces la tarea nº 1?

4. Objetivo: cargar los datos reales de los TF más antiguos.

Implementación: no utilice un temporizador de alta frecuencia para esto, ya que las funciones de recuperación de datos no están diseñadas para trabajar en un temporizador de este tipo... ¿Usamos sólo OnCalculate()?

5. En caso de que se reciba un error 4066 y se reinicie, ¿se arma OnCalculate() en cada tick?

6. ¿No funciona OnTimer() en MT5 en el hilo de la interfaz?

@Slava, por favor, responde también punto por punto;

 

1. Típicamente tendrá el estado IsConnected en la segunda llamada a OnCalculate. Primera llamada inmediatamente después de arrancar el terminal, segunda llamada a la llegada de los datos históricos

2. No utilice el temporizador rápido. En primer lugar, evalúe qué horario es aceptable para usted. Pueden ser 100 milisegundos o 500. No es casualidad que hayamos introducido originalmente el temporizador de segundos, SetMillisecondsTimer se introdujo en cinco(!) sólo 3 o 4 años después. Pero la arquitectura es diferente en el cinco.

3.1 Consigue un ordenador potente que pueda manejar colas de mensajes instantáneos.

3.2 No lances el temporizador de milisegundos inmediatamente, sino al menos después del primer OnCalculate. O más bien: en el primer OnCalculate iniciar un segundo temporizador (lo que si no hay conexión o el día libre), para que pueda analizar el medio ambiente. Y entonces, cuando estés seguro de que todos los datos están cargados, hay una conexión y todo está bien, mata el segundo temporizador y pon en marcha el temporizador de milisegundos. Entonces saltarás con seguridad por la estrecha puerta principal. En el mejor de los casos (y habrá un 99% de ellos) perderás de 2 a 5 segundos en la salida

4. Un temporizador es posible. Pero no inmediatamente (ver 3.2). Y creo que 50 milisegundos es suficiente. No estás proporcionando HFT, ¿verdad?

5. El 4066 sólo aparece en la primera solicitud de datos sobre el carácter del período de otra persona. En la siguiente solicitud del mismo período de caracteres 4066 no obtendrá más

6. En MT5 los indicadores se cuentan en un hilo de procesamiento de símbolos separado. Por lo tanto, si tiene más de un gráfico en este símbolo (o hay otros indicadores en este símbolo) puede ralentizarlos. Pero todavía no es un hilo de interfaz

 
Slava:

1. Normalmente se tendrá el estado IsConnected en la segunda llamada a OnCalculate. La primera llamada inmediatamente después de la puesta en marcha del terminal, la segunda llamada a la llegada de los datos históricos

2. No utilice el temporizador rápido. En primer lugar, evalúe qué horario es aceptable para usted. Pueden ser 100 milisegundos o 500. No es casualidad que hayamos introducido originalmente el temporizador de segundos, SetMillisecondsTimer se introdujo en cinco(!) sólo 3 o 4 años después. Pero la arquitectura es diferente en el cinco.

3.1 Consigue un ordenador potente que pueda manejar colas de mensajes instantáneos.

3.2 No lances el temporizador de milisegundos inmediatamente, sino al menos después del primer OnCalculate. O más bien: en el primer OnCalculate iniciar un segundo temporizador (lo que si no hay conexión o el día libre), para que pueda analizar el medio ambiente. Y entonces, cuando estés seguro de que todos los datos están cargados, hay conexión y todo está bien, mata el segundo temporizador y pon en marcha el temporizador de milisegundos. Entonces conseguirás pasar con seguridad por la estrecha puerta principal. En el mejor de los casos (y habrá un 99% de ellos) perderás de 2 a 5 segundos en la salida

4. Un temporizador es posible. Pero no inmediatamente (ver 3.2). Y creo que 50 milisegundos es suficiente. No estás proporcionando HFT, ¿verdad?

5. El 4066 sólo aparece en la primera solicitud de datos sobre el carácter del período de otra persona. En la siguiente solicitud para el mismo carácter de periodo, no volverá a obtener el 4066.

6. En MT5 los indicadores se cuentan en un hilo de procesamiento de símbolos separado. Por lo tanto, si tiene más de un gráfico en este símbolo (o hay otros indicadores en este símbolo) puede ralentizarlos. Pero todavía no es un hilo de interfaz

1. Así es exactamente como funciona;

2. Aquí es donde radica el problema. Cuanto más rápido, mejor. Y la evaluación se ha hecho. El indicador está escrito para el arbitraje (o más bien para la investigación del arbitraje), es decir, cada milisegundo es importante y cuanto más rápido se reciba una cotización, mejor;

3.1. y ahora el sistema es bastante potente: CPU 8600k, terminales SSD, 16gb de RAM DDR4;

3.2. Vaya... Ok, tomé nota;

4. Es probable que la tarea de arbitraje se refiera a la HFT;

5. Al principio, esto era exactamente lo que me estresaba. Si hubiera seguido recibiendo el error y supiera que los datos aún no estaban listos, este hilo no habría ocurrido;

6. Ya veo.

Gracias por la elaborada respuesta.

 
Igor Makanu:

Si no es difícil, aquí está el tema del tema - la carga correcta de la historia de la TF de edad, aquí está el indicador: "Tengo que dibujar la MA" de la TF de edad en las barras de la TF más joven, lo hice dentro de 5 minutos, funcionará para el 98% correctamente, donde en este código 2% "trampas" que causará errores?

Sí, sólo por el tema que nos ocupa. Y todo está resuelto aquí.

En primer lugar, antes de cualquier referencia a las series temporales de otros TFs/símbolos, asegúrese de comprobar que los datos están disponibles (véase la función IsTFDataReady() anterior). En el código anterior sólo se guía por el resultado de CopyClose. Pero no sabe nada de la carga de la historia. Así que, en primer lugar, asegúrese de que los datos están disponibles y sólo entonces solicítelos.

En segundo lugar, llamar a una función como argumento de otra no siempre está justificado. Y en el caso anterior, es inaceptable en principio. Al fin y al cabo, también hay que comprobar el resultado de la llamada a iBars. Así, en primer lugar se llama a iBars, el resultado se almacena en caché y se comprueba y luego sólo se transfiere el valor recibido a CopyClose().

En tercer lugar, tras la llamada de CopyClose no se comprueba que se obtengan todos los datos solicitados. Al fin y al cabo, la función puede devolver 1 o 2 barras, y se pidió, por ejemplo, 10. Yo consideraría que ese resultado es un error.

Encuarto lugar, hay un error en la propia idea del planteamiento. El bucle asume que opera con barras de otro TF pero confunde los cálculos con la variable rates_total cuyo valor se refiere al TF actual. Aquí son posibles dos enfoques que utilizo en este o aquel caso:

  1. Hacer un bucle a través de las barras del TF actual y convertir el índice de la barra del TF actual en el índice de la barra de otro TF antes de la solicitud de datos (este enfoque se utiliza en el código siguiente).
  2. Recorre las barras de otra TF. Pero entonces tenemos que incluir un bucle adicional para el caso de que la TF actual sea menor que la otra. Porque una barra de la TF más antigua corresponderá a varias barras de la TF actual.

Estoy interesado en el código correcto para MT4

A la luz de estos cuatro puntos debería quedar así (no lo he comprobado, lo he hecho a mano, pero el sentido debe ser claro):

   if (!IsTFDataReady(TimeFrame))
      return 0;

   int i,limit;

   static int nOldBars = 0;
   int nBars = iBars(_Symbol, TimeFrame);
   if (nBars == 0)
      return 0;
      
   if (nOldBars == 0 || nBars - nOldBars > 1)
   {
      if(nBars < MAPeriod)
      {
         Comment("Большой период МА!!!, в истории доступно ", nBars," баров");
         return 0;
      }
      
      limit = nBars - fmin(MAPeriod, nBars);
   }
   else
      limit = nBars - nOldBars;  // здесь всегда будет 0 или 1
   
   nOldBars = nBars;
   datetime dtTime = iTime(NULL, TimeFrame, limit);
   if (dtTime == 0)
      return 0;

   limit = iBarShift(NULL, PERIOD_CURRENT, dtTime);

// основной цикл расчета индикатора
   for(i = limit; i >= 0 && !IsStopped(); i--)
   {
      int nOtherTFBarIndex = iBarShift(NULL, TimeFrame, time[i]);
      if (nOtherTFBarIndex < 0 || nOtherTFBarIndex >= nBars)
         continue;
      
      BufMA[i] = iMA(_Symbol,TimeFrame,MAPeriod,0,MODE_SMA,PRICE_CLOSE,nOtherTFBarIndex);
   }
//---
   return rates_total;

Por cierto, lo he comprobado:


 
Ihor Herasko:

Sí, ese es el tema del hilo. Y ya está todo resuelto aquí.

En primer lugar, antes de cualquier referencia a otras series temporales de TF/símbolos, asegúrese de que los datos están disponibles (véase la función IsTFDataReady() anterior). En el código anterior sólo se guía por el resultado de CopyClose. Pero no sabe nada de la carga de la historia. Así que, en primer lugar, asegúrese de que los datos están disponibles y sólo entonces solicítelos.

En segundo lugar, llamar a una función como argumento de otra no siempre está justificado. Y en el caso anterior, es inaceptable en principio. Al fin y al cabo, también hay que comprobar el resultado de la llamada a iBars. Así, en primer lugar se llama a iBars, el resultado se almacena en caché y se comprueba y luego sólo se transfiere el valor recibido a CopyClose().

En tercer lugar, tras la llamada de CopyClose no se comprueba que se obtengan todos los datos solicitados. Al fin y al cabo, la función puede devolver 1 o 2 barras, y se pidió, por ejemplo, 10. Yo consideraría que ese resultado es un error.

Encuarto lugar, hay un error en la propia idea del planteamiento. El bucle asume que opera con barras de otro TF pero confunde los cálculos con la variable rates_total cuyo valor se refiere al TF actual. Aquí son posibles dos enfoques que utilizo en este o aquel caso:

  1. Hacer un bucle a través de las barras del TF actual y convertir el índice de la barra del TF actual en el índice de la barra de otro TF antes de la solicitud de datos (este enfoque se utiliza en el código siguiente).
  2. Recorre las barras de otra TF. Pero entonces tenemos que incluir un bucle adicional para el caso de que la TF actual sea menor que la otra. Al fin y al cabo, una barra de la TF más antigua corresponderá a varias barras de la TF actual.

A la luz de estos cuatro puntos así es como debe ser (no lo he comprobado, lo hacía a mano, pero el sentido debe ser claro):

Por cierto, lo he comprobado:


1. ¡lo tomó en sus manos! ¡Gracias!

2. ¡palabras de oro! Antes escribía así, pero con el tiempo, leyendo los códigos de otras personas, que persiguen la compacidad... Presto más atención a "la brevedad es la hermana del talento" .... y dedico mi tiempo a buscar los fallos que he encontrado.

4. "La brevedad es la hermana del talento"... Tienes razón.

3. punto interesante de análisis, lo que devuelve CopyClose(), lo he comprobado yo mismo, si no hay archivo .hst para el TF solicitado, CopyClose() nunca devuelve más de 2048 - es decir, este es el valor máximo que se puede descargar?