Economic Calendar News Indicator for MT5

Author: Roberto Jacobs (3rjfx) | Featured on Forex Home Expert

Introduction

In the fast-paced world of foreign exchange trading, staying ahead of market-moving events is not just an advantage—it is a necessity. For traders who rely on technical analysis and price action, sudden volatility caused by unexpected macroeconomic announcements can be both an opportunity and a risk.
The ability to anticipate these moments separates successful day trading professionals from amateurs. This is where specialized tools like the Economic Calendar News (ECN) Indicator for MetaTrader 5 become indispensable components of a comprehensive trading strategy.

The ECN.mq5 indicator, developed specifically for the MQL5 environment, bridges the gap between fundamental data and technical charting.
By integrating real-time economic calendar data directly into your trading interface, it eliminates the need to constantly switch tabs or rely on external websites that may lag behind server time.
Whether you are executing a high-frequency momentum detection strategy or simply managing risk around major releases, this tool provides the clarity needed to navigate volatile markets.
In this comprehensive guide, we will dissect the architecture of this powerful indicator, exploring its core functions and demonstrating how it enhances forex analysis for traders of all experience levels.

Economic Calendar News Illustration Indicator for MT5
Figure 1: Economic Calendar News Illustration Indicator for MT5

1. Understanding Global Variables and Input Properties

The foundation of any robust MQL5 indicator lies in its configurability.
The ECN.mq5 script begins by defining a series of global variables and input properties that allow users to tailor the tool to their specific trading signals and workflow preferences.
These inputs serve as the control panel for the indicator, ensuring it operates efficiently without consuming unnecessary system resources.

At the top of the source code, we see the definition of custom enumerations such as YN (Yes/No), updmnt (Update Minutes), and almnt (Alert Minutes). These enums create user-friendly dropdown menus in the indicator settings.
For instance, the upev variable controls the update frequency of the event check, allowing traders to choose between 5, 10, or 15-minute intervals.
This is crucial for balancing accuracy with performance; checking every tick might be overkill for daily news, while checking every hour could miss critical intraday setups.

Furthermore, the alert system is highly customizable through inputs like alerts, UseEmailAlert, and UseSendnotify.
In modern forex strategy execution, receiving timely notifications is paramount. A trader focusing on macroeconomic events needs to know exactly when a high-impact release is imminent.
The albefore parameter allows users to set a pre-alert timer—ranging from 5 to 60 minutes before the actual news release.
This lead time is essential for preparing positions, tightening stop-losses, or stepping aside to avoid slippage during low-liquidity periods often associated with major news events.

The display_info boolean toggle determines whether the textual information is rendered directly on the chart window. For traders who practice pure price action, having visual clutter can be distracting.
However, for those who integrate fundamental bias into their technical approach, seeing the upcoming "Non-Farm Payrolls" or "CPI" release directly next to the candlesticks provides immediate context.
This seamless integration of data supports a holistic view of the market, combining the precision of technical analysis with the foresight of fundamental awareness.


//+------------------------------------------------------------------+
//|                                                          ECN.mq5 |
//|        Copyright 2026, Roberto Jacobs (3rjfx) ~ Date: 2026-06-26 |
//|                              https://www.mql5.com/en/users/3rjfx |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Roberto Jacobs (3rjfx) ~ Date: 2026-06-26"
#property link      "https://www.mql5.com/en/users/3rjfx"
#property version   "1.00"
//--
#property description "ECN indicator for MT5 is an Economic Calendar News Indicator"
#property description "that provides and displays relevant and influential macroeconomic"
#property description "indicator news directly on the MetaTrader 5 platform at the time"
#property description "of publication for 9 currencies: USD, EUR, GBP, AUD, NZD, CAD, CHF"
#property description "JPY and CNY, with Medium and High importance levels, accompanied by"
#property description "a system alert before the news is published."
//--
#property indicator_chart_window
#property indicator_plots   0
//---
//--
enum YN
 {
   No,
   Yes
 };
//--
enum updmnt
  {
    mn_05=5,   // 5 Minutes 
    mn_10=10,  // 10 Minutes
    mn_15=15   // 15 Minutes
  };
//--
enum almnt
  {
    amn_05=5,   // 5 Minutes 
    amn_10=10,  // 10 Minutes
    amn_15=15,  // 15 Minutes
    amn_20=20,  // 20 Minutes
    amn_30=30,  // 30 Minutes
    amn_60=60   // 60 Minutes
  };  
//--
//---
input updmnt           upev = mn_05;      // Select Update Event in minute
input YN             alerts = Yes;        // Display Alerts / Messages (Yes) or (No)
input YN      UseEmailAlert = No;         // Email Alert (Yes) or (No)
input YN      UseSendnotify = No;         // Send Notification (Yes) or (No)
input almnt        albefore = amn_15;     // Alert In Minutes Before News Event
input YN       display_info = Yes;        // Select Display Trading Info on Chart (Yes) or (No)
//---
//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

2. The Core Architecture: Class NewsEvent

Moving beyond simple scripts, the ECN indicator utilizes Object-Oriented Programming (OOP) principles through the class NewsEvent. This architectural choice is significant for maintaining clean, modular, and scalable code.
In the context of complex trading tools, encapsulating logic within a class prevents variable conflicts and makes the code easier to debug and extend.

