Libraries: Local Timezones and Local Session Hours - page 7

 

Hi,

I have one more bug that I've come across. Not sure if it is only on Sundays (which is usually when get some time to code and troubleshoot), but my broker (Active Trades) seems to be detected as a Timezone of GMT-21 which is incorrect (should be GMT+1). Any idea what could be causing this? I am using BTCUSD pair so it is trading on Sundays. 

In my code, I pass a candle datetime and from there try to determine whether the sessions was open at that time (i.e. I need to be able to throw any candle at it and it should tell me whether it was printed during the session, with weekends always being closed), so I am doing this:

CSessionHours session(ZONE_ID_TOKYO);
session.BeginLocalTime(h_open, m_open);
session.EndLocalTime(h_close, m_close);

CTimeZoneInfo broker(ZONE_ID_BROKER);
broker.SetLocalTime(candle_time);
converted = broker.ConvertLocalTime(ZONE_ID_TOKYO);
session.SetLocalTime(converted);

Thanks

 
csol007 #:

Hi,

I have one more bug that I've come across. Not sure if it is only on Sundays (which is usually when get some time to code and troubleshoot), but my broker (Active Trades) seems to be detected as a Timezone of GMT-21 which is incorrect (should be GMT+1). Any idea what could be causing this? I am using BTCUSD pair so it is trading on Sundays. 

In my code, I pass a candle datetime and from there try to determine whether the sessions was open at that time (i.e. I need to be able to throw any candle at it and it should tell me whether it was printed during the session, with weekends always being closed), so I am doing this:

Thanks

Update: Using Gold fixed the above problem for me. :)
 

Hi @amrali.

Great work on all your libraries (upvote from me)!

I have a minor issue and perhaps you could point me out to the correct library (or function) if I haven't seen it.

I am located at UTC+3 DST (Athens time zone or Cyprus). I run the BrokerDaylightSchedule.mq5 and I get the following for the Nasdaq symbol:

Server : PepperstoneUK-Demo

Time   : 2025.05.17 16:22:46

Offset : GMT+3

DST_US : server dst begins on the second Sunday of March (+1) and ends on the first Sunday of November (-1)

Nasdaq opens always at 16:30 at my time zone except for a couple of weeks where NY has switched to DST but Athens hasn't. In this case Nasdaq opens at 15:30 my local (Greek) time but Metatrader still displays 16:30 (since it switches DST on US times). As such, there is no problem with my experts since they always know that Nasdaq bar with time 16:30 is the first one of the market open.

The problem arrives when I want to make my expert run on FTSE (UK time zone). FTSE opens at 10:00 local time but when US enters DST and UK hasn't entered it yet, the open bar at Metatrader arrives at 11:00 (for almost 2-3 weeks until UK switches to DST). How do you handle that issue? Do you have any ready made library to handle these kind of issues or you do it manually, eg pseudocode below:

// remove 7 hours (from current bar time) to match the correct US time
datetime realUSTime = TIME_NOW - 7 * 3600; // or time[0] - 7 * 3600

int utcDiff = (IsDaylightSavingTime(ZONE_ID_NEWYORK, realUSTime) ? 1 : 0) -
                   (IsDaylightSavingTime(ZONE_ID_LONDON, realUSTime) ? 1 : 0); // Maybe we have to add 5 hours here for the London time?

if (utcDiff != 0) {
        // One of the 2 times (US or UK) has switched to DST or exited from it. Either add or subtract one hour on the Local time of the target (the UK one). eg. something like below:
        //   datetime realUKTime = realUSTime + 5 * 3600 + utcDiff * 3600;
}

Thanks in advance!

 
Very nice library. I suggest it!
 
Efthymios Kalyviotis #:

The problem arrives when I want to make my expert run on FTSE (UK time zone). FTSE opens at 10:00 local time but when US enters DST and UK hasn't entered it yet, the open bar at Metatrader arrives at 11:00 (for almost 2-3 weeks until UK switches to DST). How do you handle that issue? Do you have any ready made library to handle these kind of issues or you do it manually, eg pseudocode below:

