English Русский 中文 Deutsch 日本語
preview
Operar con el Calendario Económico MQL5 (Parte 4): Implementación de actualizaciones de noticias en tiempo real en el panel de control

Operar con el Calendario Económico MQL5 (Parte 4): Implementación de actualizaciones de noticias en tiempo real en el panel de control

MetaTrader 5Trading |
34 2
Allan Munene Mutiiria
Allan Munene Mutiiria

Introducción

En este artículo continuamos con el desarrollo del panel del Calendario Económico de MetaQuotes Language 5 (MQL5), incorporando actualizaciones en tiempo real que permiten mostrar de forma continua los eventos económicos más relevantes. En el artículo anterior, diseñamos e implementamos un panel de control para filtrar las noticias según la actualidad, la importancia y la hora, lo que nos proporcionó una visión personalizada de los eventos relevantes. Ahora vamos más allá al habilitar actualizaciones en tiempo real, lo que garantiza que nuestro calendario muestre los datos más recientes para tomar decisiones oportunas. Los temas que trataremos incluyen:

  1. Implementación de actualizaciones de noticias en tiempo real en MQL5
  2. Conclusión

Esta mejora transformará nuestro panel de control en una herramienta dinámica y en tiempo real que se actualizará continuamente con los últimos acontecimientos económicos. Al implementar la función de actualización en tiempo real, nos aseguraremos de que nuestro calendario siga siendo preciso y relevante, lo que facilitará la toma de decisiones comerciales oportunas en MetaTrader 5 o en la terminal de operaciones.


Implementación de actualizaciones de noticias en tiempo real en MQL5

Para implementar actualizaciones en tiempo real en nuestro panel de control, debemos asegurarnos de que los eventos de noticias se almacenen y comparen periódicamente para detectar cualquier cambio. Esto requiere mantener matrices para almacenar los datos de eventos actuales y anteriores, lo que nos permite identificar las actualizaciones y reflejarlas con precisión en el panel de control. De este modo, podemos garantizar que el panel de control se ajuste dinámicamente para mostrar los acontecimientos económicos más recientes en tiempo real. A continuación, definimos las matrices que utilizaremos para este fin:

string current_eventNames_data[];
string previous_eventNames_data[];

Aquí definimos dos matrices string, «current_eventNames_data» y «previous_eventNames_data», que utilizaremos para gestionar y comparar datos de eventos económicos para actualizaciones en tiempo real del panel de control. La matriz «current_eventNames_data» almacenará los últimos eventos recuperados del calendario económico, mientras que «previous_eventNames_data» contendrá los datos del último ciclo de actualización. Al comparar estas dos matrices, podemos identificar cualquier cambio o nueva incorporación a los eventos, lo que nos permite actualizar el panel de control de forma dinámica.

Utilizando estas matrices, tendremos que obtener los valores actuales de cada evento seleccionado en la sección de inicialización y almacenarlos en la matriz de datos actual, para luego copiarlos en la matriz anterior, que utilizaremos para realizar la comparación en el siguiente tick de precios.

ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;

Aquí, ampliamos dinámicamente la matriz «current_eventNames_data» y le añadimos un nuevo nombre de evento. Utilizamos la función ArrayResize para aumentar el tamaño de la matriz en uno, creando espacio para una nueva entrada. Después de cambiar el tamaño, asignamos el nombre del evento al último índice de la matriz utilizando la expresión «current_eventNames_data[ArraySize(current_eventNames_data)-1]». Este proceso garantiza que cada nuevo nombre de evento recuperado del calendario económico se almacene en la matriz, lo que nos permite mantener una lista actualizada de eventos para su posterior procesamiento y comparación.

Sin embargo, antes de añadir los eventos a la matriz, debemos asegurarnos de empezar desde cero, lo que significa que necesitamos una matriz vacía.

ArrayFree(current_eventNames_data);

Aquí utilizamos la función ArrayFree para borrar todos los elementos de la matriz «current_eventNames_data», restableciéndola efectivamente a un estado vacío. Esto es esencial para garantizar que la matriz no conserve datos obsoletos de iteraciones anteriores, preparándola así para almacenar un nuevo conjunto de nombres de eventos durante el ciclo de procesamiento. Después de rellenar la matriz, debemos copiarla en el contenedor anterior y utilizarla más tarde para realizar la comparación.

Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