The NewsEvent class acts as the central nervous system of the indicator.
It houses all the necessary member variables required to track time, manage arrays of currency codes, store event details, and handle alert states.
Variables such as year, mon, day, and hour are grouped together to facilitate easy time manipulation.
Similarly, the array CCurr[] stores the nine supported currencies (USD, EUR, GBP, AUD, NZD, CAD, CHF, JPY, CNY), ensuring that the indicator only processes relevant data for the pairs the trader is interested in.

By organizing the code into a class, the developer ensures that the state of the indicator is preserved across different function calls.
For example, the eLoop variable tracks whether the current calculation cycle has already processed the news list, preventing redundant drawing operations on every tick. This efficiency is vital for day trading environments where platform latency can impact execution.
The class structure also allows for virtual methods, meaning the indicator could theoretically be extended or inherited by other tools in a larger forex analysis suite without rewriting the core logic.


//+------------------------------------------------------------------+
//| Class for working Indicator                             |
//+------------------------------------------------------------------+
class NewsEvent
  {
//---
    public:
    //----
    int              year,         // Year 
                     mon,          // Month 
                     day,          // Day 
                     hour,         // Hour 
                     min,          // Minutes 
                     sec,          // Seconds 
                     dow,          // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
                     doy;          // Day number of the year (January 1st is assigned the number value of zero)
    //--
    int              cMin;
    int              pMin;
    int              eLoop;
    int              ArrCurr;
    int              MinAlert;
    int              TotalEvent;
    ENUM_CALENDAR_EVENT_IMPORTANCE              
                     Cal_Importance;
    //--
    datetime         prvTimeF;
    datetime         EventBefore;
    datetime         EventForward;
    datetime         EventStartTime;
    datetime         EventEndTime;
    //--
    string           CCurr[];
    string           CComm;
    string           PComm;
    string           ARemMin;
    string           ind_name;
    string           prvEventF;
    string           HeaderEvent;
    //--
                     NewsEvent(void);
                     ~NewsEvent(void);          
    //--
    virtual void     NewsEvent_Config(void);
    virtual void     HasNewsEvent(void);
    //--
    void             NewsInfo(string inevent);
    void             UpdateServerTime(void);
    void             ResetNewsInfo(void);
    void             Do_Alerts(const string symbx,string msgText,datetime tmrel);
    //--
    int              CurrIdxArray(const string currency);
    int              ThisTime(const int reqmode);
    //--
    string           CalendarEventImportance(ENUM_CALENDAR_EVENT_IMPORTANCE importance_set);
    string           CalendarEventImpactSet(ENUM_CALENDAR_EVENT_IMPACT impact_set);
    string           TF2Str(ENUM_TIMEFRAMES period);
    string           getUninitReasonText(int reasonCode);
    //---
//---
  }; //-end class NewsEvent
//---------//
 
NewsEvent ne;

//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

3. Initialization and Configuration Logic

Before the indicator can begin processing market data, it must be properly initialized. This process involves two critical functions: NewsEvent_Config() and OnInit().
These functions set the stage for all subsequent operations, establishing the parameters that define how the indicator interacts with the MetaTrader 5 terminal.

The NewsEvent_Config() method is responsible for setting up the internal state of the NewsEvent object.
Here, the importance threshold is defined using CALENDAR_IMPORTANCE_MODERATE, ensuring that only Medium and High impact events are displayed. This filtering is essential because low-importance news rarely generates enough volume to affect price action significantly.
The function also initializes the MinAlert variable based on the user's selected pre-alert time, converting minutes into seconds for precise comparison later.
Additionally, it constructs the header string for the on-chart display, creating a formatted table layout that will hold the news events.

The standard MQL5 OnInit() function serves as the entry point. When a trader attaches the ECN indicator to a chart, OnInit() is called immediately.
Its primary role in this script is to invoke ne.NewsEvent_Config(), thereby triggering the setup sequence described above. If this configuration fails or returns an error, the indicator would not load correctly.
Successful initialization ensures that all arrays are resized, default values are assigned, and the indicator is ready to receive data from the OnCalculate loop.
This separation of concerns—keeping configuration logic distinct from the main calculation loop—is a hallmark of professional MQL5 programming and contributes to the stability of the trading strategy implementation.

  
void NewsEvent::NewsEvent_Config(void)
  {
//---
    if(display_info==No) Comment("");
    //--
    Cal_Importance = CALENDAR_IMPORTANCE_MODERATE;
    //--
    eLoop=0;
    pMin=ThisTime(min);
    //--
    switch(albefore)
      {
        case amn_05: { MinAlert=PeriodSeconds(PERIOD_M5);  ARemMin="5 minutes left";  break; }
        case amn_10: { MinAlert=PeriodSeconds(PERIOD_M10); ARemMin="10 minutes left"; break; }
        case amn_15: { MinAlert=PeriodSeconds(PERIOD_M15); ARemMin="15 minutes left"; break; }
        case amn_20: { MinAlert=PeriodSeconds(PERIOD_M20); ARemMin="20 minutes left"; break; }
        case amn_30: { MinAlert=PeriodSeconds(PERIOD_M30); ARemMin="30 minutes left"; break; }
        case amn_60: { MinAlert=PeriodSeconds(PERIOD_H1);  ARemMin="60 minutes left"; break; }
      }
    //--
    string Ccurrency[]={"USD","AUD","EUR","GBP","NZD","CAD","CHF","JPY","CNY"};
    ArrCurr=ArraySize(Ccurrency);
    ArrayResize(CCurr,ArrCurr,ArrCurr);
    ArrayCopy(CCurr,Ccurrency,0,0,WHOLE_ARRAY);
    //--
    HeaderEvent="\n     ------------------------------------------------------------------------------------------------------------------------------------"+
                "\n     | Time  Currency  Importance   Impact        Event                                                            |"+
                "\n     ------------------------------------------------------------------------------------------------------------------------------------";
    CComm=HeaderEvent;                    
    //--
    return;
//---
  } //-end NewsEvent_Config()
