The code
An Expert Advisor that trades nothing: it prints when the session opens and closes, with both clocks, and marks where entry logic goes.
Save it as MQL5/Experts/trading-session-time-filter.mq5 and compile it in MetaEditor (F7): 0 errors, 0 warnings.
enum ENUM_CLOCK
{
CLOCK_SERVER, // Broker server time
CLOCK_UTC, // UTC (GMT)
CLOCK_LONDON, // London time, with UK daylight saving
CLOCK_NEW_YORK // New York time, with US daylight saving
};
input ENUM_CLOCK InpClock = CLOCK_LONDON; // Clock the session hours are in
input int InpStartHour = 8; // Session start, hour
input int InpStartMinute = 0; // Session start, minute
input int InpEndHour = 16; // Session end, hour
input int InpEndMinute = 30; // Session end, minute
input int InpTesterOffset = 2; // Strategy Tester only: server UTC offset in winter, hours
input bool InpTesterUsDst = true; // Strategy Tester only: server clock follows US daylight saving
// 00:00 of the n-th Sunday (n = 1..4) of a month, or of the last Sunday of a 31-day month (n = 0), as UTC
datetime Sunday(const int year, const int mon, const int n)
{
MqlDateTime d = {};
d.year = year;
d.mon = mon;
d.day = (n == 0) ? 31 : 1;
datetime t = StructToTime(d);
MqlDateTime w;
TimeToStruct(t, w);
if(n == 0)
return t - w.day_of_week * 86400; // back to the last Sunday
return t + (((7 - w.day_of_week) % 7) + 7 * (n - 1)) * 86400;
}
// UK summer time: last Sunday of March to last Sunday of October, at 01:00 UTC
bool UkSummer(const datetime utc)
{
MqlDateTime t;
TimeToStruct(utc, t);
return utc >= Sunday(t.year, 3, 0) + 3600 && utc < Sunday(t.year, 10, 0) + 3600;
}
// US daylight time: second Sunday of March 02:00 EST (07:00 UTC) to first Sunday of November 02:00 EDT (06:00 UTC)
bool UsSummer(const datetime utc)
{
MqlDateTime t;
TimeToStruct(utc, t);
return utc >= Sunday(t.year, 3, 2) + 7 * 3600 && utc < Sunday(t.year, 11, 1) + 6 * 3600;
}
// Server time minus UTC, in seconds
int ServerOffset(const datetime server)
{
if(MQLInfoInteger(MQL_TESTER))
{
// In the tester TimeGMT() returns the simulated server time, so the offset has to come from the inputs
int offset = InpTesterOffset * 3600;
if(InpTesterUsDst && UsSummer(server - offset))
offset += 3600;
return offset;
}
// TimeGMT() comes from this computer's clock and time zone: round to 30 minutes to absorb small drifts
double diff = (double)((long)TimeTradeServer() - (long)TimeGMT());
return (int)MathRound(diff / 1800.0) * 1800;
}
// The server time expressed on the session's clock
datetime SessionClock(const datetime server)
{
if(InpClock == CLOCK_SERVER)
return server;
datetime utc = server - ServerOffset(server);
if(InpClock == CLOCK_UTC)
return utc;
if(InpClock == CLOCK_LONDON)
return utc + (UkSummer(utc) ? 3600 : 0);
return utc - 5 * 3600 + (UsSummer(utc) ? 3600 : 0);
}
bool InSession(const datetime server)
{
MqlDateTime t;
TimeToStruct(SessionClock(server), t);
if(t.day_of_week == 0 || t.day_of_week == 6)
return false; // Saturday and Sunday on the session's clock
int now = t.hour * 60 + t.min;
int start = InpStartHour * 60 + InpStartMinute;
int end = InpEndHour * 60 + InpEndMinute;
if(start < end)
return now >= start && now < end;
return now >= start || now < end; // a session that crosses midnight, e.g. 22:00-02:00
}
void OnTick()
{
static int state = -1;
datetime server = TimeCurrent(); // time of the last tick, on the broker's clock
int open = InSession(server) ? 1 : 0;
if(open != state)
{
PrintFormat("Session %s: server %s, session clock %s", open == 1 ? "open" : "closed",
TimeToString(server, TIME_DATE | TIME_MINUTES), TimeToString(SessionClock(server), TIME_DATE | TIME_MINUTES));
state = open;
}
if(open == 0)
return;
// Entry logic goes here: it only runs inside the session
}How it works
ENUM_CLOCK. The session hours mean nothing until you say which clock they're on. Server time is simplest; London or New York time follows the market whose session you mean, whatever the broker does.Sunday(). Daylight-saving rules are stated as "the second Sunday of March" or "the last Sunday of October". The function finds those dates from the day of the week of the 1st (or the 31st) of the month.UkSummer()andUsSummer(). UK summer time runs from the last Sunday of March to the last Sunday of October, changing at 01:00 UTC. US daylight time runs from the second Sunday of March to the first Sunday of November, changing at 02:00 local time.ServerOffset()live.TimeTradeServer() - TimeGMT(), rounded to 30 minutes because the two clocks are read a moment apart and the computer's clock drifts.ServerOffset()in the tester.TimeGMT()returns the simulated server time there, so the offset would be 0. The EA uses its inputs instead: the server's winter offset, plus an hour during US summer time if the broker's server follows it.InSession().start < endis a normal session; otherwise it crosses midnight (22:00 to 02:00) and is open after the start or before the end. Weekends are judged on the session's own clock.
Pitfalls
TimeLocal()for the session. That's your computer's clock: the EA trades different hours on your laptop and on a VPS in another time zone.- Assuming
TimeCurrent()is GMT. Many MetaTrader 5 brokers run their server at UTC+2 in winter and UTC+3 in summer; others use UTC or something else. Hours copied from a guide written for another broker are off by the difference. - Testing a GMT filter in the Strategy Tester. Because
TimeGMT()equals the server time there, a filter built on it is shifted by the broker's offset in every backtest, and still looks right live. - A fixed server-time window for a London session. On a UTC+2/+3 server that follows US daylight saving, 08:00 London is 10:00 server time most of the year, but 11:00 during the weeks when only one of the two countries has changed its clocks.
- Closing on time with no ticks.
TimeCurrent()stops between ticks and over the weekend. A rule such as "close at 21:30" needs a timer andTimeTradeServer(), and a closed market answers 10018.
Variations
- Several windows. Call
InSession()with different hours, or keep arrays of start and end minutes, for example London open and New York open only. - Close at the end of the session. Track the state change from open to closed, as
OnTick()does, and close the EA's positions at that moment. - Sessions on the chart. The free market hours tool shows when the main sessions open in your time zone, and the session high and low indicator draws them in TradingView.
- The Pine Script version. TradingView handles time zones differently: see the Pine Script session filter.
Why London 08:00 isn't always the same server hour
Take a server at UTC+2 in winter and UTC+3 during US daylight time, a common setup that ends the trading day at 17:00 New York time. London's 08:00 open lands at these server times:
| Period | London | Server | London 08:00 in server time |
|---|---|---|---|
| November to the second Sunday of March | UTC | UTC+2 | 10:00 |
| Second Sunday to last Sunday of March | UTC | UTC+3 | 11:00 |
| Last Sunday of March to last Sunday of October | UTC+1 | UTC+3 | 10:00 |
| Last Sunday of October to first Sunday of November | UTC | UTC+3 | 11:00 |
New York's 09:30 open, by contrast, stays at 16:30 server time all year on such a server, because the server changes its clock with New York. A filter in London time with the right daylight-saving rule, as in this EA, is correct in all four periods; a fixed 10:00 server-time filter is an hour late for about three weeks a year.
Questions
Is TimeCurrent() GMT in MQL5?
No. TimeCurrent() is the time of the last tick on the broker's server clock, which is often UTC+2 or UTC+3 and sometimes UTC. TimeGMT() is computed from your computer's clock and time zone.
How do I find my broker's GMT offset?
On a live chart, print TimeTradeServer() - TimeGMT() in seconds and divide by 3600, or compare the time in Market Watch with UTC. Check it again after a daylight-saving change: many servers shift by an hour.
Why does my time filter work live but not in the Strategy Tester?
Because TimeGMT() in the tester returns the simulated server time. Any rule built on it is shifted by the server's offset in backtests. Give the EA the offset as an input for testing, as this example does.
This program is a minimal example written to show one technique, not a trading system, and none of it is a recommendation to trade. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.