Deutsch 日本語
preview
Trading with the MQL5 Economic Calendar (Part 4): Implementing Real-Time News Updates in the Dashboard

Trading with the MQL5 Economic Calendar (Part 4): Implementing Real-Time News Updates in the Dashboard

MetaTrader 5Trading | 3 December 2024, 11:22
2 067 2
Allan Munene Mutiiria
Allan Munene Mutiiria

Introduction

In this article, we advance our work on the MetaQuotes Language 5 (MQL5) Economic Calendar dashboard by adding functionality for live updates, allowing us to maintain a continuously refreshed display of critical economic news events. In the previous part, we designed and implemented a dashboard panel to filter news based on currency, importance, and time, giving us a tailored view of relevant events. Now, we take it further by enabling real-time updates, ensuring that our calendar displays the latest data for timely decision-making. The topics we will cover include:

  1. Implementing Real-Time News Updates in MQL5
  2. Conclusion

This enhancement will transform our dashboard into a dynamic, real-time tool continuously updated with the latest economic events. By implementing live refresh functionality, we will ensure that our calendar remains accurate and relevant, supporting timely trading decisions in MetaTrader 5 or the trading terminal.


Implementing Real-Time News Updates in MQL5

To implement live updates for our dashboard, we need to ensure that news events are stored and compared periodically to detect any changes. This requires maintaining arrays to hold current and previous event data, enabling us to identify updates and reflect them accurately on the dashboard. By doing so, we can ensure that the dashboard dynamically adjusts to display the most recent economic events in real-time. Below, we define the arrays that we will use for this purpose:

string current_eventNames_data[];
string previous_eventNames_data[];

Here, we define two string arrays, "current_eventNames_data" and "previous_eventNames_data", which we will use to manage and compare economic event data for live updates to the dashboard. The array "current_eventNames_data" will store the latest events retrieved from the economic calendar, while "previous_eventNames_data" will hold the data from the last update cycle. By comparing these two arrays, we can identify any changes or new additions to the events, allowing us to update the dashboard dynamically.

Using these arrays, we will need to get the current values on every event selected in the initialization section and store them in the current data holder array, and then later on copy them into the previous holder, which we will use to make the comparison on the next price tick.

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

Here, we dynamically expand the "current_eventNames_data" array and add a new event name to it. We use the function ArrayResize to increase the size of the array by one, making space for a new entry. After resizing, we assign the event's name to the last index of the array using the expression "current_eventNames_data[ArraySize(current_eventNames_data)-1]". This process ensures that each new event name retrieved from the economic calendar is stored in the array, enabling us to maintain an up-to-date list of events for further processing and comparison.

However, before adding the events to the array, we need to ensure that we start fresh, meaning that we need an empty array.

ArrayFree(current_eventNames_data);

Here, we use the ArrayFree function to clear all elements from the "current_eventNames_data" array, effectively resetting it to an empty state. This is essential for ensuring that the array does not retain outdated data from previous iterations, thus preparing it to store a fresh set of event names during the processing cycle. After filling the array, we then need to copy it into the previous holder and use it later to make the comparison.

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);

Here, we log and manage the transition of data between the "current_eventNames_data" and "previous_eventNames_data" arrays. First, we use the Print function to display the size of the "current_eventNames_data" array, providing visibility into the number of event names stored at that moment. We then call the ArrayPrint function to output the array's contents for further verification. Next, we log the size of the "previous_eventNames_data" array before copying, giving us a baseline for comparison.

Using the ArrayCopy function, we copy the contents of "current_eventNames_data" into "previous_eventNames_data", effectively transferring the latest event names for future comparisons. We then print the size of the "previous_eventNames_data" array after the copy operation to confirm the successful update. Finally, we call the ArrayPrint function to output the updated contents of "previous_eventNames_data", ensuring that the data transfer is accurate and complete. Those are the changes that we need on the OnInit event handler to store the initial events. Let us highlight them for clarity.

//+------------------------------------------------------------------+
//| 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);
}

Here, we just have made the changes that will help us get the initial event data. We have highlighted them in yellow color for clarity. Next, we just need to update the dashboard values when there are changes detected during comparison. For this, we will create a custom function that will contain all the logic for the event updates and dashboard recalculation, respectively.

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

//---

}