//---------//

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
     ne.NewsEvent_Config();
     //--
     return(INIT_SUCCEEDED);
//---
  } //-end OnInit() 
//---------//  
***Copyright © 2026 3rjfx ~ For educational purposes only.***

4. The Calculation Loop: OnCalculate Function

The heartbeat of any indicator is the OnCalculate() function. In the ECN.mq5 script, this function is optimized to run efficiently without bogging down the terminal.
Unlike indicators that recalculate on every single price tick, the ECN indicator employs a time-based gating mechanism to reduce computational overhead.

Inside OnCalculate, the code checks the current minute against the user-defined update interval (upev). Using the modulo operator (fmod), it determines if the current minute is a multiple of the selected interval (e.g., every 5 minutes). Only when this condition is met does the variable ne.cMin update.
Subsequently, the code compares ne.cMin with the previous minute value (ne.pMin).
If they differ, it signifies that a new update cycle has begun, triggering ne.ResetNewsInfo() to clear old data and prepare for fresh retrieval.

This intelligent throttling is particularly beneficial for traders running multiple charts or engaging in resource-intensive momentum detection strategies.
By limiting the frequency of calendar queries, the indicator preserves CPU cycles for order execution and chart rendering. Once the time gate opens, ne.HasNewsEvent() is called to fetch and process the latest economic data.
This structured approach ensures that the economic calendar news displayed is always current but never overwhelming, providing a smooth user experience that aligns with the demands of professional forex analysis.


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t rates_total,
                const int32_t prev_calculated,
                const int32_t begin,
                const double &price[])
  {
//---
    int curMin=ne.ThisTime(ne.min);
    if(fmod((double)curMin,(double)upev)==0.0) ne.cMin=curMin;
    if(ne.cMin!=ne.pMin) ne.ResetNewsInfo();
    //--
    ne.HasNewsEvent();
    //--
//--- return value of prev_calculated for next call
   return(rates_total);
//---
  } //-end OnCalculate()
//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

5. Data Retrieval and Event Processing

The core intelligence of the ECN indicator resides in the HasNewsEvent(void) method. This function is responsible for querying the MQL5 Economic Calendar API and filtering the results to match the trader's criteria.
It begins by defining a time window for the current day using iTime(Symbol(), PERIOD_D1, 0) and adding one day's worth of seconds.
This ensures that only today's events are considered, keeping the display relevant.

The function utilizes CalendarValueHistory() to retrieve an array of MqlCalendarValue structures. It then iterates through each event, fetching detailed information via CalendarEventById() and country-specific data via CalendarCountryById().
A nested loop checks if the event's currency matches any of the nine supported currencies stored in the CCurr array. Crucially, it also verifies that the event's importance meets or exceeds the configured threshold (Cal_Importance).

For matching events, the function determines the visual status. Events that have already passed are marked with a left arrow («), while upcoming events within the current day's window are marked with a right arrow (»).
Most importantly, this is where the alert logic triggers. If the current server time is exactly MinAlert seconds away from the event time, the Do_Alerts() function is executed.
This precise timing mechanism ensures that traders receive their trading signals regarding upcoming volatility exactly when they need them, allowing for proactive rather than reactive decision-making in their trading strategy.

  
void NewsEvent::HasNewsEvent(void)
  {
//---
    TotalEvent=0;
    //--
    EventStartTime = iTime(Symbol(),PERIOD_D1,0);
    EventEndTime   = EventStartTime + PeriodSeconds(PERIOD_D1); 
    //--
    MqlCalendarValue Cvalues[];
    //--
    TotalEvent = CalendarValueHistory(Cvalues,EventStartTime,EventEndTime,NULL,NULL);
    //--
    EventBefore  = EventStartTime;
    EventForward = EventEndTime;
    //Print("TotalEvent = "+(string)TotalEvent);
    //--
    for(int i=0; i<TotalEvent; i++)
      {
        MqlCalendarEvent event;
        CalendarEventById(Cvalues[i].event_id,event);
        //--
        MqlCalendarCountry country;
        CalendarCountryById(event.country_id,country);
        //--
        for(int x=0; x<ArrCurr; x++)
          {
            if(CurrIdxArray(country.currency)!=-1)
              {
                if(event.importance >= Cal_Importance)
                  {
                    //--
                    string CImport=CalendarEventImportance(event.importance);
                    if(country.currency=="JPY" && CImport=="Moderate") CImport=" "+CImport;
                    string Cimpact=CalendarEventImpactSet(Cvalues[i].impact_type);
                    string Carrow="";
                    //--
                    if(Cvalues[i].time >= EventBefore && Cvalues[i].time < TimeTradeServer()) { Carrow="    « "; }
                    if(Cvalues[i].time >= TimeTradeServer() && Cvalues[i].time <= EventForward) 
                      {
                        Carrow="    » ";
                        if(alerts==Yes||UseEmailAlert==Yes||UseSendnotify==Yes)
                          {
                            string msginfo="New Event will be released soon, "+ARemMin+
                            "\n Currency = "+country.currency+" >> Importance = "+CImport+
                            "\n Event: "+event.name;
                            if(Cvalues[i].time - TimeTradeServer() == MinAlert)
                              Do_Alerts(Symbol(),msginfo,Cvalues[i].time);
                          }
                      }
                    //--
                    if(display_info == Yes && eLoop==0)
                      {
                         string FNevent=Carrow+TimeToString(Cvalues[i].time,TIME_MINUTES)+"    "+country.currency+"     "+
                               " "+CImport+"     "+Cimpact+"    "+event.name;
                         if(event.name!=prvEventF)
                           {
                             NewsInfo(FNevent);
                             prvEventF=event.name;
                             prvTimeF=Cvalues[i].time;
                           }
                         else break;
                      }
                    if(display_info == Yes && eLoop==1)
                      {
                        UpdateServerTime();
                      }
                  }
              }
          }
      }
    //--
    eLoop=1;
    //--
    return;
//---
  } //-end HasNewsEvent()
