Quant from Scratch by QuantWright

Testing Popular Ideas · Lesson 10

Session windows (traders call them “killzones”)

Trading only inside set hours: which hours, which clock, how many windows you tried, and the hour daylight saving moves.

Know the basics? Read the lesson notes

A window on the clock

Each day in this market is one session (the hours a market is open), 09:30 to 16:00 New York time. Its prices come as five-minute bars: candles, as in the Markets and prices lesson, each holding the open, high, low and close of five minutes, 78 a day. A session window is a fixed stretch of clock time in which a trader trades, or looks for trades, and does nothing outside it. Traders call such windows “killzones”. Where a window starts and ends is a choice: the same idea could be run as 07:00–10:00 or as 07:00–11:00, and each is a different version.

The prices are simulated: made up by a computer, not a real market. These markets were built so that past prices say nothing about which way the next move goes, at any time of day; the size of moves does cluster, in calm and wild spells. So the counts here show what windows do when there is nothing to find. They cannot show whether any window matters in a real market. Drag a one-hour window across one day.

One day, five-minute bars (simulated)

Each bar: a thin line from its low to its high, a box from its open to its close (empty if it closed higher). Shaded: the window.

Window–
Its move that day–

On this day, 3 July 2017, the 10:00–11:00 window moved +0.15% and the 11:00–12:00 window +0.29%. Each window gives its own number every day; which one you test is a choice.

Busy hours

Over ten years on 1,000 more simulated markets, made by the same generator (the program that makes these prices), we measured each one-hour window's typical move: its average size, up or down. Which window's moves were largest?

Yes. The generator builds busier first and last bars, and quieter ones at midday.
Midday is among the quietest hours here. The generator builds busier first and last bars.
They differ: the generator builds busier first and last bars, and quieter ones at midday.
The first hour's typical move was 0.35%, midday's 0.24%: about one and a half times as large.

Each one-hour window, over 1,000 simulated markets

Top: the typical size of its move, in %. Bottom: the days it rose, in 100. Labels: each window's start.

The generator was built with busier first and last bars. Did the busy hour go up more often? No. Every window rose on 49.8 to 50.3 days in 100 and fell on about 49; on the rest it ended where it started, to the cent. In this simulation the hour decides how far prices move, not which way, so a busy hour has bigger swings, gains and losses alike, not a better edge.

For the precisePooled over 1,000 simulated markets × 2,606 days. Typical move (the average of |log(exit ÷ entry)|): 09:30 window 0.349%, 12:00 window 0.242%, 15:00 window 0.300%. The generator shares its slow rise out over the day in proportion to each bar's share of the day's variance; each window's average log move differed from that share by at most 1.91 standard errors (days treated as independent), what chance alone gives across 12 windows.

One window against just holding

Take a window of the kind traders quote, 10:00 to 11:00 New York time. The exact rule: every day, buy at 10:00 and sell at 11:00. Each buy and each sale costs 0.1% of the price (the Costs lesson). Compare it with just holding (the How we test an idea lesson): buying once on the first day and never selling, which pays the 0.1% once. Results are in % a year: the steady yearly growth that gives the same total. From 2015 to 2021 holding made 4.4% a year. Where did the window end, after costs?

The 10:00–11:00 window and just holding, 2015–2021, after costs (simulated)

Accounts starting at 100. Orange: the window. Dotted: holding.

Your guess: it ends
The window?
Holding?

It lost 40.4% a year after costs; before costs it made +0.4% a year, because one hour a day holds only a small slice of this market's slow rise. It traded on 261 days a year, every weekday, and each day keeps 0.998 of the account after costs: 0.998 multiplied 261 times is 0.59, so costs alone take about 41% of the account a year. On 1,000 more simulated markets it beat holding after costs in none.

Every window trades every day and pays the same costs, so costs pull every window down alike and never change which comes first. From here on, results are before costs.

How many windows?

Each window is a version: the same idea with different settings (the How we test an idea lesson). Every version you try is one more chance for luck to look like a find. One-hour windows starting on every half hour, the first at 09:30, each ending by the 16:00 close: how many are there?