Aquí registramos y gestionamos la transición de datos entre las matrices «current_eventNames_data» y «previous_eventNames_data». En primer lugar, utilizamos la función Print para mostrar el tamaño de la matriz «current_eventNames_data», lo que permite ver el número de nombres de eventos almacenados en ese momento. A continuación, llamamos a la función ArrayPrint para mostrar el contenido de la matriz y poder verificarlo. A continuación, registramos el tamaño de la matriz «previous_eventNames_data» antes de copiarla, lo que nos proporciona una referencia para la comparación.

Utilizando la función ArrayCopy, copiamos el contenido de «current_eventNames_data» en «previous_eventNames_data», transfiriendo de forma eficaz los nombres de los eventos más recientes para futuras comparaciones. A continuación, imprimimos el tamaño de la matriz «previous_eventNames_data» tras la operación de copia para confirmar que la actualización se ha realizado correctamente. Por último, llamamos a la función ArrayPrint para generar el contenido actualizado de «previous_eventNames_data», asegurándonos de que la transferencia de datos sea precisa y completa. Esos son los cambios que necesitamos en el controlador de eventos OnInit para almacenar los eventos iniciales. Para mayor claridad, vamos a resaltarlos.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---

   ArrayFree(current_eventNames_data);
      
   //--- Loop through each calendar value up to the maximum defined total
   for (int i = 0; i < valuesTotal; i++){
   
      //---

      //--- Loop through calendar data columns
      for (int k=0; k<ArraySize(array_calendar); k++){
         //---

         //--- Prepare news data array with time, country, and other event details
         string news_data[ArraySize(array_calendar)];
         news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
         news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
         news_data[2] = country.currency; //--- Event country currency
      
         //--- Determine importance color based on event impact
         color importance_color = clrBlack;
         if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
         else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
         else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
      
         //--- Set importance symbol for the event
         news_data[3] = ShortToString(0x25CF);
      
         //--- Set event name in the data array
         news_data[4] = event.name;
            
         //--- Populate actual, forecast, and previous values in the news data array
         news_data[5] = DoubleToString(value.GetActualValue(),3);
         news_data[6] = DoubleToString(value.GetForecastValue(),3);
         news_data[7] = DoubleToString(value.GetPreviousValue(),3);         
         //---

      }
      
      ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
      current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
      
   }
   Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
   ArrayPrint(current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
   ArrayCopy(previous_eventNames_data,current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data); 
   
   //Print("Final News = ",news_filter_count);
   updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(),
              TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
              IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));
//---
   return(INIT_SUCCEEDED);
}

Aquí, solo hemos realizado los cambios que nos ayudarán a obtener los datos iniciales del evento. Los hemos resaltado en color amarillo para mayor claridad. A continuación, solo tenemos que actualizar los valores del panel de control cuando se detecten cambios durante la comparación. Para ello, crearemos una función personalizada que contendrá toda la lógica para las actualizaciones de eventos y el recálculo del panel de control, respectivamente.

//+------------------------------------------------------------------+
//| Function to update dashboard values                              |
//+------------------------------------------------------------------+
void update_dashboard_values(){

//---

}

Aquí definimos la función «update_dashboard_values», que utilizaremos para gestionar la actualización dinámica del panel del calendario económico. Esta función contendrá la lógica central para comparar los datos de noticias almacenados, identificar cualquier cambio y aplicar las actualizaciones necesarias a la interfaz del panel de control. Al organizar esta funcionalidad en esta función dedicada, garantizaremos una estructura de código limpia y modular, lo que facilitará la gestión de futuras modificaciones o mejoras. A continuación, llamaremos a la función en el controlador de eventos OnTick de la siguiente manera.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
//---
   
   update_dashboard_values();
   
}

Aquí, simplemente llamamos a la función personalizada en cada tick para realizar las actualizaciones. Tras compilar y ejecutar el programa, obtenemos los siguientes resultados:

INICIALIZACIÓN DE MATRICES DE DATOS