Here, we define the "update_dashboard_values" function, which we will use to handle the dynamic updating of the economic calendar dashboard. This function will contain the core logic for comparing stored news data, identifying any changes, and applying the necessary updates to the dashboard interface. By organizing this functionality into this dedicated function, we will ensure a clean and modular code structure, making future modifications or enhancements easier to manage. Next, we will call the function on the OnTick event handler as follows.

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

Here, we just call the custom function on every tick to do the updates. Upon compilation and running of the program, we have the following results:

INITIALIZATION ARRAYS DATA

From the image, we can see that we gather all the news events into the "current" array, which we then copy into the fresh "previous" array for storage, which perfectly aligns with what we want. We can now proceed to use these copied data for further analysis. In the function, we just get the current events as follows:

//--- 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));

This is just the prior code snippet code that we used during the initialization section, but we need it on every tick to get the updates. We will however go via it briefly. We focus on dynamically updating the dashboard with the latest economic news events on every tick, and to achieve this, we streamline the logic by removing the creation of graphical objects and instead concentrate on managing event data efficiently. We begin by defining variables to track the total news count and filter criteria such as currency, importance, and time ranges. These filters ensure that only relevant events are considered for further processing.

We loop through the retrieved calendar values, applying the filters to identify events that match the specified conditions. For each matching event, we extract key details like the event name, time, currency, and importance level. These details are stored in the "current_eventNames_data" array, which is resized dynamically to accommodate new entries. This array is crucial for tracking the events and allows us to identify changes between ticks by comparing them with previous data. Finally, we update the dashboard label to reflect the total filtered events and current server time, ensuring the dashboard always reflects the latest event data without creating unnecessary objects. This approach efficiently captures and updates the economic news information in real-time.

Next, we need to track if there are changes in the storage arrays using the newly acquired data. To do this, we use a custom function.

//+------------------------------------------------------------------+
//|   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);
}

Here, we define the boolean function "isChangeInStringArrays", which compares two string arrays, "arr1" and "arr2", to detect any changes between them. We begin by determining the sizes of both arrays using the ArraySize function and store these sizes in "size1" and "size2". If the sizes of the arrays differ, we print the respective sizes, set the "isChange" flag to true, and return true, indicating a change. If the sizes are the same, we proceed to compare the elements of the arrays using a for loop. For each index, we use the StringCompare function to check if the strings in both arrays are identical. If any strings differ, we print the details of the change and set "isChange" to true, returning true to signal the update. If no differences are found after the loop, the function returns false, indicating that there are no changes. This approach is essential for detecting updates, such as new or updated news events, which we need to reflect on the dashboard.

Armed with the function, we can then use it to update the events.

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);

   //---

}

Here, we check if there has been any change between the "previous_eventNames_data" and "current_eventNames_data" arrays by calling the "isChangeInStringArrays" function. If the function returns true, indicating that changes have been detected, we print a message "CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES". Following this, we delete all objects related to data holders and news arrays on the chart using the ObjectsDeleteAll function, specifying the identifiers "DATA_HOLDERS" and "ARRAY_NEWS" as the object prefixes. We do this to clear up any outdated information before updating the dashboard with the latest event data. Finally, we free the memory used by the "current_eventNames_data" array using the ArrayFree function, ensuring that the array is cleared in preparation for the next update. Following this, we update the events data as usual, but this time round, create the data holders and update the news events on the fresh dashboard. Here is the logic.

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);
   
}

Here, we update the dashboard based on the newly acquired data to ensure there are live updates taking effect. Using copy logic, we log the data into the "previous" data holder so that we can use the current data on the next check. We have highlighted the logic that takes care of that, but let us have a deeper look at it.

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);

Here, we begin by printing the current size of the "current_eventNames_data" array using the ArraySize function and displaying its contents with the ArrayPrint function. This will help us inspect the current set of event names that we are tracking. Then, we print the size of the "previous_eventNames_data" array before it is updated, followed by printing its contents.

Next, we free the memory used by "previous_eventNames_data" with the ArrayFree function, ensuring any previous data stored in the array is cleared to avoid memory issues. After freeing the memory, we use the ArrayCopy function to copy the contents of the "current_eventNames_data" array into "previous_eventNames_data", effectively updating it with the latest event names.

Finally, we print the updated size of the "previous_eventNames_data" array and its contents to confirm that the array now holds the most recent event names. This ensures that the previous event names are correctly updated for future comparison. Upon running the program, we have the following outcome.