//---------//  
***Copyright © 2026 3rjfx ~ For educational purposes only.***

6. Visual Display and Information Management

Raw data is useless if it cannot be interpreted quickly. The ECN indicator excels in presenting complex macroeconomic information in a digestible format through the NewsInfo(string inevent) and UpdateServerTime() functions.
These methods handle the rendering of text directly onto the chart window, transforming abstract calendar entries into actionable visual cues.

The NewsInfo function appends formatted strings to the CComm variable, which acts as a buffer for the chart comment.
Each line includes the event time, currency code, importance level, impact type, and event name.Special formatting is applied to ensure alignment, making the list easy to scan at a glance.
For example, "Moderate" importance events for JPY are given extra spacing to maintain column integrity. This attention to detail reflects the high standards expected in professional technical analysis tools.

Complementing this is the UpdateServerTime() function, which prepends the current server date and time to the news list.
Knowing the exact server time is critical for synchronizing with broker feeds and understanding when "end of day" resets occur. Together, these functions create a dynamic dashboard that updates in real-time.
When the ResetNewsInfo() function is called at the start of a new update cycle, it clears the CComm buffer and restores the header, ensuring that stale data never lingers on the screen.
This continuous refresh cycle keeps the trader informed and focused on the present market conditions.

 
void NewsEvent::NewsInfo(string inevent) // function: write Event Info on the chart
  {
//---
   string CommInfo="";
   //--
   CommInfo=CommInfo+"\n "+inevent;
   //--
   CommInfo=CommInfo+"";
   CComm=CComm+CommInfo;
   PComm=CComm;
   //--
   Comment(CComm);
   ChartRedraw();
   //--
   return;
//---
  } //-end NewsInfo()  
//---------//

void NewsEvent::UpdateServerTime(void)
  {
//---
   string HeaderTime="     Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+
                                              "   "+TimeToString(TimeCurrent(),TIME_SECONDS);
   //--
   Comment(HeaderTime+PComm);
   ChartRedraw();
   //--
   return;
//---
  } //-end UpdateServerTime()  
//---------//

void NewsEvent::ResetNewsInfo(void)
  {
//---
   eLoop=0; 
   pMin=cMin;
   CComm=HeaderEvent;
   //--
   return;
//---
  } //-end ResetNewsInfo()  
//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

Using MT5 data for June 26, 2026, the Economic Calendar News Indicator for MT5 will appear as shown in the image below.

EURUSDH1_ECN_indicator_data_ecn_2026-06-26
Figure 2: Economic Calendar News Indicator appearance on MT5 chart

7. Alert Systems and Utility Functions

A key feature of the ECN indicator is its multi-channel alert system, managed by the Do_Alerts(...) function.
Recognizing that traders have different preferences for notifications, this function supports three distinct output methods: on-screen Alerts, Email notifications, and Push Notifications to mobile devices.
When a qualifying event approaches, the function constructs a detailed message string containing the symbol, timeframe, remaining time, currency, importance, and event name.

Beyond alerts, the indicator relies on several utility functions to maintain data integrity. The CurrIdxArray(const string currency) function performs a linear search through the supported currency array to validate if an event is relevant. While simple, this function is called frequently during the event processing loop, making its efficiency important.
Similarly, CalendarEventImportance(...) and CalendarImpactSet(...) translate numeric enum values into human-readable strings like "High," "Moderate," "Positive," or "Negative."
These translation layers are essential for making the raw API data accessible to traders who may not be familiar with MQL5 enumeration constants.

