Libraries: Local Timezones and Local Session Hours - page 3

 

Update 11 April 2024 - version 1.77

Speed-up of the GetDaylightSwitchTimes mehod. Now using a static array to memorize the switch times for the current year.


 

Update 12 April 2024 - version 1.80

Fixed issue in the calculation of the broker GMT offset on brokers that do not provide gold trading.

 
I suggest writing the following functions.
 enum ENUM_DST_SCHEDULE
{
  DST_US,   // US DST
  DST_UK,   // UK DST
  DST_AU,   // AU DST
  DST_NONE, // No DST
};

ENUM_DST_SCHEDULE GetDSTSchedule( void );
ENUM_DST_SCHEDULE GetDSTSchedule( const MqlRates &Rates[] );
ENUM_DST_SCHEDULE GetDSTSchedule( const string Symb );

int GetGMTOffset( void ); // Broker GMT offset.

datetime ChangeDSTSchedule( const datetime Time, const ENUM_DST_SCHEDULE ScheduleFrom, const ENUM_DST_SCHEDULE ScheduleTo = DST_US );
datetime ChangeGMTOffset( const datetime Time, const int OffsetFrom, const int OffsetTo = - 10800 );


So they can be used as follows.

 #property script_show_inputs

input datetime inFrom = D'2023.01.01' ;
input ENUM_DST_SCHEDULE inDSTScheduleTo = DST_US;
input int inGMTOffsetTo = + 3 ;

void OnStart ()
{  
   const ENUM_DST_SCHEDULE DSTSchedule = GetDSTSchedule() ;
  
   if (! _LastError )
  {    
     MqlRates Rates[];        
     const int Size = CopyRates ( _Symbol , PERIOD_CURRENT , inFrom, INT_MAX , Rates);        
    
     if (Size > 0 )
    {
       const int GMTOffset = GetGMTOffset() ;

       // Change DST/GMT.
       for ( uint i = Size; ( bool )i--;)
      {
        Rates[i].time = ChangeDSTSchedule(Rates[i].time, DSTSchedule, inDSTScheduleTo) ;
        Rates[i].time = ChangeGMTOffset(Rates[i].time, GMTOffset, - 3600 * inGMTOffsetTo) ;      
      }
      
       // Create custom symbol.
       const string Symb = _Symbol + "_From" + EnumToString (DSTSchedule) + ( string )(GMTOffset / - 3600 ) +
                                     "_To" + EnumToString (inDSTScheduleTo) + ( string )inGMTOffsetTo;
      
       CustomSymbolCreate (Symb, NULL , _Symbol );      
       CustomRatesReplace (Symb, 0 , INT_MAX , Rates);
       SymbolSelect (Symb, true );
       ChartOpen (Symb, _Period );
    }                    
  }
}



To check, you can then go to the broker at the desired DST/GMT and compare the real symbol with the custom symbol .

They should match, with only slight differences between bars (different brokers).

 
I suggest changing the paths a little.
#include <amrali\TimeZoneInfo.mqh> // https://www.mql5.com/en/code/48419
 

Update 15 April 2024 - version 1.82

Added SetCustomTimeZone method to CTimeZoneInfo class, which you can use to configure the built-in custom time zone with a specified name, an offset from Greenwich Mean Time (GMT) and a daylight schedule identifier. Later, the custom time zone can be accessed via ZONE_ID_CUSTOM.

bool CTimeZoneInfo::SetCustomTimeZone(
   const string name, 
   const int baseGMTOffset = 0,   // Offset from GMT in seconds
   const ENUM_ZONE_ID daylightRuleId = ZONE_ID_UTC
   );

 
fxsaber #:
I suggest writing the following functions.


Thanks for that nice idea.

However, I have implemented your idea differently in the library as a custom time zone that you can configure and use freely, like any other time zone.

#property script_show_inputs

#include "TimeZoneInfo.mqh"

input datetime      inFrom = D'2023.01.01' ;
input string        InpName  = "Custom+3";                // Custom Timezone's name
input int           InpBaseGMTOffset  = 10800;            // Custom Timezone's base GMT offset (in seconds)
input ENUM_ZONE_ID  InpDaylightRuleId = ZONE_ID_NEWYORK;  // Custom Timezone's DST schedule