Time updates.

TIME UPDATES GIF

Events update.

EVENTS UPDATE

Dashboard update.

DASHBOARD UPDATE

From the image, we can see that the newly registered data is accurately updated on the dashboard. To reconfirm this, we can wait again for some time and try to see of we can keep track of this data, and with the one that logs the updated data. Here is the outcome.

Events data update.

NEW EVENTS DATA UPDATE

Dashboard update.

NEW DASHBOARD UPDATE

From the image, we can see that once there are changes from the previously stored data, they are detected and updated according to the newly registered data and stored for further reference. The stored data is the used to update the dashboard interface in real time, displaying the current news events, and thus confirming the success of our objective.


Conclusion

In conclusion, we implemented a robust system to monitor and detect changes in MQL5 Economic News events by comparing previously stored event data with newly retrieved updates. This comparison mechanism ensures that any differences in event names or details are promptly identified, triggering our dashboard refresh to maintain accuracy and relevance. By filtering data based on currency, importance, and time, we further refined the process to focus on impactful events while dynamically updating the interface.

In the next parts of this series, we will build on this foundation by integrating economic news events into trading strategies, enabling practical applications of the data. Additionally, we aim to enhance the dashboard's functionality by introducing mobility and responsiveness, ensuring a more seamless and interactive experience for traders. Keep tuned.

Attached files |
Last comments | Go to discussion (2)
Stanislav Korotky
Stanislav Korotky | 3 Dec 2024 at 20:57
Users will probably be interested to know that the same topics have been covered thoroughly in the algotrading book (and the site does not show this somehow in automatic suggestions), including tracking and saving event changes, filtering events by multiple conditions (with different logical operators) for extended set of fields, displaying customizable on-the-fly calendar subset in a panel on chart, and embedding for trading into EAs with support of transferring complete archive of the calendar into the tester.
Allan Munene Mutiiria
Allan Munene Mutiiria | 5 Dec 2024 at 00:08
Stanislav Korotky #:
Users will probably be interested to know that the same topics have been covered thoroughly in the algotrading book (and the site does not show this somehow in automatic suggestions), including tracking and saving event changes, filtering events by multiple conditions (with different logical operators) for extended set of fields, displaying customizable on-the-fly calendar subset in a panel on chart, and embedding for trading into EAs with support of transferring complete archive of the calendar into the tester.
Okay. Thanks. 
Introduction to MQL5 (Part 10): A Beginner's Guide to Working with Built-in Indicators in MQL5 Introduction to MQL5 (Part 10): A Beginner's Guide to Working with Built-in Indicators in MQL5
This article introduces working with built-in indicators in MQL5, focusing on creating an RSI-based Expert Advisor (EA) using a project-based approach. You'll learn to retrieve and utilize RSI values, handle liquidity sweeps, and enhance trade visualization using chart objects. Additionally, the article emphasizes effective risk management, including setting percentage-based risk, implementing risk-reward ratios, and applying risk modifications to secure profits.
Generative Adversarial Networks (GANs) for Synthetic Data in Financial Modeling (Part 1): Introduction to GANs and Synthetic Data in Financial Modeling Generative Adversarial Networks (GANs) for Synthetic Data in Financial Modeling (Part 1): Introduction to GANs and Synthetic Data in Financial Modeling
This article introduces traders to Generative Adversarial Networks (GANs) for generating Synthetic Financial data, addressing data limitations in model training. It covers GAN basics, python and MQL5 code implementations, and practical applications in finance, empowering traders to enhance model accuracy and robustness through synthetic data.
Chemical reaction optimization (CRO) algorithm (Part II): Assembling and results Chemical reaction optimization (CRO) algorithm (Part II): Assembling and results
In the second part, we will collect chemical operators into a single algorithm and present a detailed analysis of its results. Let's find out how the Chemical reaction optimization (CRO) method copes with solving complex problems on test functions.
Price Action Analysis Toolkit Development (Part 3): Analytics Master — EA Price Action Analysis Toolkit Development (Part 3): Analytics Master — EA
Moving from a simple trading script to a fully functioning Expert Advisor (EA) can significantly enhance your trading experience. Imagine having a system that automatically monitors your charts, performs essential calculations in the background, and provides regular updates every two hours. This EA would be equipped to analyze key metrics that are crucial for making informed trading decisions, ensuring that you have access to the most current information to adjust your strategies effectively.