The ThisTime(const int reqmode) function serves as a centralized time accessor, returning specific components of the current time (year, month, day, hour, minute, second) based on a mode integer.This abstraction simplifies time handling throughout the class, reducing code duplication.
Finally, the getUninitReasonText(int reasonCode) function provides diagnostic feedback during deinitialization, helping developers and advanced users troubleshoot issues if the indicator stops unexpectedly.
Together, these utility functions form the supportive infrastructure that enables the indicator's primary features to operate reliably.

 
void NewsEvent::Do_Alerts(const string symbol,string msgText,datetime tmrel)
  {
//---
    //--
    Print(ind_name+"--- "+symbol+": "+msgText+
          "\n--- at: ",TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert(ind_name+"--- "+symbol+": "+msgText+
              "--- at: ",TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(ind_name,"--- "+symbol+" "+TF2Str(PERIOD_CURRENT)+": "+msgText+
                       "\n--- at: "+TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(ind_name+"--- "+symbol+" "+TF2Str(PERIOD_CURRENT)+": "+msgText+
                      "\n--- at: "+TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

Frequently Asked Questions (FAQ)

Q: Does the ECN indicator work on all currency pairs?

A: Yes, the indicator monitors news for nine major currencies: USD, EUR, GBP, AUD, NZD, CAD, CHF, JPY, and CNY. Since most forex pairs involve at least one of these currencies, the indicator is relevant for virtually all major and minor pair trading strategies.

Q: Can I customize the alert timing?

A: Absolutely. The albefore input parameter allows you to set alerts for 5, 10, 15, 20, 30, or 60 minutes before a news event. This flexibility helps you align alerts with your specific preparation routine for high-volatility periods.

Q: Does this indicator predict market direction?

A: No. The ECN indicator is an informational tool, not a predictive signal generator. It displays scheduled macroeconomic events and their historical importance. Traders must still apply their own forex analysis and trading strategy to interpret how these events might affect price.

Q: Will it slow down my MetaTrader 5 platform?

A: The indicator is optimized with a configurable update interval (default 5 minutes) to minimize resource usage. It only queries the calendar API at set intervals rather than on every tick, ensuring smooth performance even during active day trading sessions.

Q: Is the economic calendar data real-time?

A: Yes, the indicator uses the native MQL5 Economic Calendar API, which syncs with the MetaQuotes servers. This ensures that the news times and importance levels displayed are accurate and synchronized with your broker's server time.

Conclusion

The Economic Calendar News Indicator for MT5 represents a sophisticated fusion of fundamental data and technical convenience.
By automating the monitoring of high-impact macroeconomic events, it empowers traders to make more informed decisions without leaving their charts.
The thoughtful architecture—from the efficient OnCalculate loop to the versatile Do_Alerts system—demonstrates a deep understanding of the practical needs of modern forex traders.

Whether you are a seasoned professional refining a momentum detection system or a beginner learning to respect the power of news-driven volatility, the ECN.mq5 indicator offers valuable support.
It transforms the often chaotic flow of economic data into structured, actionable intelligence. As markets continue to evolve, tools that seamlessly integrate diverse information streams will remain essential for anyone serious about mastering the art and science of forex trading.
Download the ECN indicator today and elevate your trading strategy with precision-timed fundamental awareness.

⚠️ Important: Risk Disclaimer

  • Demo Testing: You are strongly advised to test this indicator on an MT5 Demo Account.
  • Real Account Trading: If you proceed to use this indicator for automated trading on a Real Account, you do so at your own risk. Algorithmic trading involves substantial risk to your capital.
  • Always remember the rules: Never trade with money you cannot afford to lose.
  • Trading foreign exchange on margin carries a high level of risk and may not be suitable for all investors. The high degree of leverage can work against you as well as for you. Before deciding to invest in foreign exchange, you should carefully consider your investment objectives, level of experience, and risk appetite.
  • The ECN indicator logic provided in this article are for educational purposes and do not guarantee profits. Past performance is not indicative of future results.
  • For more details, please read our full Risk Disclaimer and Terms of Service.

Vital Records

We hope that this article and the ECN or Economic Calendar News Indicator for MT5 program will be useful for traders in learning and generating new ideas, thereby will be able improving your trading performance.

If you think the Economic Calendar News Indicator for MT5 is worthy of being used for automated trading as an Expert Advisor, please leave a comment below this article.

If at least 25 people agree that this indicator is worthy of being used as an Expert Advisor, I will create an Expert Advisor based on its signals and share it on this blog.

Thanks for reading this article.

Explore more algorithmic trading resources:

Note: Please see the source program and download at the bottom of this article.

Risk Warning:
Trading Forex and CFDs involves significant risk and may not be suitable for all investors.
Trading in Forex and Contract for Difference (CFDs) entails a high risk of losing capital.
Before investing, always do your own research and never risk more than you can afford to lose.
All content provided is for educational purposes only and does not constitute financial advice.


//+------------------------------------------------------------------+
//|                                                          ECN.mq5 |
//|        Copyright 2026, Roberto Jacobs (3rjfx) ~ Date: 2026-06-26 |
//|                              https://www.mql5.com/en/users/3rjfx |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Roberto Jacobs (3rjfx) ~ Date: 2026-06-26"
#property link      "https://www.mql5.com/en/users/3rjfx"
#property version   "1.00"
//--
#property description "ECN indicator for MT5 is an Economic Calendar News Indicator"
#property description "that provides and displays relevant and influential macroeconomic"
#property description "indicator news directly on the MetaTrader 5 platform at the time"
#property description "of publication for 9 currencies: USD, EUR, GBP, AUD, NZD, CAD, CHF"
#property description "JPY and CNY, with Medium and High importance levels, accompanied by"
#property description "a system alert before the news is published."
//--
#property indicator_chart_window
#property indicator_plots   0
//---
//--
enum YN
 {
   No,
   Yes
 };
//--
enum updmnt
  {
    mn_05=5,   // 5 Minutes 
    mn_10=10,  // 10 Minutes
    mn_15=15   // 15 Minutes
  };
//--
enum almnt
  {
    amn_05=5,   // 5 Minutes 
    amn_10=10,  // 10 Minutes
    amn_15=15,  // 15 Minutes
    amn_20=20,  // 20 Minutes
    amn_30=30,  // 30 Minutes
    amn_60=60   // 60 Minutes
  };  
//--
//---
input updmnt           upev = mn_05;      // Select Update Event in minute
input YN             alerts = Yes;        // Display Alerts / Messages (Yes) or (No)
input YN      UseEmailAlert = No;         // Email Alert (Yes) or (No)
input YN      UseSendnotify = No;         // Send Notification (Yes) or (No)
input almnt        albefore = amn_15;     // Alert In Minutes Before News Event
input YN       display_info = Yes;        // Select Display Trading Info on Chart (Yes) or (No)
//---
//---------//
//+------------------------------------------------------------------+
//| Class for working Indicator                             |
//+------------------------------------------------------------------+
class NewsEvent
  {
//---
    public:
    //----
    int              year,         // Year 
                     mon,          // Month 
                     day,          // Day 
                     hour,         // Hour 
                     min,          // Minutes 
                     sec,          // Seconds 
                     dow,          // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
                     doy;          // Day number of the year (January 1st is assigned the number value of zero)
    //--
    int              cMin;
    int              pMin;
    int              eLoop;
    int              ArrCurr;
    int              MinAlert;
    int              TotalEvent;
    ENUM_CALENDAR_EVENT_IMPORTANCE              
                     Cal_Importance;
    //--
    datetime         prvTimeF;
    datetime         EventBefore;
    datetime         EventForward;
    datetime         EventStartTime;
    datetime         EventEndTime;
    //--
    string           CCurr[];
    string           CComm;
    string           PComm;
    string           ARemMin;
    string           ind_name;
    string           prvEventF;
    string           HeaderEvent;
    //--
                     NewsEvent(void);
                     ~NewsEvent(void);          
    //--
    virtual void     NewsEvent_Config(void);
    virtual void     HasNewsEvent(void);
    //--
    void             NewsInfo(string inevent);
    void             UpdateServerTime(void);
    void             ResetNewsInfo(void);
    void             Do_Alerts(const string symbx,string msgText,datetime tmrel);
    //--
    int              CurrIdxArray(const string currency);
    int              ThisTime(const int reqmode);
    //--
    string           CalendarEventImportance(ENUM_CALENDAR_EVENT_IMPORTANCE importance_set);
    string           CalendarEventImpactSet(ENUM_CALENDAR_EVENT_IMPACT impact_set);
    string           TF2Str(ENUM_TIMEFRAMES period);
    string           getUninitReasonText(int reasonCode);
    //---
//---
  }; //-end class NewsEvent
//---------//
 
NewsEvent ne;

//---------//

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
NewsEvent::NewsEvent(void):
                  year(0),
                  mon(1),
                  day(2),
                  hour(3),
                  min(4),
                  sec(5),
                  dow(6),
                  doy(7),
                  eLoop(0),
                  ind_name("ECN")
  {
  }
//---------//

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
NewsEvent::~NewsEvent(void)
  {
  }
//---------//

void NewsEvent::NewsEvent_Config(void)
  {
//---
    if(display_info==No) Comment("");
    //--
    Cal_Importance = CALENDAR_IMPORTANCE_MODERATE;
    //--
    eLoop=0;
    pMin=ThisTime(min);
    //--
    switch(albefore)
      {
        case amn_05: { MinAlert=PeriodSeconds(PERIOD_M5);  ARemMin="5 minutes left";  break; }
        case amn_10: { MinAlert=PeriodSeconds(PERIOD_M10); ARemMin="10 minutes left"; break; }
        case amn_15: { MinAlert=PeriodSeconds(PERIOD_M15); ARemMin="15 minutes left"; break; }
        case amn_20: { MinAlert=PeriodSeconds(PERIOD_M20); ARemMin="20 minutes left"; break; }
        case amn_30: { MinAlert=PeriodSeconds(PERIOD_M30); ARemMin="30 minutes left"; break; }
        case amn_60: { MinAlert=PeriodSeconds(PERIOD_H1);  ARemMin="60 minutes left"; break; }
      }
    //--
    string Ccurrency[]={"USD","AUD","EUR","GBP","NZD","CAD","CHF","JPY","CNY"};
    ArrCurr=ArraySize(Ccurrency);
    ArrayResize(CCurr,ArrCurr,ArrCurr);
    ArrayCopy(CCurr,Ccurrency,0,0,WHOLE_ARRAY);
    //--
    HeaderEvent="\n     ------------------------------------------------------------------------------------------------------------------------------------"+
                "\n     | Time  Currency  Importance   Impact        Event                                                            |"+
                "\n     ------------------------------------------------------------------------------------------------------------------------------------";
    CComm=HeaderEvent;                    
    //--
    return;
//---
  } //-end NewsEvent_Config()
//---------//

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
     ne.NewsEvent_Config();
     //--
     return(INIT_SUCCEEDED);
//---
  } //-end OnInit() 
//---------//
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//----
    Comment("");
    //--
    PrintFormat("%s: Deinitialization reason code=%d",__FUNCTION__,reason);
    Print(ne.getUninitReasonText(reason));
    //--
    return;
//---
  } //-end OnDeinit() 
//---------//
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t rates_total,
                const int32_t prev_calculated,
                const int32_t begin,
                const double &price[])
  {
//---
    int curMin=ne.ThisTime(ne.min);
    if(fmod((double)curMin,(double)upev)==0.0) ne.cMin=curMin;
    if(ne.cMin!=ne.pMin) ne.ResetNewsInfo();
    //--
    ne.HasNewsEvent();
    //--
//--- return value of prev_calculated for next call
   return(rates_total);
//---
  } //-end OnCalculate()
//---------//
//+------------------------------------------------------------------+

void NewsEvent::HasNewsEvent(void)
  {
//---
    TotalEvent=0;
    //--
    EventStartTime = iTime(Symbol(),PERIOD_D1,0);
    EventEndTime   = EventStartTime + PeriodSeconds(PERIOD_D1); 
    //--
    MqlCalendarValue Cvalues[];
    //--
    TotalEvent = CalendarValueHistory(Cvalues,EventStartTime,EventEndTime,NULL,NULL);
    //--
    EventBefore  = EventStartTime;
    EventForward = EventEndTime;
    //Print("TotalEvent = "+(string)TotalEvent);
    //--
    for(int i=0; i<TotalEvent; i++)
      {
        MqlCalendarEvent event;
        CalendarEventById(Cvalues[i].event_id,event);
        //--
        MqlCalendarCountry country;
        CalendarCountryById(event.country_id,country);
        //--
        for(int x=0; x<ArrCurr; x++)
          {
            if(CurrIdxArray(country.currency)!=-1)
              {
                if(event.importance >= Cal_Importance)
                  {
                    //--
                    string CImport=CalendarEventImportance(event.importance);
                    if(country.currency=="JPY" && CImport=="Moderate") CImport=" "+CImport;
                    string Cimpact=CalendarEventImpactSet(Cvalues[i].impact_type);
                    string Carrow="";
                    //--
                    if(Cvalues[i].time >= EventBefore && Cvalues[i].time < TimeTradeServer()) { Carrow="    « "; }
                    if(Cvalues[i].time >= TimeTradeServer() && Cvalues[i].time <= EventForward) 
                      {
                        Carrow="    » ";
                        if(alerts==Yes||UseEmailAlert==Yes||UseSendnotify==Yes)
                          {
                            string msginfo="New Event will be released soon, "+ARemMin+
                            "\n Currency = "+country.currency+" >> Importance = "+CImport+
                            "\n Event: "+event.name;
                            if(Cvalues[i].time - TimeTradeServer() == MinAlert)
                              Do_Alerts(Symbol(),msginfo,Cvalues[i].time);
                          }
                      }
                    //--
                    if(display_info == Yes && eLoop==0)
                      {
                         string FNevent=Carrow+TimeToString(Cvalues[i].time,TIME_MINUTES)+"    "+country.currency+"     "+
                               " "+CImport+"     "+Cimpact+"    "+event.name;
                         if(event.name!=prvEventF)
                           {
                             NewsInfo(FNevent);
                             prvEventF=event.name;
                             prvTimeF=Cvalues[i].time;
                           }
                         else break;
                      }
                    if(display_info == Yes && eLoop==1)
                      {
                        UpdateServerTime();
                      }
                  }
              }
          }
      }
    //--
    eLoop=1;
    //--
    return;
//---
  } //-end HasNewsEvent()
//---------//

void NewsEvent::NewsInfo(string inevent) // function: write Event Info on the chart
  {
//---
   string CommInfo="";
   //--
   CommInfo=CommInfo+"\n "+inevent;
   //--
   CommInfo=CommInfo+"";
   CComm=CComm+CommInfo;
   PComm=CComm;
   //--
   Comment(CComm);
   ChartRedraw();
   //--
   return;
//---
  } //-end NewsInfo()  
//---------//

void NewsEvent::UpdateServerTime(void)
  {
//---
   string HeaderTime="     Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+
                                              "   "+TimeToString(TimeCurrent(),TIME_SECONDS);
   //--
   Comment(HeaderTime+PComm);
   ChartRedraw();
   //--
   return;
//---
  } //-end UpdateServerTime()  
//---------//

void NewsEvent::ResetNewsInfo(void)
  {
//---
   eLoop=0; 
   pMin=cMin;
   CComm=HeaderEvent;
   //--
   return;
//---
  } //-end ResetNewsInfo()  
//---------//

void NewsEvent::Do_Alerts(const string symbol,string msgText,datetime tmrel)
  {
//---
    //--
    Print(ind_name+"--- "+symbol+": "+msgText+
          "\n--- at: ",TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert(ind_name+"--- "+symbol+": "+msgText+
              "--- at: ",TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(ind_name,"--- "+symbol+" "+TF2Str(PERIOD_CURRENT)+": "+msgText+
                       "\n--- at: "+TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(ind_name+"--- "+symbol+" "+TF2Str(PERIOD_CURRENT)+": "+msgText+
                      "\n--- at: "+TimeToString(tmrel,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//

int NewsEvent::CurrIdxArray(const string currency)
  {
//---
    int cidx=-1;
    //--
    for(int x=0; x<ArrCurr; x++)
      {
        if(CCurr[x]==currency)
          {
            cidx=x;
            break;
          }
      } 
    //--
    return(cidx);
//---
  } //-end CurrIdxArray()
//---------//

string NewsEvent::CalendarEventImportance(ENUM_CALENDAR_EVENT_IMPORTANCE importance_set) // function: to known Event Importance degree
   {
//---
   string importance_;
   //--
   switch(importance_set) 
     { 
      case  CALENDAR_IMPORTANCE_NONE: 
         importance_="Not set  "; 
         break; 
      case  CALENDAR_IMPORTANCE_LOW: 
         importance_="Low        "; 
         break; 
      case  CALENDAR_IMPORTANCE_MODERATE: 
         importance_="Moderate"; 
         break; 
      case  CALENDAR_IMPORTANCE_HIGH: 
         importance_=" High       ";
         break; 
     }
   //--
   return(importance_);
//----
   } //-end CalendarEventImportance()
//---------//

string NewsEvent::CalendarEventImpactSet(ENUM_CALENDAR_EVENT_IMPACT impact_set) // function: to known Event Impact Set mode
   {
//---
   string impact_;
   //--
   switch(impact_set) 
     { 
      case  CALENDAR_IMPACT_NA: 
         impact_="Not set   "; 
         break; 
      case  CALENDAR_IMPACT_POSITIVE: 
         impact_="Positive  "; 
         break; 
      case  CALENDAR_IMPACT_NEGATIVE: 
         impact_="Negative"; 
         break; 
     }
   //--
   return(impact_);
//----
   } //-end CalendarEventImpactSet()
//---------//

int NewsEvent::ThisTime(const int reqmode) 
  {
//---
    MqlDateTime tm;
    TimeCurrent(tm);
    int valtm=0;
    //--
    switch(reqmode)
      {
        case 0: valtm=tm.year; break;        // Return Year 
        case 1: valtm=tm.mon;  break;        // Return Month 
        case 2: valtm=tm.day;  break;        // Return Day 
        case 3: valtm=tm.hour; break;        // Return Hour 
        case 4: valtm=tm.min;  break;        // Return Minutes 
        case 5: valtm=tm.sec;  break;        // Return Seconds 
        case 6: valtm=tm.day_of_week; break; // Return Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
        case 7: valtm=tm.day_of_year; break; // Return Day number of the year (January 1st is assigned the number value of zero) 
      }
    //--
    return(valtm);
//---
  } //-end ThisTime()
//---------//

string NewsEvent::TF2Str(ENUM_TIMEFRAMES period)
  {
//---
   switch(period)
     {
       //--
       case PERIOD_M1:   return("M1");
       case PERIOD_M2:   return("M2");
       case PERIOD_M3:   return("M3");
       case PERIOD_M4:   return("M4");
       case PERIOD_M5:   return("M5");
       case PERIOD_M6:   return("M6");
       case PERIOD_M10:  return("M10");
       case PERIOD_M12:  return("M12");
       case PERIOD_M15:  return("M15");
       case PERIOD_M20:  return("M20");
       case PERIOD_M30:  return("M30");
       case PERIOD_H1:   return("H1");
       case PERIOD_H2:   return("H2");
       case PERIOD_H3:   return("H3");
       case PERIOD_H4:   return("H4");
       case PERIOD_H6:   return("H6");
       case PERIOD_H8:   return("H8");
       case PERIOD_H12:  return("H12");
       case PERIOD_D1:   return("D1");
       case PERIOD_W1:   return("W1");
       case PERIOD_MN1:  return("MN1");
       //--
     }
   return(string(period));
//---
  } //-end TF2Str()
//---------//

string NewsEvent::getUninitReasonText(int reasonCode) 
  { 
//---
   string text=""; 
   //--- 
   switch(reasonCode) 
     { 
       case REASON_PROGRAM:
            text="The EA has stopped working calling by remove function."; break;
       case REASON_REMOVE: 
            text="Program "+__FILE__+" was removed from chart"; break;
       case REASON_RECOMPILE:
            text="Program recompiled."; break;    
       case REASON_CHARTCHANGE: 
            text="Symbol or timeframe was changed"; break;
       case REASON_CHARTCLOSE: 
            text="Chart was closed"; break; 
       case REASON_PARAMETERS: 
            text="Input-parameter was changed"; break;            
       case REASON_ACCOUNT: 
            text="Account was changed"; break; 
       case REASON_TEMPLATE: 
            text="New template was applied to chart"; break; 
       case REASON_INITFAILED:
            text="The OnInit() handler returned a non-zero value."; break;
       case REASON_CLOSE: 
            text="Terminal closed."; break;
       default: text="Another reason"; break;
     } 
   //--
   return text;
//---
  } //-end getUninitReasonText()
//---------//
***Copyright © 2026 3rjfx ~ For educational purposes only.***

Please download the Economic Calendar News indicator: Economic Calendar News

If you want to get the source code of the program, please send your request via the Contact page by mentioning the article and program you want.


© 2026 Economic Calendar News Indicator for MT5 - Developed by Roberto Jacobs (3rjfx)

No comments :

Post a Comment

Leave A Comment...