En la imagen, podemos ver que recopilamos todas las noticias en la matriz «actual», que luego copiamos en la nueva matriz «anterior» para su almacenamiento, lo que se ajusta perfectamente a lo que queremos. Ahora podemos proceder a utilizar estos datos copiados para realizar análisis adicionales. En la función, simplemente obtenemos los eventos actuales de la siguiente manera:

//--- Declare variables for tracking news events and status
int totalNews = 0;
bool isNews = false;
MqlCalendarValue values[]; //--- Array to store calendar values

//--- Define start and end time for calendar event retrieval
datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H12);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H12);

//--- Set a specific country code filter (e.g., "US" for USD)
string country_code = "US";
string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE);

//--- Retrieve historical calendar values within the specified time range
int allValues = CalendarValueHistory(values,startTime,endTime,NULL,NULL);

//--- Print the total number of values retrieved and the array size
//Print("TOTAL VALUES = ",allValues," || Array size = ",ArraySize(values));

//--- Define time range for filtering news events based on daily period
datetime timeRange = PeriodSeconds(PERIOD_D1);
datetime timeBefore = TimeTradeServer() - timeRange;
datetime timeAfter = TimeTradeServer() + timeRange;

//--- Print the furthest time look-back and current server time
//Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> CURRENT = ",TimeTradeServer());

//--- Limit the total number of values to display
int valuesTotal = (allValues <= 11) ? allValues : 11;
   
string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"};
int news_filter_count = 0;

ArrayFree(current_eventNames_data);

// Define the levels of importance to filter (low, moderate, high)
ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH};

//--- Loop through each calendar value up to the maximum defined total
for (int i = 0; i < valuesTotal; i++){

   MqlCalendarEvent event; //--- Declare event structure
   CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID

   MqlCalendarCountry country; //--- Declare country structure
   CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID

   MqlCalendarValue value; //--- Declare calendar value structure
   CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values
   
   //--- Check if the event’s currency matches any in the filter array (if the filter is enabled)
   bool currencyMatch = false;
   if (enableCurrencyFilter) {
      for (int j = 0; j < ArraySize(curr_filter); j++) {
         if (country.currency == curr_filter[j]) {
            currencyMatch = true;
            break;
         }
      }
      
      //--- If no match found, skip to the next event
      if (!currencyMatch) {
         continue;
      }
   }
   
   //--- Check importance level if importance filter is enabled
   bool importanceMatch = false;
   if (enableImportanceFilter) {
      for (int k = 0; k < ArraySize(allowed_importance_levels); k++) {
         if (event.importance == allowed_importance_levels[k]) {
            importanceMatch = true;
            break;
         }
      }
      
      //--- If importance does not match the filter criteria, skip the event
      if (!importanceMatch) {
         continue;
      }
   }
   
   //--- Apply time filter and set timeMatch flag (if the filter is enabled)
   bool timeMatch = false;
   if (enableTimeFilter) {
      datetime eventTime = values[i].time;
      
      if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) {
         timeMatch = true;  //--- Event is already released
      }
      else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) {
         timeMatch = true;  //--- Event is yet to be released
      }
      
      //--- Skip if the event doesn't match the time filter
      if (!timeMatch) {
         continue;
      }
   }
   
   //--- If we reach here, the currency matches the filter
   news_filter_count++; //--- Increment the count of filtered events
   
   //--- Set alternating colors for each data row holder
   color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite;
      
   //--- Loop through calendar data columns
   for (int k=0; k<ArraySize(array_calendar); k++){
         
      //--- Print event details for debugging
      //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time);
   
      //--- Skip event if currency does not match the selected country code
      // if (StringFind(_Symbol,country.currency) < 0) continue;
   
      //--- Prepare news data array with time, country, and other event details
      string news_data[ArraySize(array_calendar)];
      news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
      news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
      news_data[2] = country.currency; //--- Event country currency
   
      //--- Determine importance color based on event impact
      color importance_color = clrBlack;
      if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
      else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
      else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
   
      //--- Set importance symbol for the event
      news_data[3] = ShortToString(0x25CF);
   
      //--- Set event name in the data array
      news_data[4] = event.name;
         
      //--- Populate actual, forecast, and previous values in the news data array
      news_data[5] = DoubleToString(value.GetActualValue(),3);
      news_data[6] = DoubleToString(value.GetForecastValue(),3);
      news_data[7] = DoubleToString(value.GetPreviousValue(),3);
   }
   
   ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
   current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
  
}   
//Print("Final News = ",news_filter_count);
updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(),
           TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
           IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));

