//+------------------------------------------------------------------+ //| worldFxHoliday.mqh | //| A reusable holiday‐calendar module for MQL5 | //| Copyright 2025, Kimar Miller | //| https://www.AtomosMaestoso.com | //+------------------------------------------------------------------+ #ifndef _WORLD_FX_HOLIDAY_MQH_ #define _WORLD_FX_HOLIDAY_MQH_ //--- Include necessary libraries #include #include #include //+------------------------------------------------------------------+ //| HolidayEntry class | //+------------------------------------------------------------------+ class HolidayEntry : public CObject { private: string m_currency; // e.g. "USD" string m_name; // e.g. "Christmas Day" datetime m_date; // full date with correct year public: // initialization void Init(const string currency_, const string name_, const datetime date_) { m_currency = currency_; m_name = name_; m_date = date_; } // accessors string Currency() const { return(m_currency); } string Name() const { return(m_name); } datetime Date() const { return(m_date); } // required override for CArrayObj cloning virtual CObject* Clone() const { HolidayEntry* copy = new HolidayEntry(); copy.Init(m_currency, m_name, m_date); return(copy); } }; //+------------------------------------------------------------------+ //| Static fixed‐date holidays: currency, MM, DD, description | //+------------------------------------------------------------------+ static const string staticHolidays[][4] = { {"AUD","01","25","Australia Day"}, {"AUD","04","25","Anzac Day"}, {"AUD","12","23","Christmas Eve"}, {"AUD","12","24","Christmas Day"}, {"AUD","12","25","Boxing Day"}, {"AUD","12","25","Proclamation Day"}, {"AUD","12","30","New Year's Eve"}, {"AUD","12","31","New Year's Day"}, {"CAD","06","21","National Indigenous Peoples Day"}, {"CAD","06","22","June Day"}, {"CAD","07","01","Canada Day"}, {"CAD","09","30","National Day for Truth and Reconciliation"}, {"CAD","11","10","Remembrance Day"}, {"CAD","12","24","Christmas Day"}, {"CAD","12","25","Boxing Day"}, {"CAD","12","31","New Year's Day"}, {"CHF","01","01","Berchtolds Day"}, {"CHF","01","05","Three King's Day"}, {"CHF","02","28","Republic Day"}, {"CHF","03","19","St. Joseph's Day"}, {"CHF","05","01","May Day"}, {"CHF","06","23","Fête d'Indépendance"}, {"CHF","06","29","Saint Peter and Saint Paul"}, {"CHF","08","01","National Day"}, {"CHF","08","15","Assumption Day"}, {"CHF","11","01","All Saints' Day"}, {"CHF","12","07","Immaculate Conception Day"}, {"CHF","12","23","Christmas Eve"}, {"CHF","12","24","Christmas Day"}, {"CHF","12","25","St. Stephen's Day"}, {"CHF","12","30","New Year's Eve"}, {"CHF","12","30","Restoration Day"}, {"CHF","12","31","New Year's Day"}, {"CNY","04","05","Ching Ming Festival"}, {"CNY","05","01","Labour Day"}, {"CNY","10","01","Chinese National Day"}, {"CNY","10","02","Chinese National Day Holiday"}, {"CNY","10","03","Chinese National Day Holiday"}, {"CNY","10","04","Chinese National Day Holiday"}, {"CNY","10","05","Chinese National Day Holiday"}, {"EUR","01","05","Three King's Day"}, {"EUR","01","05","Epiphany"}, {"EUR","02","27","Andalucía Day"}, {"EUR","03","01","Balearic Day (in lieu)"}, {"EUR","03","07","International Women's Day"}, {"EUR","03","19","St. Joseph's Day"}, {"EUR","04","17","Feast of San Vicente Ferrer"}, {"EUR","04","23","Castile & León Community Day"}, {"EUR","04","23","St. George's Day"}, {"EUR","04","24","Saint Vincent the Martyr"}, {"EUR","04","25","Feast of St. Mark"}, {"EUR","04","25","Liberation Day"}, {"EUR","04","28","Sardinia's Day"}, {"EUR","05","01","Labour Day"}, {"EUR","05","02","Community Festival of Madrid"}, {"EUR","05","08","V-E Day"}, {"EUR","05","13","Saint Peter de Regalado"}, {"EUR","05","15","Feast of St. Isidro"}, {"EUR","05","17","Galician Literature Day"}, {"EUR","05","30","Canary Islands Day"}, {"EUR","05","31","Castilla-La Mancha Day"}, {"EUR","06","02","Republic Day"}, {"EUR","06","09","Day of Murcia"}, {"EUR","06","09","La Rioja Day"}, {"EUR","06","13","Feast of St. Anthony"}, {"EUR","06","24","Feast of St. John the Baptist"}, {"EUR","06","29","Saint Peter and Saint Paul"}, {"EUR","07","14","Bastille Day"}, {"EUR","07","15","Feast of St. Rosalia"}, {"EUR","07","25","St. James' Day"}, {"EUR","07","28","Day of Cantabria Institutions"}, {"EUR","08","05","Our Lady of Africa"}, {"EUR","08","15","Assumption Day"}, {"EUR","09","02","Ceuta Day"}, {"EUR","09","08","Feast of Our Lady of Victories"}, {"EUR","09","11","National Day of Catalonia"}, {"EUR","09","15","Lady of Aparecida"}, {"EUR","09","17","Day of Melilla"}, {"EUR","09","19","Feast of St. Gennaro"}, {"EUR","09","20","World Children's Day"}, {"EUR","09","24","La Mercè"}, {"EUR","10","03","German Unity Day"}, {"EUR","10","04","Feast of St. Petronius"}, {"EUR","10","12","Hispanic Day"}, {"EUR","10","13","Hispanic Day (in lieu)"}, {"EUR","10","31","Reformation Day"}, {"EUR","11","01","All Saints' Day"}, {"EUR","11","02","Feast of St. Giusto"}, {"EUR","11","08","Our Lady of the Almudena"}, {"EUR","11","09","Our Lady of the Almudena (in lieu)"}, {"EUR","11","10","Armistice Day"}, {"EUR","11","17","Repentance Day"}, {"EUR","12","02","Feast of St. Francis Xavier"}, {"EUR","12","05","Constitution Day"}, {"EUR","12","05","Feast of St. Nicholas"}, {"EUR","12","06","Constitution Day (in lieu)"}, {"EUR","12","06","Feast of St. Ambrose"}, {"EUR","12","07","Immaculate Conception Day"}, {"EUR","12","24","Christmas Day"}, {"EUR","12","25","St. Stephen's Day"}, {"EUR","12","31","New Year's Day"}, {"GBP","01","01","Day after New Year's Day"}, {"GBP","11","29","St. Andrew's Day"}, {"GBP","12","24","Christmas Day"}, {"GBP","12","25","Boxing Day"}, {"GBP","12","31","New Year's Day"}, {"JPY","02","10","National Foundation Day"}, {"JPY","02","22","The Emperor's Birthday"}, {"JPY","04","29","Showa Day"}, {"JPY","05","04","Greenery Day"}, {"JPY","05","05","Children's Day"}, {"JPY","08","11","Mountain Day"}, {"JPY","11","02","Culture Day"}, {"JPY","11","22","Labour Thanksgiving Day"}, {"JPY","12","31","New Year's Day"}, {"NZD","12","24","Christmas Day"}, {"NZD","12","25","Boxing Day"}, {"NZD","12","31","New Year's Day"}, {"USD","06","19","Juneteenth"}, {"USD","07","04","Independence Day"}, {"USD","11","10","Veterans Day"}, {"USD","12","24","Christmas Day"}, {"USD","12","31","New Year's Day"} }; //+------------------------------------------------------------------+ //| Class to manage the holiday calendar | //+------------------------------------------------------------------+ class CHolidays : public CObject { private: CList *m_holidayList; public: //--- Constructor void CHolidays() { m_holidayList = new CList(); if(CheckPointer(m_holidayList) == POINTER_INVALID) { Print("Failed to create CList instance."); return; } // Populate the calendar with holidays LoadHolidays(); } //--- Destructor void ~CHolidays() { if(CheckPointer(m_holidayList) != POINTER_INVALID) { // FreeAll is a method of CList that correctly deallocates all // dynamically created objects (which inherit from CObject) in the list. m_holidayList.Clear(); delete m_holidayList; } } //+------------------------------------------------------------------+ //| LoadHolidays: populates g_holidays with correct-year dates | //+------------------------------------------------------------------+ void LoadHolidays() { // clear any existing entries m_holidayList.Clear(); // grab current year MqlDateTime now; TimeToStruct(TimeCurrent(), now); // iterate fixed holidays int total = ArraySize(staticHolidays); for(int i = 0; i < total; i++) { // parse month/day int mon = (int)StringToInteger(staticHolidays[i][1]); int day = (int)StringToInteger(staticHolidays[i][2]); // build full date at midnight MqlDateTime hd = {now.year, mon, day, 0, 0, 0}; datetime dt = ::StructToTime(hd); // create and initialize object HolidayEntry *entry = new HolidayEntry(); entry.Init(staticHolidays[i][0], staticHolidays[i][3], dt); // add to list (CList owns cloned objects) m_holidayList.Add(entry); } } //+------------------------------------------------------------------+ //| Checks if a given date is a holiday for a specific currency | //+------------------------------------------------------------------+ bool IsHoliday(datetime date, string currency) { // Break the datetime into Y/M/D MqlDateTime dt; TimeToStruct(date, dt); // Iterate by index int total = m_holidayList.Total(); for(int i = 0; i < total; i++) { // GetNodeAtIndex(i) returns a CObject* CObject *obj = m_holidayList.GetNodeAtIndex(i); if(obj == NULL) continue; // MQL5 only supports C-style casts HolidayEntry *h = (HolidayEntry*)obj; // decompose the holiday's stored datetime MqlDateTime hdt; TimeToStruct(h.Date(), hdt); // compare Y/M/D and currency if(hdt.year == dt.year && hdt.mon == dt.mon && hdt.day == dt.day && h.Currency() == currency) { Print("Found holiday: ", h.Name(), " for ", h.Currency()); return true; } } return false; } //+------------------------------------------------------------------+ //| Calculates the Easter date for a given year using the Gauss algorithm. | //+------------------------------------------------------------------+ int GetEasterDay(int year) { int a = year % 19; int b = year / 100; int c = year % 100; int d = b / 4; int e = b % 4; int g = (8 * b + 13) / 25; int h = (19 * a + b - d - g + 15) % 30; int i = c / 4; int k = c % 4; int L = (32 + 2 * e + 2 * i - h - k) % 7; int m = (a + 11 * h + 22 * L) / 451; int month = (h + L - 7 * m + 114) / 31; int day = ((h + L - 7 * m + 114) % 31) + 1; return (month * 100) + day; } //+------------------------------------------------------------------+ //| Helper to get the Nth weekday of a month | //| CORRECTED: Now calls the built-in StructToTime with :: operator. | //| The logic for finding the last weekday of a month is also corrected. | //+------------------------------------------------------------------+ int GetNthWeekdayOfMonth(int year, int month, int weekday, int count) { // For 'last' weekday of month, count is -1 if (count == -1) { MqlDateTime date_struct; date_struct.year = year; date_struct.mon = month + 1; date_struct.day = 1; datetime next_month_start = ::StructToTime(date_struct); datetime current_date = next_month_start - 1; MqlDateTime current_struct; while(true) { TimeToStruct(current_date, current_struct); if(current_struct.day_of_week == weekday) { return current_struct.day; } current_date--; } } MqlDateTime date_struct; date_struct.year = year; date_struct.mon = month; date_struct.day = 1; datetime start_date = ::StructToTime(date_struct); MqlDateTime start_struct; TimeToStruct(start_date, start_struct); int day = 1; int found_count = 0; while(day <= 31) { MqlDateTime current_struct; current_struct.year = year; current_struct.mon = month; current_struct.day = day; datetime current_date = ::StructToTime(current_struct); TimeToStruct(current_date, current_struct); if(current_struct.mon != month) break; if(current_struct.day_of_week == weekday) { found_count++; if(found_count == count) { return day; } } day++; } return -1; // Not found } //+------------------------------------------------------------------+ //| Wrapper for StructToTime that takes 6 integers. | //| CORRECTED: Now calls the built-in StructToTime with :: operator. | //+------------------------------------------------------------------+ datetime StructToTime(int year, int month, int day, int hour, int minute, int second) { MqlDateTime datetime_struct; datetime_struct.year = year; datetime_struct.mon = month; datetime_struct.day = day; datetime_struct.hour = hour; datetime_struct.min = minute; datetime_struct.sec = second; return ::StructToTime(datetime_struct); } }; //--- Global instance of the holiday calendar CHolidays g_holidays; #endif //WORLD_FX_HOLIDAY /* Header for global bank and currency exchange holidays. worldFxHoliday.mqh encapsulates a reusable holiday‐calendar module for MQL5, enabling scripts to load, store, and query currency‐specific holiday dates via an object‐oriented interface. ##### Core Responsibilities Defines the *HolidayEntry* class * Inherits from *CObject* to support cloning and integration with array/list containers * Encapsulates three fields: currency code (m\_currency), holiday name (m\_name), and exact date (m\_date) * Provides accessors (*Date(), Currency(), Name()*) for safe retrieval of entry data Implements the *CHolidays* manager class * Maintains an internal CList or *CArrayObj* of cloned *HolidayEntry* objects * Offers *LoadHolidays()* to populate the list from a static definition or external source, computing both fixed and dynamic holidays (e.g., nth weekday events) * Exposes *IsHoliday(datetime date, string currency)* to determine whether a given date is a holiday for a specified currency * Leverages MQL5’s built-in *StructToTime* and *TimeToStruct* (disambiguated where necessary) to convert between datetime and structured date representations Ensures modularity and future-proofing * Uses include guards (#ifndef…#define…) and clearly namespaced file naming * Integrates cleanly with other utility modules (ArrayObj, List, Object, StdLibErr) for dependency-driven extension ##### Typical Use Case 1. Include worldFxHoliday.mqh in an Expert Advisor or script. 2. Instantiate *CHolidays*, call *LoadHolidays()* at initialization. 3. On each tick or at critical decision points, invoke *IsHoliday(TimeCurrent(), "USD")* (or another currency) to determine if trading logic should respect market closures. */