That counts windows that don't overlap. Starting every half hour, they overlap: 09:30–10:30, then 10:00–11:00, and so on.
That counts every half hour in the session. A window starting at 15:30 would end at 16:30, after the close.
Starts at 09:30, 10:00, …, 15:00: 12 windows, 12 versions. Allow 30- or 90-minute windows too and the count grows again.

Pick a window

Here are all 12 windows on this simulated market, 2015 to 2021, before costs. The years 2022 to 2024 were held out: set aside before anything was run, to be used once (the held-out test lesson). A window's place is its rank among the 12, counting from the best. Pick the window you would choose.

12 windows, % a year before costs (simulated)

Grey: 2015–2021. Orange outline, after you pick: 2022–2024.

Your pick
Your pick, 2015–2021?
Its place, 2022–2024?

The best on 2015–2021 was 15:00–16:00, at +3.6% a year; on 2022–2024 it came 3rd. The best on 2022–2024, 14:30–15:30, had come 11th. The two busiest windows, 09:30 and 15:00, are among the three tallest bars in both periods: their bigger moves spread their yearly results wider.

Does the found window stay best?

A window found by looking for the hours where results were good is the best of 12 versions. On each of the 1,000 simulated markets we took the best window on 2015–2021 and ran it once on 2022–2024. A blind draw, one window taken at random, would be best there in about 83 of 1,000 (1,000 ÷ 12 = 83.3). Guess how often the found window stayed best.

The found window's place on 2022–2024, on 1,000 simulated markets

One bar per place, 1st on the left. Dashed: a blind draw.

Stayed best?

It stayed best in 90 of the 1,000 simulated markets, against a blind draw's 83: about what chance gives. The bars differ from each other by chance too: a count like these varies by about 9 either way around 83 (√(1,000 × 1/12 × 11/12) ≈ 8.7).

On the years it was picked from, the found window averaged +4.8% a year before costs, against +0.9 for all 12 windows on average. On the held-out years it averaged +1.1, against +1.0. Picking the best of 12 picked the luckiest, and in markets with nothing to find the luck didn't carry over (the Best of many lesson). After costs it beat holding on the held-out years in none of the 1,000.

For the preciseAverage held-out place of the found window: 6.43 of 12. It was the 09:30 window in 204 markets and the 15:00 window in 150 (a blind draw: 83 each); those busier windows' results spread wider, so they land at the top more often in any stretch of years. The 09:30 window was best on the held-out years in 188 markets. No market had a tie for first place.

An hour off

Data may come stamped in UTC (Coordinated Universal Time), the world's reference clock, which never changes for summer. New York runs 5 hours behind UTC in winter and 4 hours behind under daylight saving time, when clocks go forward an hour: from the second Sunday in March to the first Sunday in November. Those hours behind (or ahead) are a clock's offset. A tester who turns the stamps into New York time by subtracting 5 hours on every date is right in winter and an hour early in summer. Try both dates with each clock.

Which bars a “10:00–11:00” label picks (simulated)

The same bars, labelled by the chosen clock. Shaded: the bars that clock calls 10:00–11:00.

Date
Clock
First bar reads–
“10:00–11:00” is really–

On 3 July the fixed clock labels the 10:00 bar 09:00, and the bars it calls 10:00–11:00 are really 11:00–12:00 New York time. Daylight saving covered 1,700 of the 2,607 trading days (weekdays) in these ten years, 65 in 100: on every one of them the test measured the wrong hour.

Would anyone notice?

The test still runs and still prints a result. On this simulated market the 10:00–11:00 window made +0.4% a year before costs on 2015–2021 with the right clock, and −2.2% with the fixed one. With the right clock it gained, before costs, in 653 of the 1,000 simulated markets: these markets rise slowly, so most windows gain a little before costs. In how many of the 1,000 did the two clocks disagree about whether it gained?

The same window, two clocks, 1,000 simulated markets

Each dot: one market's 2015–2021 result before costs, in % a year. Across: the right clock. Up: the fixed clock. Orange: the two disagree on gain or loss.

Disagree?

In 358 of the 1,000 simulated markets. On 65 days in 100 the two tests measured different hours, and in markets with nothing to find two different hours give partly separate draws. The wrong results look just as ordinary as the right ones.