void OnStart()
  {
   // Configure the built-in custom time zone
   bool success = CTimeZoneInfo::SetCustomTimeZone(InpName, InpBaseGMTOffset, InpDaylightRuleId);

   if(success)
     {
      MqlRates Rates[];
      const int copied = CopyRates(_Symbol, PERIOD_CURRENT, inFrom, INT_MAX, Rates);

      if(copied > 0)
        {
         // Change DST/GMT.
         for(int i = 0; i < copied; i++)
           {
            Rates[i].time = CTimeZoneInfo::ConvertTimeForPlace(Rates[i].time, ZONE_ID_BROKER, ZONE_ID_CUSTOM);
           }

         // Create custom symbol.
         const string Symb = _Symbol + "_" + InpName;

         CustomSymbolCreate(Symb, NULL, _Symbol);
         CustomRatesReplace(Symb, 0, INT_MAX, Rates);
         SymbolSelect(Symb, true);
         ChartOpen(Symb, _Period);
        }
     }
  }
 

Update 16 April 2024 - version 1.85

Replaced the GetNthSunday internal method with the more optimized GetMonthTime method.

Liquid Chart
Liquid Chart
  • www.mql5.com
Would you like to see an hourly chart with bars opening from the second and the fifth minute of the hour? What does a redrawn chart look like when the opening time of bars is changing every minute? What advantages does trading on such charts have? You will find answers to these questions in this article.
 
amrali #:

Thanks for that nice idea.

However, I have implemented your idea differently in the library as a custom time zone that you can configure and use freely, like any other time zone.

Unfortunately, I couldn’t figure out from your source how I could write the following functions.

Forum on trading, automated trading systems and testing trading strategies

Libraries: Local Timezones and Local Session Hours

fxsaber, 2024.04.15 09:34

 enum ENUM_DST_SCHEDULE
{
  DST_US,   // US DST
  DST_UK,   // UK DST
  DST_AU,   // AU DST
  DST_NONE, // No DST
};

ENUM_DST_SCHEDULE GetDSTSchedule( void );


int GetGMTOffset( void ); // Broker GMT offset.

datetime ChangeDSTSchedule( const datetime Time, const ENUM_DST_SCHEDULE ScheduleFrom, const ENUM_DST_SCHEDULE ScheduleTo = DST_US );
datetime ChangeGMTOffset( const datetime Time, const int OffsetFrom, const int OffsetTo = - 10800 );

Could you tell me how to do it correctly?

 

fxsaber #
:

Unfortunately, I couldn’t figure out from your source how I could write the following functions.

Could you tell me how to do it correctly?

Please refer to the code in post #26

input string        InpName  = "Custom+3";                // Custom Timezone's name
input int           InpBaseGMTOffset  = 10800;            // Custom Timezone's base GMT offset (in seconds)
input ENUM_ZONE_ID  InpDaylightRuleId = ZONE_ID_NEWYORK;  // Custom Timezone's DST schedule

