Leer registros de eventos por ID

Al conocer el calendario de eventos para un futuro próximo, los operadores pueden ajustar sus robots en consecuencia. No hay funciones ni eventos en la API de calendario («eventos» en el sentido de funciones para procesar nueva información financiera como OnCalendar, por analogía con OnTick) para hacer un seguimiento automático de las publicaciones de noticias. El algoritmo debe hacerlo por sí mismo a cualquier frecuencia elegida. En concreto, puede averiguar el identificador del evento deseado utilizando una de las funciones comentadas anteriormente (por ejemplo, CalendarValueHistoryByEvent, CalendarValueHistory) y, a continuación, llamar a CalendarValueById para obtener el estado actual de los campos de la estructura MqlCalendarValue.

bool CalendarValueById(ulong id, MqlCalendarValue &value)

La función rellena la estructura pasada por referencia con información actual sobre un evento específico.

El resultado de la función denota un signo de éxito (true) o de error (false).

Vamos a crear un sencillo indicador sin búfer CalendarRecordById.mq5, que encontrará en el futuro el evento más cercano con el tipo de «indicador financiero» (es decir, un indicador numérico) y sondeará su estado en el temporizador. Cuando se publique la noticia, los datos cambiarán (se conocerá el valor «real» del indicador), y el indicador mostrará una alerta.

La frecuencia de sondeo del calendario se establece en la variable de entrada.

input uint TimerSeconds = 5;

Ponemos en marcha el temporizador en OnInit.

void OnInit()
{
   EventSetTimer(TimerSeconds);
}

Para la salida conveniente al registro de descripción de eventos, utilizamos la estructura MqlCalendarRecord que ya conocemos del ejemplo con el script CalendarForDates.mq5.

Para almacenar el estado inicial de la información de las noticias, describimos la estructura track.

MqlCalendarValue track;

Cuando la estructura está vacía (y hay «0» en el campo id), el programa debe consultar los próximos eventos y encontrar entre ellos el más cercano con el tipo CALENDAR_TYPE_INDICATOR y para el que aún no se conoce el valor actual.

void OnTimer()
{
   if(!track.id)
   {
      MqlCalendarValue values[];
      if(PRTF(CalendarValueHistory(valuesTimeCurrent(), TimeCurrent() + DAY_LONG * 3)))
      {
         for(int i = 0i < ArraySize(values); ++i)
         {
            MqlCalendarEvent event;
            CalendarEventById(values[i].event_idevent);
            if(event.type == CALENDAR_TYPE_INDICATOR && !values[i].HasActualValue())
            {
               track = values[i];
               PrintFormat("Started monitoring %lld"track.id);
               StructPrint(MqlCalendarRecord(track), ARRAYPRINT_HEADER);
               return;
            }
         }
      }
   }
   ...

El evento encontrado se copia en track y se envía al registro. Después de eso, cada llamada a OnTimer se reduce a obtener información actualizada sobre el evento en la estructura update, que se transfiere a CalendarValueById con el identificador track.id. A continuación, las estructuras original y nueva se comparan utilizando la función auxiliar StructCompare (basada en StructToCharArray y ArrayCompare, véase el código fuente completo). Cualquier diferencia hace que se imprima un nuevo estado (la previsión puede haber cambiado), y si aparece el valor actual, el temporizador se detiene. Para empezar a esperar la siguiente noticia, este indicador necesita ser reiniciado: esto es para demostración, y para controlar la situación según la lista de noticias, más adelante desarrollaremos una clase de filtro más práctica.

   else
   {
      MqlCalendarValue update;
      if(CalendarValueById(track.idupdate))
      {
         if(fabs(StructCompare(trackupdate)) == 1)
         {
            Alert(StringFormat("News %lld changed"track.id));
            PrintFormat("New state of %lld"track.id);
            StructPrint(MqlCalendarRecord(update), ARRAYPRINT_HEADER);
            if(update.HasActualValue())
            {
               Print("Timer stopped");
               EventKillTimer();
            }
            else
            {
               track = update;
            }
         }
      }
      
      if(TimeCurrent() <= track.time)
      {
         Comment("Forthcoming event time: "track.time,
            ", remaining: "Timing::stringify((uint)(track.time - TimeCurrent())));
      }
      else
      {
         Comment("Forthcoming event time: "track.time,
            ", late for: "Timing::stringify((uint)(TimeCurrent() - track.time)));
      }
   }
}

Mientras se está a la espera del evento, el indicador muestra un comentario con la hora prevista de la publicación de la noticia y cuánto tiempo falta para que se produzca (o cuál es el retraso).

Comentario sobre la expectativa o el vencimiento de la próxima noticia

Comentario sobre esperar o llegar tarde a las próximas noticias

Es importante tener en cuenta que la noticia puede salir un poco antes o un poco después de la fecha prevista. Esto crea algunos problemas a la hora de simular estrategias de noticias en el historial, ya que no se proporciona la hora de actualización de las entradas del calendario en el terminal y a través de la API de MQL5. Intentaremos resolver parcialmente este problema en la próxima sección.

A continuación se muestran fragmentos de la salida logarítmica producida por el indicador con una laguna:

CalendarValueHistory(values,TimeCurrent(),TimeCurrent()+(60*60*24)*3)=186 / ok

Started monitoring 156045

[id] [event_id] [time] [period] [revision] »

156045 840020013 2022.06.27 15:30:00 2022.05.01 00:00:00 0 »

» [actual_value] [prev_value] [revised_prev_value] [forecast_value] [impact_type] »

» -9223372036854775808 400000 -9223372036854775808 0 0 »

» [importance] [name] [currency] [code] [actual] [previous] [revised] [forecast]

» "Medium" "Durable Goods Orders m/m" "USD" "US" nan 0.40000 nan 0.00000

...

Alert: News 156045 changed

New state of 156045

[id] [event_id] [time] [period] [revision] »

156045 840020013 2022.06.27 15:30:00 2022.05.01 00:00:00 0 »

» [actual_value] [prev_value] [revised_prev_value] [forecast_value] [impact_type] »

» 700000 400000 -9223372036854775808 0 1 »

» [importance] [name] [currency] [code] [actual] [previous] [revised] [forecast]

» "Medium" "Durable Goods Orders m/m" "USD" "US" 0.70000 0.40000 nan 0.00000

Timer stopped

 

Las noticias actualizadas tienen el valor actual_value.

Para no esperar demasiado durante la prueba, es aconsejable ejecutar este indicador durante las horas de trabajo de los principales mercados, cuando la densidad de publicación de noticias es elevada.

La función CalendarValueById no es la única, y probablemente tampoco la más flexible, con la que puede controlar los cambios en el calendario. En las secciones siguientes veremos un par de enfoques más.