If an hour did matter in a real market, this mistake would test a different hour on 65 days in 100; this simulation can't say what it would find there. One clue does show: from March to November the fixed clock's first bar reads 08:30, an hour before the session opens.

Theory

A clock time needs its offset

A time stamp means nothing without its clock. Local time is UTC plus the place's UTC offset, and where there is daylight saving time the offset changes twice a year. A time zone database (the tz database, which much software uses) holds each place's offsets and the dates they change: look the offset up for each date, never type in one number.

tNY = tUTC + o(d)
tUTC
the time stamped in UTC
o(d)
New York's offset on date d: −4 hours from the second Sunday in March to the first Sunday in November (the US rule since 2007), −5 hours otherwise
tNY
the New York clock time of the same moment
Worked example: the two days you just saw

The 10:00 bar on 3 July 2017 is stamped 14:00 UTC. That date is under daylight saving, so o = −4: 14:00 − 4 = 10:00. A fixed −5 gives 09:00, and the bar it calls 10:00 is stamped 15:00 UTC: 15:00 − 4 = 11:00 New York. On 2 January 2017 the 10:00 bar is stamped 15:00 UTC; o = −5, so both clocks read 10:00.

Holds when
  • the stamps really are UTC;
  • the offset is looked up for each date;
  • the rules used are the ones in force in those years.
Breaks when

The data is stamped in another clock, such as an exchange's local time or a data provider's own server clock: read the data's notes, and check the first bar's time in January and in July. Before 2007 the US dates were the first Sunday in April to the last Sunday in October. London changes its clocks on other Sundays (the last in March and the last in October), so on 170 of these ten years' 2,607 trading days London was 4 hours ahead of New York, not 5.

A bar is stamped 13:30 UTC on 15 July. What is its New York time?

That subtracts 5 hours, the winter offset. 15 July is under daylight saving, so o = −4.
That subtracts 3 hours. New York's offset is −4 under daylight saving and −5 otherwise.
15 July is under daylight saving: 13:30 − 4 = 09:30, the session's first bar.

What this means for your test

  1. Write the window with its clock.

    “10:00–11:00 New York time, the offset looked up for each date”, the clock the data is stamped in, the exact rule and the costs.

Practice 1 of 3

A bigger search

The situationA friend tests windows of 30, 60 and 90 minutes, each starting on any half hour from 09:30, each ending by the 16:00 close, then checks whether the best stays best on held-out years.

On 1,000 simulated markets with nothing to find, in about how many would a blind draw be best on the held-out years?

Hint: count the starts for each length (a 30-minute window can start from 09:30 to 15:30), add them up, then divide 1,000 by the total.

30 minutes: 13 starts; 60: 12; 90: 11. 13 + 12 + 11 = 36 versions; 1,000 ÷ 36 = 27.8.
30-minute windows start at 09:30 … 15:30 (13), 60-minute at 09:30 … 15:00 (12), 90-minute at 09:30 … 14:30 (11): 36 versions. 1,000 ÷ 36 = 27.8.
Practice 2 of 3

A window set in London

The situationA trader in London keeps a window of 15:00 to 16:00 London time, meant as 10:00 to 11:00 New York. On 20 March 2024 London is still on winter time, the same as UTC; New York has been on daylight saving since 10 March.

At what New York hour does the window start that day?

Hint: 15:00 London that day is 15:00 UTC. Then use tNY = tUTC + o(d).

15:00 UTC − 4 = 11:00 New York: the window is an hour late, as on 170 of the ten years' days in this lesson's calendar.
15:00 London = 15:00 UTC that day, and New York's offset is −4 under daylight saving: 15:00 − 4 = 11:00.
Practice 3 of 3

An odd first bar

The situationA friend's five-minute bars for a market open 09:30 to 16:00 New York time start at 09:30 from November to March, and at 08:30 from March to November. Their backtest says 10:00–11:00 was the best of 12 windows.

What is the likeliest reason for the 08:30 bars?