void OnStart()
  {
   // Configure the built-in custom time zone
   bool success = CTimeZoneInfo::SetCustomTimeZone(InpName, InpBaseGMTOffset, InpDaylightRuleId);

I added a new timezone (ZONE_ID_CUSTOM) that you can configure with name, desired base GMT offset and a custom DST schedule of another timezone.

This custom time zone object once configured as you liking (e.g., custom broker), it will handle the updating of its current local time, dst timings, time conversion and text formatting, etc...

         // Change DST/GMT.
         for(int i = 0; i < copied; i++)
           {
            Rates[i].time = CTimeZoneInfo::ConvertTimeForPlace(Rates[i].time, ZONE_ID_BROKER, ZONE_ID_CUSTOM);
           }

Here you convert bar times as given by your broker's time to the corresponding times of the hypothetical broker that we configured above, respecting its defined GMT offset and DST switch times.

The array on converted rates, is then used to display the price chart of the custom broker (or symbol).


The code above achieves the intent of your code:

datetime ChangeDSTSchedule( const datetime Time, const ENUM_DST_SCHEDULE ScheduleFrom, const ENUM_DST_SCHEDULE ScheduleTo = DST_US );
datetime ChangeGMTOffset( const datetime Time, const int OffsetFrom, const int OffsetTo = - 10800 );


NB:

Converting bar times from one broker to another causes the timelines (i.e., the simplified graph) of the bars to changes.

** Changing DST schedule changes the shape of the timeline of the weekly start hours of your broker:

  • DST_US : Straight line  (e.g., ICMarkets always starts at 12:00 am Monday, every week, server is always catching up with US "Fx start/end")
  • DST_UK : Double_notched (spring / autumn: one zone switches early causing a notch, then the other time zone catches up in the same direction, e.g, AdmiralMarkets starts early one hour for 2 weeks in mid-march, and also early one hour in Nov)
  • DST_AU : Double_Stepped   (at time of US switch + AU switch, because switches are in opposite directions at interleaving times)
  • DST_NONE : Single_step (at time of US switch: although the server does not switch, but the time offset = server-US has changes, e.g., EXness does not apply dst rules, but it starts 21:00 in US summer, and 22:-00 is US winter. Exness does not move, US moves forth and back due to its DST)

** Changing only the GMT offset and keeping the same DST schedule causes shift of the timeline forward / back.

NOTICE: to accurately check those timelines, use the GOLD charts of the broker. They are more reliable for weekly start/end timing than Fx pairs that I found having a lot of variations/surprises.

Libraries: Local Timezones and Local Session Hours
Libraries: Local Timezones and Local Session Hours
  • 2024.04.11
  • amrali
  • www.mql5.com
Articles, Library comments: Libraries: Local Timezones and Local Session Hours
 

Basic example of custom time zone:

#include "TimeZoneInfo.mqh"

void OnStart()
  {
   Print("\n========== Configure the built-in custom timezone ==========");

   string        name  = "Custom+3";               // Custom Timezone's name
   int           baseGMTOffset  = 10800;           // Custom Timezone's base GMT offset (in seconds)
   ENUM_ZONE_ID  daylightRuleId = ZONE_ID_LONDON;  // Custom Timezone's DST schedule

   bool success = CTimeZoneInfo::SetCustomTimeZone(name, baseGMTOffset, daylightRuleId);
   Print("Parameter 'name'            : ", name);
   Print("Parameter 'baseGMTOffset'   : ", baseGMTOffset);
   Print("Parameter 'daylightRuleId'  : ", EnumToString(daylightRuleId));
   Print("SetCustomTimeZone() returns : ", success);

   if(success)
     {
      Print("\n========== More information about a timezone ==========");

      CTimeZoneInfo tz(ZONE_ID_CUSTOM);
      //tz.RefreshTime();
      Print("Name()                  : ", tz.Name());
      Print("TimeUTC()               : ", tz.TimeUTC());
      Print("TimeLocal()             : ", tz.TimeLocal());
      Print("TimeGMTOffset()         : ", tz.TimeGMTOffset());
      Print("TimeDaylightSavings()   : ", tz.TimeDaylightSavings());
      Print("ToString()              : ", tz.ToString());
      datetime dst_start, dst_end;
      tz.GetDaylightSwitchTimes(dst_start, dst_end);
      Print("dst_start               : ", dst_start);
      Print("dst_end                 : ", dst_end);
      Print("GetDaylightNextSwitch() : ", tz.GetDaylightNextSwitch());

      datetime converted = tz.ConvertLocalTime(ZONE_ID_BROKER);  // convert current local time in custom -> corresponding broker time
      Print("converted               : ", CTimeZoneInfo::FormatTimeForPlace(converted, ZONE_ID_BROKER));
     }
  }

You can read more about custom time zones in C# docs here: https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.createcustomtimezone?view=net-8.0
TimeZoneInfo.CreateCustomTimeZone Method (System)
TimeZoneInfo.CreateCustomTimeZone Method (System)
  • dotnet-bot
  • learn.microsoft.com
Defines a time zone that is not found on the local computer.