SymbolInfoSessionTrade: sessions that cross midnight look closed with the usual check

A pattern I see in many EAs: read SymbolInfoSessionTrade for today, take from % 86400 and to % 86400, and compare them with the current time of day. It breaks when a session crosses midnight. The returned 'to' can be later than 24:00 (a session from 21:00 to 08:00 the next day), so to % 86400 becomes 08:00 and the whole evening looks closed. There is a second gap: after midnight, today's list does not contain the session that started yesterday.

The script below prints every session of a symbol, marks the ones that cross midnight, and compares the usual check with one that keeps the real length (to - from) and also looks at yesterday's sessions. Online it uses TimeTradeServer(), because TimeCurrent() stops between ticks.

Which symbols on your account have sessions that cross midnight, and how do you handle them in your EAs?


//+------------------------------------------------------------------+
//| SessionAcrossMidnight.mq5                                         |
//| Prints the broker's trade sessions of a symbol and checks whether |
//| the market is open now, including sessions that cross midnight.  |
//+------------------------------------------------------------------+
#property strict
#property script_show_inputs

input string InpSymbol = "";   // Symbol (empty = chart symbol)

// TimeCurrent() stops between ticks; TimeTradeServer() keeps running (equal in the Tester).
datetime ServerNow()
  {
   return MQLInfoInteger(MQL_TESTER) ? TimeCurrent() : TimeTradeServer();
  }

// A session "to" can be later than 24:00 (for example 21:00 -> 08:00 next day).
// Check today's sessions and the part of yesterday's sessions that runs into today,
// keeping the real length (to - from) instead of taking "to % 86400".
bool SessionOpen(const string sym, const datetime now)
  {
   const datetime day0 = now - now % 86400;
   for(int back = 0; back <= 1; back++)
     {
      MqlDateTime d;
      TimeToStruct(day0 - back * 86400, d);
      datetime from, to;
      for(uint i = 0; i < 10 && SymbolInfoSessionTrade(sym, (ENUM_DAY_OF_WEEK)d.day_of_week, i, from, to); i++)
        {
         const datetime a = day0 - back * 86400 + (from % 86400);
         const datetime b = a + (to - from);
         if(now >= a && now < b)
            return true;
        }
     }
   return false;
  }

// The naive check many EAs use: drops the date part of from/to.
bool NaiveOpen(const string sym, const datetime now)
  {
   MqlDateTime t;
   TimeToStruct(now, t);
   const int sec = t.hour * 3600 + t.min * 60 + t.sec;
   datetime from, to;
   for(uint i = 0; i < 10 && SymbolInfoSessionTrade(sym, (ENUM_DAY_OF_WEEK)t.day_of_week, i, from, to); i++)
     {
      const int a = (int)(from % 86400);
      const int b = (int)(to % 86400);
      if(sec >= a && sec < b)
         return true;
     }
   return false;
  }

void OnStart()
  {
   const string sym = (InpSymbol == "") ? _Symbol : InpSymbol;
   if(!SymbolSelect(sym, true))
     {
      PrintFormat("Symbol %s not found (error %d)", sym, GetLastError());
      return;
     }
   const string days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
   for(int d = 0; d < 7; d++)
     {
      datetime from, to;
      for(uint i = 0; i < 10 && SymbolInfoSessionTrade(sym, (ENUM_DAY_OF_WEEK)d, i, from, to); i++)
        {
         const bool cross = (to - from) + (from % 86400) > 86400;
         PrintFormat("%s session %u: %s -> %s%s", days[d], i,
                     TimeToString(from, TIME_MINUTES), TimeToString(to, TIME_MINUTES),
                     cross ? "  (crosses midnight)" : "");
        }
     }
   const datetime now = ServerNow();
   PrintFormat("Server time %s: open = %s, naive check = %s", TimeToString(now, TIME_DATE | TIME_MINUTES),
               SessionOpen(sym, now) ? "true" : "false", NaiveOpen(sym, now) ? "true" : "false");
  }
//+------------------------------------------------------------------+
Huu Tho Tran:

A pattern I see in many EAs: read SymbolInfoSessionTrade for today, take from % 86400 and to % 86400, and compare them with the current time of day. It breaks when a session crosses midnight. The returned 'to' can be later than 24:00 (a session from 21:00 to 08:00 the next day), so to % 86400 becomes 08:00 and the whole evening looks closed. There is a second gap: after midnight, today's list does not contain the session that started yesterday.

Where did you see such code ?

The script below prints every session of a symbol, marks the ones that cross midnight, and compares the usual check with one that keeps the real length (to - from) and also looks at yesterday's sessions. Online it uses TimeTradeServer(), because TimeCurrent() stops between ticks.

Which symbols on your account have sessions that cross midnight, and how do you handle them in your EAs?


I have never seen such session, do you have an actual example of a broker/symbol using it ?