It is better to use a session object to handle dst changes behind the scenes and to focus on the task at hand. (The lib objects will take care of UTC/DST discrepancies between your server's and London time "FTSE").

#include "SessionHours.mqh"

void OnStart()
  {
   Print("\n========== Working with FTSE session hours  ==========");
   const ENUM_ZONE_ID FTSE_zone_id = ZONE_ID_LONDON;
   CSessionHours FTSE_tz(FTSE_zone_id);

//--- FTSE session hours are set to 8:00 am - 4:30 pm local London time
   FTSE_tz.BeginLocalTime(8, 00);  // override the local session begin time using a begin local hour and minute (08:00 am London time)
   FTSE_tz.EndLocalTime(16, 30);   // override the local session end time using an end local hour and minute (04:30 pm London time)

//--- Refresh the current local time and print session hours for the day
   FTSE_tz.RefreshTime();
   Print("TimeLocal()           : ", FTSE_tz.TimeLocal());
   Print("ToString()            : ", FTSE_tz.ToString());
   Print("BeginLocalTime()      : ", FTSE_tz.BeginLocalTime());
   Print("EndLocalTime()        : ", FTSE_tz.EndLocalTime());
   Print("CheckLocalSession()   : ", FTSE_tz.CheckLocalSession());
   Print("SecRemainingSession() : ", FTSE_tz.SecRemainingSession());
   Print("SecondsToString()     : ", CSessionHours::SecondsToString(FTSE_tz.SecRemainingSession()));
   string state_str = FTSE_tz.CheckLocalSession() ? "open, ends in " + CSessionHours::SecondsToString(FTSE_tz.SecRemainingSession()) : "closed";
   PrintFormat("FTSE session is %s.", state_str);

//--- conversion to broker times
   datetime beginlocal = FTSE_tz.BeginLocalTime();
   datetime endlocal   = FTSE_tz.EndLocalTime();
   datetime beginbroker= CTimeZoneInfo::ConvertTimeForPlace(beginlocal, FTSE_zone_id, ZONE_ID_BROKER);
   datetime endbroker  = CTimeZoneInfo::ConvertTimeForPlace(endlocal, FTSE_zone_id, ZONE_ID_BROKER);

   Print("-----------------------------------");
   Print("broker begin :  ", CTimeZoneInfo::FormatTimeForPlace(beginbroker, ZONE_ID_BROKER));
   Print("broker end   :  ", CTimeZoneInfo::FormatTimeForPlace(endbroker, ZONE_ID_BROKER));
   Print("broker time  :  ", TimeTradeServer());
   Print("broker time  :  ", CTimeZoneInfo::FormatTimeForPlace(TimeTradeServer(), ZONE_ID_BROKER));
  }

 Example output on my broker (ICMarkets GMT+3):

// example output:

/*
 ========== Working with FTSE session hours  ==========
 TimeLocal()           : 2025.05.21 21:50:21
 ToString()            : Wed, 2025.05.21 21:50:21 GMT+1 DST [London]
 BeginLocalTime()      : 2025.05.21 08:00:00
 EndLocalTime()        : 2025.05.21 16:30:00
 CheckLocalSession()   : false
 SecRemainingSession() : 0
 SecondsToString()     : 00:00:00
 FTSE session is closed.
 -----------------------------------
 broker begin :  Wed, 2025.05.21 10:00:00 GMT+3 DST [ICMarketsSC-Demo]
 broker end   :  Wed, 2025.05.21 18:30:00 GMT+3 DST [ICMarketsSC-Demo]
 broker time  :  2025.05.21 23:50:21
 broker time  :  Wed, 2025.05.21 23:50:21 GMT+3 DST [ICMarketsSC-Demo]
*/
Files:
 
amrali #:

It is better to use a session object to handle dst changes behind the scenes and to focus on the task at hand. (The lib objects will take care of UTC/DST discrepancies between your server's and London time "FTSE").

 Example output on my broker (ICMarkets GMT+3):

Thank you very much!

 
Efthymios Kalyviotis #:

Thank you very much!

To trade the FTSE session in your EA, the above code can be rearranged into something like this:

#include "SessionHours.mqh"

//--- global variables
const ENUM_ZONE_ID FTSE_zone_id = ZONE_ID_LONDON;
CSessionHours FTSE_tz(FTSE_zone_id);

int OnInit()
  {
//--- FTSE session hours are set to 8:00 am - 4:30 pm local London time
   FTSE_tz.BeginLocalTime(8, 00);  // override the local session begin time using a begin local hour and minute (08:00 am London time)
   FTSE_tz.EndLocalTime(16, 30);   // override the local session end time using an end local hour and minute (04:30 pm London time)

   return (INIT_SUCCEEDED);
  }

void OnTick()
  {
//--- Refresh the current local time and session hours for the day
   FTSE_tz.RefreshTime();
  
//--- Trade the FTSE session when it is open, and until 2 hours before close.  
   if(FTSE_tz.CheckLocalSession() == true && FTSE_tz.SecRemainingSession() > 2 * 3600)
     {
      // TradingBlock(); 
     }
  }
Files:
 
Excellent!!
 

Hi @amrali.

I am trying to find some error in the `CTimeZoneInfo` class. Running the following on history data (debugging):

#include "SessionHours.mqh"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   Print("\n========== Working with FTSE session hours  ==========");
   const ENUM_ZONE_ID FTSE_zone_id = ZONE_ID_LONDON;
   CSessionHours FTSE_tz(FTSE_zone_id);

//--- FTSE session hours are set to 8:00 am - 4:30 pm local London time
   FTSE_tz.BeginLocalTime(8, 00);  // override the local session begin time using a begin local hour and minute (08:00 am London time)
   FTSE_tz.EndLocalTime(16, 30);   // override the local session end time using an end local hour and minute (04:30 pm London time)

//--- Refresh the current local time and print session hours for the day
   FTSE_tz.RefreshTime();
   Print("TimeLocal()           : ", FTSE_tz.TimeLocal());
   Print("ToString()            : ", FTSE_tz.ToString());
   Print("BeginLocalTime()      : ", FTSE_tz.BeginLocalTime());
   Print("EndLocalTime()        : ", FTSE_tz.EndLocalTime());
   Print("CheckLocalSession()   : ", FTSE_tz.CheckLocalSession());
   Print("SecRemainingSession() : ", FTSE_tz.SecRemainingSession());
   Print("SecondsToString()     : ", CSessionHours::SecondsToString(FTSE_tz.SecRemainingSession()));
   string state_str = FTSE_tz.CheckLocalSession() ? "open, ends in " + CSessionHours::SecondsToString(FTSE_tz.SecRemainingSession()) : "closed";
   PrintFormat("FTSE session is %s.", state_str);

//--- conversion to broker times
   datetime beginlocal = FTSE_tz.BeginLocalTime();
   datetime endlocal   = FTSE_tz.EndLocalTime();
   datetime beginbroker= CTimeZoneInfo::ConvertTimeForPlace(beginlocal, FTSE_zone_id, ZONE_ID_BROKER);
   datetime endbroker  = CTimeZoneInfo::ConvertTimeForPlace(endlocal, FTSE_zone_id, ZONE_ID_BROKER);

   Print("-----------------------------------");
   Print("broker begin :  ", CTimeZoneInfo::FormatTimeForPlace(beginbroker, ZONE_ID_BROKER));
   Print("broker end   :  ", CTimeZoneInfo::FormatTimeForPlace(endbroker, ZONE_ID_BROKER));
   Print("broker time  :  ", TimeTradeServer());
   Print("broker time  :  ", CTimeZoneInfo::FormatTimeForPlace(TimeTradeServer(), ZONE_ID_BROKER));
//---
   return(INIT_SUCCEEDED);
  }

I get different outputs from the app (especially in the TimeLocal and broker time).

2025.09.12 13:57:57.947 XAUUSD: load 27 bytes of history data to synchronize in 0:00:00.001
2025.09.12 13:57:57.947 XAUUSD: history synchronized from 2016.01.04 to 2025.09.05
2025.09.12 13:57:57.967 XAUUSD,H1: history cache allocated for 10205 bars and contains 5935 bars from 2024.01.02 01:00 to 2024.12.31 21:00
2025.09.12 13:57:57.967 XAUUSD,H1: history begins from 2024.01.02 01:00
2025.09.12 13:57:57.967 2025.01.09 04:42:00   TimeLocal()           : 2025.01.09 02:42:00
2025.09.12 13:57:57.967 2025.01.09 04:42:00   ToString()            : Thu, 2025.01.09 02:42:00 GMT+0 STD [London]
2025.09.12 13:57:57.967 2025.01.09 04:42:00   BeginLocalTime()      : 2025.01.09 08:00:00
2025.09.12 13:57:57.967 2025.01.09 04:42:00   EndLocalTime()        : 2025.01.09 16:30:00
2025.09.12 13:57:57.967 2025.01.09 04:42:00   CheckLocalSession()   : false
2025.09.12 13:57:57.967 2025.01.09 04:42:00   SecRemainingSession() : 49679
2025.09.12 13:57:57.967 2025.01.09 04:42:00   SecondsToString()     : 13:47:59
2025.09.12 13:57:57.967 2025.01.09 04:42:00   FTSE session is closed.
2025.09.12 13:57:57.967 2025.01.09 04:42:00   -----------------------------------
2025.09.12 13:57:57.967 2025.01.09 04:42:00   broker begin :  Thu, 2025.01.09 10:00:00 GMT+2 STD [PepperstoneUK-Demo]
2025.09.12 13:57:57.967 2025.01.09 04:42:00   broker end   :  Thu, 2025.01.09 18:30:00 GMT+2 STD [PepperstoneUK-Demo]
2025.09.12 13:57:57.967 2025.01.09 04:42:00   broker time  :  2025.01.09 04:42:00
2025.09.12 13:57:57.967 2025.01.09 04:42:00   broker time  :  Thu, 2025.01.09 04:42:00 GMT+2 STD [PepperstoneUK-Demo]

The below is the same exact options to the above...

2025.09.12 13:59:20.369 XAUUSD: load 27 bytes of history data to synchronize in 0:00:00.000
2025.09.12 13:59:20.369 XAUUSD: history synchronized from 2016.01.04 to 2025.09.05
2025.09.12 13:59:20.389 XAUUSD,H1: history cache allocated for 10205 bars and contains 5935 bars from 2024.01.02 01:00 to 2024.12.31 21:00
2025.09.12 13:59:20.389 XAUUSD,H1: history begins from 2024.01.02 01:00
2025.09.12 13:59:20.389 2025.01.09 00:03:45   TimeLocal()           : 2025.01.08 22:03:45
2025.09.12 13:59:20.389 2025.01.09 00:03:45   ToString()            : Wed, 2025.01.08 22:03:45 GMT+0 STD [London]
2025.09.12 13:59:20.389 2025.01.09 00:03:45   BeginLocalTime()      : 2025.01.08 08:00:00
2025.09.12 13:59:20.389 2025.01.09 00:03:45   EndLocalTime()        : 2025.01.08 16:30:00
2025.09.12 13:59:20.389 2025.01.09 00:03:45   CheckLocalSession()   : false
2025.09.12 13:59:20.389 2025.01.09 00:03:45   SecRemainingSession() : 0
2025.09.12 13:59:20.389 2025.01.09 00:03:45   SecondsToString()     : 00:00:00
2025.09.12 13:59:20.389 2025.01.09 00:03:45   FTSE session is closed.
2025.09.12 13:59:20.389 2025.01.09 00:03:45   -----------------------------------
2025.09.12 13:59:20.389 2025.01.09 00:03:45   broker begin :  Wed, 2025.01.08 10:00:00 GMT+2 STD [PepperstoneUK-Demo]
2025.09.12 13:59:20.389 2025.01.09 00:03:45   broker end   :  Wed, 2025.01.08 18:30:00 GMT+2 STD [PepperstoneUK-Demo]
2025.09.12 13:59:20.389 2025.01.09 00:03:45   broker time  :  2025.01.09 00:03:45
2025.09.12 13:59:20.389 2025.01.09 00:03:45   broker time  :  Thu, 2025.01.09 00:03:45 GMT+2 STD [PepperstoneUK-Demo]

The options are:

Observe something. None of the 2 runs have a TimeLocal() of 2025.01.01 or at least the first next working day after new year.

Also, I observed that the TimeLocal() returns constantly different time but it is around 5 hours difference every time it is run (I don't know if it does have to do anything).


Finally, I have one more question if you can answer. Inside the `HistoryServerDaylightSavings` you have the following code:

         //--- lets analyze the first H1 bar of the trading week (the first bar after weekend)
         //--- now, check if the server time falls in the US Daylight Savings Time
         if(CTimeZoneInfo::IsDaylightSavingsTime(ZONE_ID_NEWYORK, FstBarWk))
           {
            //--- compensate the effect of US switch on the server time by adding +1 hour
            FstBarWk += 1*HOURSECS;
           }

Can't this be replaced to something like:

           int iYear = GetYear(weekend);
            datetime dst_start = Date(iYear, 03, 08);  // the second Sunday of March for the US switch
            datetime dst_end   = Date(iYear, 11, 01);  // the first Sunday of November for the US switch
            if (weekend>=dst_start && weekend<dst_end) {
                FstBarWk += 1*HOURSECS;
            }

You use that 'if' statement on the `HistoryServerGMTOffset` method and it is more simple than calling the `IsDaylightSavingsTime(...)` method which repeatedly instantiates a new `CTimeZoneInfo` class and then re-calls the `SetLocalTime` method resulting in big call stack (from the recursion).

Maybe it could be simplified or am I missing something?


Thanks for the hard work! You have developed a truly amazing library!

 
Efthymios Kalyviotis #:

I am trying to find some error in the `CTimeZoneInfo` class. Running the following on history data (debugging):

I get different outputs from the app (especially in the TimeLocal and broker time).

The below is the same exact options to the above...


Just a guess: try to disable the visual mode and/or choose real ticks.