Infrastructure
GMT offset, DST, and the day your EA fires at the wrong time
Daylight Saving Time shifts cost most retail EAs around four weeks of broken behaviour every year. Here is the plumbing, the gotchas, and the helper code that fixes it.
Twice a year, on a Sunday night, half the retail EAs in the world start firing at the wrong time. The strategy logic still works. The risk math still works. The trades just happen at 15:30 instead of 14:30 — or 09:30 instead of 08:30 — and the edge that depends on the cash-session open quietly evaporates for the next two to three weeks.
The cause is Daylight Saving Time, and the interaction with the broker's server clock, your local clock, and the market's actual session times. This article walks through the plumbing, the gotchas, and the helper code that gets the EA back onto the right schedule.
Three clocks, all telling different lies
When an EA reads TimeCurrent() in MQL5, it gets the broker's server time. That is not your local time, not GMT, and not the market's native session time. The relationship between them is:
- Broker server time. Whatever the broker chose. Most retail MT5 brokers run GMT+2 in winter, GMT+3 in summer — following EU DST. A handful follow a fixed offset year-round. A few follow US DST.
- Local time. Whatever timezone you live in. Irrelevant to the EA unless you converted somewhere by hand.
- Market session time. The native timezone of the venue: New York for US indices, London for UK assets, Tokyo for Asian assets. Each follows its own DST rule.
The strategy cares about market session time. The EA reads broker server time. The two diverge whenever a DST shift happens at one venue and not the other.
The DST schedule, by region
| Region | DST start | DST end | Offset summer / winter |
|---|---|---|---|
| US | 2nd Sunday of March | 1st Sunday of November | UTC−4 / UTC−5 |
| UK + EU | Last Sunday of March | Last Sunday of October | UTC+1 / UTC+0 (UK) · UTC+2 / +1 (EU) |
| Most MT5 brokers (EET) | Last Sunday of March | Last Sunday of October | GMT+3 / GMT+2 |
| Japan | (no DST) | (no DST) | UTC+9 year-round |
| Australia | 1st Sunday of October | 1st Sunday of April | UTC+11 / +10 (reverse calendar) |
The interesting consequence: US DST starts two weeks earlier than EU DST in March, and ends one week earlier in November. For three weeks per year (one in March, two in autumn), the offset between US session opens and broker server time is not what it was the week before.
A worked example
You write an EA that places an Opening Range Breakout trade on the US session. The US cash session opens at 09:30 New York time. Your broker runs on GMT+2/+3 (most do). On 10 March 2026:
- Before US DST starts (8 March): NY = UTC−5, broker = UTC+2 in winter. NY 09:30 = broker 16:30.
- After US DST starts (9 March): NY = UTC−4. Broker still on UTC+2. NY 09:30 = broker 15:30.
- Two weeks later, EU DST starts (29 March): broker shifts to UTC+3. NY 09:30 = broker 16:30 again.
For the two-week gap between US and EU DST, the broker-time mapping is 15:30. For the rest of the year it is 16:30. An EA that hardcoded 16:30 misses every cash open in that window. The bug is invisible because the EA still executes — it just executes against the wrong reference.
The autumn version
US DST ends a week earlier than EU DST. For one week in late October / early November, both regions are still on summer time but US has already shifted. Same problem, opposite direction.
How to write DST-aware MQL5
Two clean ways to handle the problem. First, anchor on the market's native time, not on broker time. Convert broker time to NY time using a DST helper, then make trading decisions against the NY clock.
// US DST: 2nd Sunday of March → 1st Sunday of November (until 2:00 local time)
bool IsUsDstActive(datetime utcTime) {
MqlDateTime dt;
TimeToStruct(utcTime, dt);
int year = dt.year;
// Compute 2nd Sunday of March
datetime marchStart = StringToTime(StringFormat("%d.03.01 02:00", year));
MqlDateTime ms; TimeToStruct(marchStart, ms);
int marchSundayOffset = (7 - ms.day_of_week) % 7 + 7; // 2nd Sunday
datetime dstStart = marchStart + marchSundayOffset * 86400;
// Compute 1st Sunday of November
datetime novStart = StringToTime(StringFormat("%d.11.01 02:00", year));
MqlDateTime ns; TimeToStruct(novStart, ns);
int novSundayOffset = (7 - ns.day_of_week) % 7;
datetime dstEnd = novStart + novSundayOffset * 86400;
return (utcTime >= dstStart && utcTime < dstEnd);
}
// Convert broker time (assumed EET = GMT+2/+3 with EU DST) to NY time.
datetime BrokerTimeToNyTime(datetime brokerTime) {
// Detect broker offset by comparing with EU DST.
bool euDst = IsEuDstActive(brokerTime); // analogous helper
int brokerOffsetMinutes = euDst ? 180 : 120; // GMT+3 or GMT+2
datetime utc = brokerTime - brokerOffsetMinutes * 60;
bool usDst = IsUsDstActive(utc);
int nyOffsetMinutes = usDst ? -240 : -300; // UTC-4 or UTC-5
return utc + nyOffsetMinutes * 60;
}Second, pre-compute the broker-time of every session open for the year at EA initialisation, using the rules above. Store the array of (date, broker_time_of_NY_open) tuples; check the array on every tick. Slightly more code, slightly easier to test.
Backtesting through DST
Your backtest must cover at least one full calendar year — preferably two — to catch all four DST transition windows. A backtest from June to December never crosses a DST shift; the EA passes; the live account fails the next March.
The strategy tester quirk
A subtle gotcha in the MT5 Strategy Tester: the tester uses broker time history, which means historical DST shifts are baked into the data. An EA tested across 2018–2024 sees the DST shifts as they actually happened. So if the EA logic depends on broker time directly, the bug shows up in backtest — good.
The trap is when the EA logic thinks it is timezone-agnostic but actually contains a hardcoded broker-hour. The tester runs it, the wrong trades happen, the equity curve takes a chunk out around DST shifts, and the author writes it off as "noisy data". Look at the trade times directly, not at the equity curve.
Brokers that change their offset
A handful of brokers do not follow EU DST — they run on a fixed offset year-round, or follow US DST instead. Each broker is a different problem. The MT5 indicator "Market Watch" → properties → "Server Time" tells you the current broker time. Compare it to UTC at two points six months apart; that tells you whether the broker shifts on DST and which calendar they follow.
Worse, some brokers have changed their offset policy mid-life. An EA tuned in 2022 may be on the wrong assumption for the same broker in 2026. Re-check whenever you migrate hosts.
The bottom line
DST is not optional plumbing. For any EA that depends on session times — and almost every EA does — the difference between handling it correctly and not is 3–4 weeks per year of broken behaviour. The fix is mechanical: anchor on the market's native time, convert from broker time using DST-aware helpers, and verify the trade times directly on the chart across known transition windows. Once it is right, it stays right.
R3 · From AlphaLab-AI
AlphaLab Growth EA
Opening Range Breakout on US indices — anchored to NY-time session boundaries with a DST-aware mapping.