Este es solo el fragmento de código anterior que utilizamos durante la sección de inicialización, pero lo necesitamos en cada tick para obtener las actualizaciones. Sin embargo, lo repasaremos brevemente. Nos centramos en actualizar dinámicamente el panel de control con las últimas noticias económicas en cada tick y, para lograrlo, optimizamos la lógica eliminando la creación de objetos gráficos y, en su lugar, nos concentramos en gestionar los datos de los eventos de manera eficiente. Comenzamos definiendo variables para realizar un seguimiento del recuento total de noticias y filtrar criterios como la moneda, la importancia y los intervalos de tiempo. Estos filtros garantizan que solo se tengan en cuenta los eventos relevantes para su posterior procesamiento.

Recorremos los valores del calendario recuperados, aplicando los filtros para identificar los eventos que coinciden con las condiciones especificadas. Para cada evento coincidente, extraemos detalles clave como el nombre del evento, la hora, la moneda y el nivel de importancia. Estos detalles se almacenan en la matriz «current_eventNames_data», cuyo tamaño se modifica dinámicamente para dar cabida a nuevas entradas. Esta matriz es crucial para el seguimiento de los eventos y nos permite identificar los cambios entre los ticks comparándolos con los datos anteriores. Por último, actualizamos la etiqueta del panel para reflejar el total de eventos filtrados y la hora actual del servidor, lo que garantiza que el panel siempre refleje los datos de eventos más recientes sin crear objetos innecesarios. Este enfoque captura y actualiza de manera eficiente la información sobre noticias económicas en tiempo real.

A continuación, debemos realizar un seguimiento de si se producen cambios en las matrices de almacenamiento utilizando los datos recién adquiridos. Para ello, utilizamos una función personalizada.

//+------------------------------------------------------------------+
//|   Function to compare two string arrays and detect changes       |
//+------------------------------------------------------------------+
bool isChangeInStringArrays(string &arr1[], string &arr2[]) {
   bool isChange = false;
   
   int size1 = ArraySize(arr1);  // Get the size of the first array
   int size2 = ArraySize(arr2);  // Get the size of the second array
   
   // Check if sizes are different
   if (size1 != size2) {
      Print("Arrays have different sizes. Size of Array 1: ", size1, ", Size of Array 2: ", size2);
      isChange = true;
      return (isChange);
   }

   // Loop through the arrays and compare corresponding elements
   for (int i = 0; i < size1; i++) {
      // Compare the strings at the same index in both arrays
      if (StringCompare(arr1[i], arr2[i]) != 0) {  // If strings are different
         // Action when strings differ at the same index
         Print("Change detected at index ", i, ": '", arr1[i], "' vs '", arr2[i], "'");
         isChange = true;
         return (isChange);
      }
   }

   // If no differences are found, you can also log this as no changes detected
   //Print("No changes detected between arrays.");
   return (isChange);
}

Aquí definimos la función booleana «isChangeInStringArrays», que compara dos matrices de cadenas, «arr1» y «arr2», para detectar cualquier cambio entre ellas. Comenzamos determinando los tamaños de ambas matrices utilizando la función ArraySize y almacenamos estos tamaños en «size1» y «size2». Si los tamaños de las matrices difieren, imprimimos los tamaños respectivos, establecemos el indicador «isChange» en verdadero y devolvemos verdadero, lo que indica un cambio. Si los tamaños son iguales, procedemos a comparar los elementos de las matrices utilizando un bucle for. Para cada índice, utilizamos la función StringCompare para comprobar si las cadenas (strings) de ambos matrices son idénticas. Si alguna cadena difiere, imprimimos los detalles del cambio y establecemos «isChange» en verdadero, devolviendo verdadero para indicar la actualización. Si no se encuentran diferencias después del bucle, la función devuelve falso, lo que indica que no hay cambios. Este enfoque es esencial para detectar actualizaciones, como noticias nuevas o actualizadas, que debemos reflejar en el panel de control.