Under daylight saving New York is UTC − 4, so a fixed −5 labels every summer bar an hour early: the 09:30 bar reads 08:30, and the “10:00–11:00” window is really 11:00–12:00 on those days.
The session is 09:30 to 16:00 New York time all year. The labels moved, not the market: a fixed −5 on UTC stamps reads every summer bar an hour early.
The bars are an hour early, not late, and only on daylight saving dates: the sign of a fixed −5 applied to UTC stamps.
✓

Lesson done

A session window trades only inside set hours, and each window you try is a version. These simulated markets were built so that past prices say nothing about which way the next move goes, so the counts show what windows do when there is nothing to find: busy hours moved further but rose no more often, and the best of 12 windows on 2015–2021 stayed best on held-out years in 90 of 1,000 simulated markets, against about 83 for a blind draw. A clock time needs its offset for each date: a fixed UTC − 5 tested the wrong hour on 65 days in 100 and flipped whether the window gained, before costs, in 358 of 1,000 simulated markets. The counts cannot show whether any window matters in a real market.

Key ideas

Session window
a fixed stretch of clock time in which a rule trades, or looks for trades; its hours and its clock are choices
Version
the same idea with different settings; each window tried is one, so count every one
UTC
Coordinated Universal Time, the reference clock, with no daylight saving
UTC offset
the hours a place's clock is ahead of UTC (negative if behind) on a given date
Daylight saving time
clocks forward an hour for part of the year; in New York from the second Sunday in March to the first Sunday in November (since 2007)
Blind draw
a version taken at random from N; if all are equally likely to be best, it is best in about 1,000 ÷ N of 1,000 markets, the figure to set beside “stayed best”

Formulas

tNY = tUTC + o(d), with New York's offset o(d) looked up for each date: −4 hours under daylight saving, −5 otherwise (the US rule since 2007)

Lesson notes

A session window is a fixed stretch of clock time in which a rule trades, or looks for trades; traders call such windows “killzones”. The window's hours are a choice, and every window tried is a version (the same idea with different settings), so a window found by looking for the hours where results were good is the best of many. Its clock is a choice too: a time stamp needs its UTC offset for each date, and daylight saving (clocks go forward an hour for part of the year) moves a window by an hour when that is missed. This lesson's simulated markets were built so that past prices say nothing about which way the next move goes, at any time of day, so its counts show what windows do when there is nothing to find. They cannot show whether any window matters in a real market; that needs its own test.

The windows

Each simulated day (prices made up by a computer) is one session, 09:30 to 16:00 New York time, cut into 78 five-minute bars, each with an open, high, low and close. A one-hour window covers 12 of them. Starting on every half hour from 09:30, with the last ending by the 16:00 close, there are 12 windows. A window's edges are a choice, and so is its clock. On the lesson's example day, 3 July 2017, the 10:00–11:00 window moved +0.15% and the 11:00–12:00 window +0.29%.

Busy hours are not up hours

Over ten years on 1,000 simulated markets, the first hour's typical move (its average size, up or down) was 0.35%, midday's (12:00–13:00) 0.24%: about one and a half times as large, because the generator builds busier first and last bars. Yet every window rose on 49.8 to 50.3 days in 100 and fell on about 49; on the rest it ended where it started, to the cent. In this simulation the hour decides how far prices move, not which way, so a busy hour has bigger swings, gains and losses alike, not a better edge.

One window against just holding

The rule for the 10:00–11:00 window: every day, buy at 10:00 and sell at 11:00; 0.1% of the price on each buy and each sale. Just holding (buying on the first day and never selling) pays the 0.1% once. From 2015 to 2021 on the lesson's simulated market, holding made 4.4% a year (the steady yearly growth that gives the same total). The window made +0.4% a year before costs, since one hour a day holds a small slice of the market's slow rise, and lost 40.4% a year after costs: it traded on 261 days a year, each keeping 0.998 of the account after costs, and 0.998 multiplied 261 times is 0.59. On 1,000 more simulated markets it beat holding after costs in 0. Every window trades every day and pays the same costs, so costs never change which window comes first; the rest of the comparisons are before costs.

The found window