Una vez que contamos con la función, podemos utilizarla para actualizar los eventos.

if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){
   Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES");
   
   ObjectsDeleteAll(0,DATA_HOLDERS);
   ObjectsDeleteAll(0,ARRAY_NEWS);
   
   ArrayFree(current_eventNames_data);

   //---

}

Aquí, comprobamos si ha habido algún cambio entre las matrices «previous_eventNames_data» y «current_eventNames_data» llamando a la función «isChangeInStringArrays». Si la función devuelve verdadero, lo que indica que se han detectado cambios, imprimimos el mensaje «CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES». A continuación, eliminamos todos los objetos relacionados con los contenedores de datos y las matrices de noticias del gráfico utilizando la función ObjectsDeleteAll, especificando los identificadores «DATA_HOLDERS» y «ARRAY_NEWS» como prefijos de los objetos. Hacemos esto para eliminar cualquier información obsoleta antes de actualizar el panel de control con los datos más recientes del evento. Por último, liberamos la memoria utilizada por la matriz «current_eventNames_data» utilizando la función ArrayFree, asegurándonos de que la matriz se borra en preparación para la próxima actualización. A continuación, actualizamos los datos de los eventos como de costumbre, pero esta vez creamos los contenedores de datos y actualizamos los eventos de noticias en el nuevo panel de control. Esta es la lógica:

if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){
   Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES");
   
   ObjectsDeleteAll(0,DATA_HOLDERS);
   ObjectsDeleteAll(0,ARRAY_NEWS);
   
   ArrayFree(current_eventNames_data);
   
   //--- Initialize starting y-coordinate for displaying news data
   int startY = 162;
   //--- Loop through each calendar value up to the maximum defined total
   for (int i = 0; i < valuesTotal; i++){
   
      MqlCalendarEvent event; //--- Declare event structure
      CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID
   
      MqlCalendarCountry country; //--- Declare country structure
      CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID

      MqlCalendarValue value; //--- Declare calendar value structure
      CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values
      
      //--- Check if the event’s currency matches any in the filter array (if the filter is enabled)
      bool currencyMatch = false;
      if (enableCurrencyFilter) {
         for (int j = 0; j < ArraySize(curr_filter); j++) {
            if (country.currency == curr_filter[j]) {
               currencyMatch = true;
               break;
            }
         }
         
         //--- If no match found, skip to the next event
         if (!currencyMatch) {
            continue;
         }
      }
      
      //--- Check importance level if importance filter is enabled
      bool importanceMatch = false;
      if (enableImportanceFilter) {
         for (int k = 0; k < ArraySize(allowed_importance_levels); k++) {
            if (event.importance == allowed_importance_levels[k]) {
               importanceMatch = true;
               break;
            }
         }
         
         //--- If importance does not match the filter criteria, skip the event
         if (!importanceMatch) {
            continue;
         }
      }
      
      //--- Apply time filter and set timeMatch flag (if the filter is enabled)
      bool timeMatch = false;
      if (enableTimeFilter) {
         datetime eventTime = values[i].time;
         
         if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) {
            timeMatch = true;  //--- Event is already released
         }
         else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) {
            timeMatch = true;  //--- Event is yet to be released
         }
         
         //--- Skip if the event doesn't match the time filter
         if (!timeMatch) {
            continue;
         }
      }
         
      //--- If we reach here, the currency matches the filter
      news_filter_count++; //--- Increment the count of filtered events
      
      //--- Set alternating colors for each data row holder
      color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite;
   
      //--- Create rectangle label for each data row holder
      createRecLabel(DATA_HOLDERS+string(news_filter_count),62,startY-1,716,26+1,holder_color,1,clrNONE);
   
      //--- Initialize starting x-coordinate for each data entry
      int startX = 65;
      
      //--- Loop through calendar data columns
      for (int k=0; k<ArraySize(array_calendar); k++){
            
         //--- Print event details for debugging
         //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time);
      
         //--- Skip event if currency does not match the selected country code
         // if (StringFind(_Symbol,country.currency) < 0) continue;
      
         //--- Prepare news data array with time, country, and other event details
         string news_data[ArraySize(array_calendar)];
         news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
         news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
         news_data[2] = country.currency; //--- Event country currency
      
         //--- Determine importance color based on event impact
         color importance_color = clrBlack;
         if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
         else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
         else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
      
         //--- Set importance symbol for the event
         news_data[3] = ShortToString(0x25CF);
      
         //--- Set event name in the data array
         news_data[4] = event.name;
            
         //--- Populate actual, forecast, and previous values in the news data array
         news_data[5] = DoubleToString(value.GetActualValue(),3);
         news_data[6] = DoubleToString(value.GetForecastValue(),3);
         news_data[7] = DoubleToString(value.GetPreviousValue(),3);         
         
         //--- Create label for each news data item
         if (k == 3){
            createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY-(22-12),news_data[k],importance_color,22,"Calibri");
         }
         else {
            createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY,news_data[k],clrBlack,12,"Calibri");
         }
      
         //--- Increment x-coordinate for the next column
         startX += buttons[k]+3;
      }
      
      ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
      current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
      
      //--- Increment y-coordinate for the next row of data
      startY += 25;
      //Print(startY); //--- Print current y-coordinate for debugging
   }
   
   Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
   ArrayPrint(current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data);
   ArrayFree(previous_eventNames_data);
   ArrayCopy(previous_eventNames_data,current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data);
   
}