The years 2022 to 2024 were held out: set aside before anything was run, to be used once. On the lesson's market the best window on 2015–2021 was 15:00–16:00, at +3.6% a year before costs; on the held-out years it came 3rd of 12 (its place, its rank counting from the best). On each of 1,000 simulated markets the best window on 2015–2021 ran once on 2022–2024. It stayed best in 90 of the 1,000, against about 83 for a blind draw (one window taken at random: 1,000 ÷ 12 = 83.3), which is about what chance gives. On the years it was picked from it averaged +4.8% a year before costs, against +0.9 for all 12 windows on average; on the held-out years +1.1, against +1.0. Picking the best of 12 picked the luckiest, and the luck did not carry over. After costs it beat holding on the held-out years in 0 of the 1,000.

An hour off

Data may be stamped in UTC (Coordinated Universal Time, the reference clock, with no daylight saving). New York is 5 hours behind UTC in winter and 4 behind under daylight saving time (clocks go forward an hour), from the second Sunday in March to the first Sunday in November. A tester who subtracts 5 hours on every date labels every summer bar an hour early: the bars called 10:00–11:00 are really 11:00–12:00, and the 09:30 bar reads 08:30. Daylight saving covered 1,700 of the 2,607 trading days (weekdays) of the lesson's ten years, 65 in 100. On the lesson's market the 10:00–11:00 window made +0.4% a year before costs on 2015–2021 with the right clock and −2.2% with the fixed one. With the right clock it gained before costs in 653 of 1,000 simulated markets (these markets rise slowly, so most windows gain a little before costs); the two clocks disagreed about whether it gained in 358. In markets with nothing to find, two different hours give partly separate draws, and the wrong results look just as ordinary. If an hour did matter in a real market, this mistake would test a different hour on 65 days in 100; the simulation can't say what it would find there.

Formula: a clock time needs its offset

Local time is UTC plus the place's UTC offset, and where there is daylight saving the offset changes twice a year. A time zone database holds each place's offsets and change dates; look the offset up for each date, never type in one number.

tNY = tUTC + o(d)
tUTC
the time stamped in UTC
o(d)
New York's offset on date d: −4 hours from the second Sunday in March to the first Sunday in November (the US rule since 2007), −5 hours otherwise
tNY
the New York clock time of the same moment
Worked example: 3 July and 2 January 2017

The 10:00 bar on 3 July 2017 is stamped 14:00 UTC; under daylight saving o = −4, so 14:00 − 4 = 10:00. A fixed −5 gives 09:00, and the bar it calls 10:00 is stamped 15:00 UTC, which is 15:00 − 4 = 11:00 New York. On 2 January 2017 the 10:00 bar is stamped 15:00 UTC; o = −5, so both clocks read 10:00.

Holds whenBreaks when

The data is stamped in another clock, such as an exchange's local time or a data provider's own server clock: read the data's notes, and check the first bar's time in January and in July. Before 2007 the US dates were the first Sunday in April to the last Sunday in October. London changes its clocks on other Sundays (the last in March and the last in October), so on 170 of the ten years' 2,607 trading days London was 4 hours ahead of New York, not 5.

One more worked example

The week the clocks go back

In 2023 New York's clocks went back on Sunday 5 November. On Friday 3 November, still under daylight saving, the session's last bar, 15:55 New York, is stamped 15:55 + 4 = 19:55 UTC. On Monday 6 November (o = −5) the same bar is stamped 20:55 UTC. A fixed −5 reads Monday's stamp correctly, 20:55 − 5 = 15:55, but Friday's as 19:55 − 5 = 14:55: on Friday its “15:00–16:00” window holds no bars at all, and its “14:00–15:00” window is really 15:00–16:00.

Common mistakes

Check yourself

  1. How many 30-minute windows start on a half hour from 09:30 and end by a 16:00 close? A blind draw among them would be best in about how many of 1,000 markets?
    Answer

    Starts 09:30 to 15:30: 13 windows. 1,000 ÷ 13 = 76.9.

  2. A bar is stamped 15:30 UTC on 15 January. What is its New York time, and what would a fixed −5 say?
    Answer

    15 January is not under daylight saving, so o = −5: 10:30, and a fixed −5 says the same. The mistake only shows from the second Sunday in March to the first Sunday in November.

  3. In the lesson's simulation the first hour moved about one and a half times as much as midday. Does that make it a better window to buy in?
    Answer

    No. It rose on about 50 days in 100, like every window: the hour decided how far prices moved, not which way. Whether any hour leans up or down in a real market needs its own test.

  4. The found window averaged +4.8% a year before costs on the years it was picked from, against +0.9 for all 12 windows. Why did it average only +1.1 on the held-out years, against +1.0?
    Answer

    It was the best of 12 versions, so it was picked partly for luck in those years, and in markets with nothing to find the luck did not carry over. It stayed best in 90 of 1,000 markets, close to a blind draw's 83.