Aquí actualizamos el panel de control basándonos en los datos recién adquiridos para garantizar que las actualizaciones en tiempo real surtan efecto. Utilizando la lógica de copia, registramos los datos en el contenedor de datos «anterior» para poder utilizar los datos actuales en la siguiente comprobación. Hemos destacado la lógica que se encarga de eso, pero analicémosla más a fondo.

Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);
ArrayFree(previous_eventNames_data);
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

Aquí, comenzamos imprimiendo el tamaño actual de la matriz «current_eventNames_data» utilizando la función ArraySize y mostrando su contenido con la función ArrayPrint. Esto nos ayudará a inspeccionar el conjunto actual de nombres de eventos que estamos rastreando. A continuación, imprimimos el tamaño de la matriz «previous_eventNames_data» antes de que se actualice, seguido de la impresión de su contenido.

A continuación, liberamos la memoria utilizada por «previous_eventNames_data» con la función ArrayFree, asegurándonos de que se borren todos los datos anteriores almacenados en la matriz para evitar problemas de memoria. Después de liberar la memoria, utilizamos la función ArrayCopy para copiar el contenido de la matriz «current_eventNames_data» en «previous_eventNames_data», actualizándola efectivamente con los nombres de los eventos más recientes.

Por último, imprimimos el tamaño actualizado de la matriz «previous_eventNames_data» y su contenido para confirmar que la matriz ahora contiene los nombres de los eventos más recientes. Esto garantiza que los nombres de los eventos anteriores se actualicen correctamente para futuras comparaciones. Al ejecutar el programa, obtenemos el siguiente resultado.

Actualizaciones de tiempo.

ACTUALIZACIONES DE TIEMPO (GIF)

Actualización de eventos.

ACTUALIZACIÓN DE EVENTOS

Actualización del panel de control.

ACTUALIZACIÓN DEL PANEL DE CONTROL

En la imagen podemos ver que los datos recién registrados se actualizan con precisión en el panel de control. Para reconfirmar esto, podemos esperar nuevamente un tiempo e intentar ver si podemos realizar un seguimiento de estos datos, y con el que registra los datos actualizados. Aquí está el resultado.

Actualización de datos de eventos.

ACTUALIZACIÓN DE DATOS DE NUEVOS EVENTOS

Actualización del panel de control.

NUEVA ACTUALIZACIÓN DEL PANEL DE CONTROL

En la imagen podemos ver que, una vez que se producen cambios con respecto a los datos almacenados anteriormente, estos se detectan y actualizan de acuerdo con los datos recién registrados y se almacenan para su futura consulta. Los datos almacenados se utilizan para actualizar la interfaz del panel de control en tiempo real, mostrando las noticias de actualidad y confirmando así el éxito de nuestro objetivo.


Conclusión