Try it yourself

The rules, written before the code. Five-minute bars, one session a day, 09:30 to 16:00 New York time. A one-hour window starting at time s: buy at the open of the bar starting at s, sell at the close of the bar starting at s + 55 minutes, every day. Starts every half hour from 09:30 to 15:00. 0.1% of the price per buy and per sell, or no costs. Compared with buying at the first close and holding, which pays 0.1% once. Each bar's UTC stamp is its New York time minus that date's offset from the time zone database; the mistaken clock subtracts 5 hours from every stamp.

Run the script. Every number in this lesson comes from one Python script (below). It imports simmarket.py, the course's simulated market, which must sit in the same folder, and Python's own zoneinfo time zone module. Add 30- and 90-minute windows and watch the version count and the blind draw move.

By hand. In a spreadsheet with one row per bar (UTC date and time in A), the New York time is =A2-IF(AND(A2>=S,A2<E),4,5)/24, with the year's daylight saving start and end (in UTC) in cells S and E. Check the first bar of a January day and of a July day.

Written by QuantWright from the plain idea of a session window and the rules above. No code from any indicator script or charting platform.

The code behind every number (Python, imports SimMarket, seed 20261109)
Loading…
For the preciseThe lesson's market: SimMarket Market 1, seed 20261109, effect=False (no planted pattern), five-minute bars built with bridge="normal" (no pull-back within the day), the same bars as the Previous day high and low lesson. The 1,000 simulated markets: the same generator and setting with seeds 2026201001 to 2026202000. Choosing years: from the close of 5 Jan 2015 to 31 Dec 2021 (6.99 calendar years, 1,824 trading days); held-out: to 31 Dec 2024 (3.00 years). % a year = (the account's growth factor)1 ÷ years − 1; a window's return is exit ÷ entry − 1; after costs each day is multiplied by 0.999². The lesson's market: holding 4.38% a year before its cost, 4.36% after (choosing), 10.00% (held-out). Its 12 windows on 2015–2021 before costs, from 09:30: +1.94, +0.41, −0.46, +1.58, +1.94, −1.27, −1.20, −2.08, −1.40, −2.28, −2.21, +3.61% a year. On 2022–2024: +5.74, −1.72, −0.34, +2.94, +0.86, +0.17, −1.82, −1.74, +0.49, +0.69, +5.85, +4.68. The 1,000 simulated markets: the 10:00–11:00 window beat holding before costs in 154 and after costs in 0 (choosing years); averaged +1.00% a year before costs and −40.09 after. Days the windows rose, in 100, from 09:30: 50.3, 50.0, 49.9, 49.9, 49.8, 49.8, 49.8, 49.9, 49.9, 49.9, 49.9, 50.1. Flat days (unchanged to the cent): 0.9 to 1.3 in 100 per window. The found window: picked from each of the 12 (from 09:30) 204, 88, 70, 75, 49, 68, 65, 54, 55, 62, 60, 150 times; best on the held-out years 188, 76, 74, 77, 66, 57, 60, 67, 73, 72, 76, 114 times. Clocks over the ten years: 1,700 daylight saving days (1,190 of the 1,824 choosing days), 170 days with London 4 hours ahead (120 choosing). The fixed clock against the right one: correlation of the 1,000 results 0.367, average difference 2.16 points a year, against a spread (standard deviation) of 2.52 for the right clock's results; it gained in 667 markets. The London-clock window (15:00–16:00 London): disagreed with the right clock in 110 markets, correlation 0.94, on the lesson's market −0.69% a year.

Honest notes

Where this comes from