En conclusión, hemos implementado un sistema robusto para supervisar y detectar cambios en los eventos del Calendario económico de MQL5 comparando los datos de eventos almacenados previamente con las actualizaciones recién recuperadas. Este mecanismo de comparación garantiza que cualquier diferencia en los nombres o detalles de los eventos se identifique rápidamente, lo que activa la actualización de nuestro panel de control para mantener la precisión y la relevancia. Al filtrar los datos según la moneda, la importancia y el tiempo, perfeccionamos aún más el proceso para centrarnos en los eventos más impactantes, al tiempo que actualizamos dinámicamente la interfaz.

En las próximas partes de esta serie, partiremos de esta base para integrar las noticias económicas en las estrategias de negociación, lo que permitirá aplicaciones prácticas de los datos. Además, nuestro objetivo es mejorar la funcionalidad del panel de control introduciendo movilidad y capacidad de respuesta, lo que garantizará una experiencia más fluida e interactiva para los operadores. Manténgase al tanto.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16386

Archivos adjuntos |
Stanislav Korotky
Stanislav Korotky | 3 dic 2024 en 20:57
Los usuarios probablemente estarán interesados en saber que los mismos temas se han cubierto a fondo en el libro de algotrading (y el sitio no muestra esto de alguna manera en las sugerencias automáticas), incluyendo el seguimiento y guardado de los cambios de eventos, filtrado de eventos por múltiples condiciones (con diferentes operadores lógicos) para el conjunto ampliado de campos, la visualización personalizable sobre la marcha subconjunto calendario en un panel en el gráfico, y la incrustación para el comercio en EAs con el apoyo de la transferencia de archivo completo del calendario en el probador.
Allan Munene Mutiiria
Allan Munene Mutiiria | 5 dic 2024 en 00:08
Stanislav Korotky #:
Los usuarios probablemente estarán interesados en saber que los mismos temas se han cubierto a fondo en el libro de algotrading (y el sitio no muestra esto de alguna manera en las sugerencias automáticas), incluyendo el seguimiento y guardado de los cambios de eventos, filtrado de eventos por múltiples condiciones (con diferentes operadores lógicos) para el conjunto ampliado de campos, la visualización personalizable sobre la marcha subconjunto calendario en un panel en el gráfico, y la incrustación para el comercio en EAs con el apoyo de la transferencia de archivo completo del calendario en el probador.
De acuerdo. Gracias.
Métodos de discretización de los movimientos de precios en Python Métodos de discretización de los movimientos de precios en Python
Hoy analizaremos varios métodos de discretización de precios en Python + MQL5. En este artículo compartiré mi experiencia práctica en el desarrollo de una biblioteca Python que implementa toda una gama de enfoques para la formación de barras: desde las clásicas Volume y Range bars hasta métodos más exóticos como Renko y Kagi, velas de ruptura de tres líneas, barras de Rango; ¿cuáles son sus estadísticas, de qué otra forma se pueden representar los precios de forma discreta?
Utilización del modelo de aprendizaje automático CatBoost como filtro para estrategias de seguimiento de tendencias Utilización del modelo de aprendizaje automático CatBoost como filtro para estrategias de seguimiento de tendencias
CatBoost es un potente modelo de aprendizaje automático basado en árboles que se especializa en la toma de decisiones basada en características estacionarias. Otros modelos basados en árboles, como XGBoost y Random Forest, comparten características similares en cuanto a su solidez, capacidad para manejar patrones complejos e interpretabilidad. Estos modelos tienen una amplia gama de usos, desde el análisis de características hasta la gestión de riesgos. En este artículo, vamos a explicar el procedimiento para utilizar un modelo CatBoost entrenado como filtro para una estrategia clásica de seguimiento de tendencias con cruce de medias móviles.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 3): Asesor Experto Analytics Master Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 3): Asesor Experto Analytics Master
Pasar de un simple script de trading a un Asesor Experto (EA) totalmente funcional puede mejorar significativamente su experiencia de trading. Imagina tener un sistema que supervisa automáticamente tus gráficos, realiza cálculos esenciales en segundo plano y proporciona actualizaciones periódicas cada dos horas. Este EA estaría equipado para analizar métricas clave que son cruciales para tomar decisiones comerciales informadas, lo que garantiza que usted tenga acceso a la información más actualizada para ajustar sus estrategias de manera eficaz.