How far does SPX travel before the close?
An empirical touch surface: 1,082 sessions, 404,130 minute-observations
Every intraday level — a wall, a flip, yesterday's high, a round number — invites the same question: what are the odds we get there before the close? The honest answer is not a model. It is how often it happened. For every minute of every archived session the rest of the day is known, so the running maximum and minimum of the forward path say, for every candidate distance at once, whether price reached that far. Pool 1,082 sessions and you have a frequency table instead of an assumption.
The surface
Rows are minutes left in the session; columns are distance from spot in sigma units; cells are the share of minute-observations whose forward path reached at least that far, up or down pooled. Read: "with 60–120 minutes left, a level 1.12σ away was reached 28.3% of the time."
| minutes left | ≥0.12σ | ≥0.38σ | ≥0.62σ | ≥0.88σ | ≥1.12σ | ≥1.38σ | ≥1.75σ | ≥2.25σ | ≥2.75σ | ≥3.5σ | ≥5σ |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 300–391 (open → 10:30) | 81.9 | 57.4 | 39.0 | 25.1 | 15.7 | 9.9 | 5.4 | 2.5 | 1.3 | 0.6 | 0.2 |
| 210–300 | 85.8 | 64.9 | 47.5 | 34.1 | 24.4 | 17.0 | 10.1 | 5.3 | 3.2 | 1.7 | 0.7 |
| 120–210 | 85.9 | 67.3 | 51.3 | 38.6 | 28.7 | 21.3 | 13.8 | 8.0 | 4.7 | 2.5 | 1.2 |
| 60–120 | 85.7 | 67.5 | 51.4 | 38.5 | 28.3 | 20.6 | 12.8 | 6.8 | 3.8 | 1.7 | 0.5 |
| 30–60 | 85.1 | 67.8 | 52.1 | 39.3 | 28.9 | 21.1 | 13.2 | 7.2 | 4.2 | 2.0 | 0.4 |
| 15–30 | 83.2 | 68.3 | 54.3 | 42.2 | 32.1 | 24.2 | 15.6 | 9.1 | 5.3 | 2.4 | 0.4 |
| 0–15 (last quarter hour) | 74.9 | 62.3 | 50.7 | 40.6 | 31.9 | 24.5 | 16.4 | 9.8 | 5.5 | 2.3 | 0.4 |
Percent of minute-observations. Every row pools 1,073–1,082 sessions; the thinnest row (last 15 minutes) rests on 10,820 observations, the thickest on 97,290. Means are day-clustered: a session's 390 minutes count as one observation, not 390.
How distance is measured
Points are the wrong unit: 20 points is a formality on a wild day and unreachable on
a quiet one. Distance here is in units of the move the tape was already making —
the trailing 30-minute realised move per minute, projected over the minutes remaining:
σ = rv30 × √(minutes left). It uses only information available at
that minute, so there is no lookahead, and it needs no option chain, so it can be rebuilt
from price alone. Touches are judged on minute closes (see the caveat below), and a
minute counts only if at least five minutes remain.
Three things the table says
Beyond 2σ the surface is flat and small. A level 2.25σ away is reached 2.5–9.8% of the time whatever the clock says, and at 2.75σ the range is 1.3–5.5%. That is the number any "this level held 9 days in 10" claim has to be compared against — and it is exactly what the hold-rate study does.
The opening row is the quietest, not the wildest. For the same σ-distance, reach is lowest with 300+ minutes left. The reason is the scaler: in the first half hour the trailing 30-minute move is the opening volatility, the highest of the day, so "one sigma" at 10:00 is more points than "one sigma" at 13:00 — and the afternoon does not deliver what the open implied. A sigma built from the opening half hour overstates the rest of the session.
The last quarter hour under-reaches at short range. With five to fifteen minutes left even 0.12σ is reached only 75% of the time, against 85% mid-session. A walk of five steps rarely reaches its own sigma; that is discreteness, not mean reversion.
What it is not
This is the unconditional surface: it knows nothing about dealer positioning, the flip, the walls or the band. That is deliberate — it is the benchmark a conditional claim must beat, not a claim itself. Nothing on this page is investment advice; see the Terms.
Caveat
Touches are measured on minute closes, not the per-second path. An intra-minute spike that reached a level and came back is invisible here, so every probability in the table is a lower bound. The bias is the same in every cell, so differences between cells are meaningful even where a single cell is not.
Reproduce it
The grid itself is what the terminal serves: https://gex.live/touch.json —
t and u are the bucket midpoints, grid[t][u] the
probability, sessions the sample. To rebuild it, every finished session's
minute series is in its JSON at https://gex.live/snapshots/YYYY-MM-DD.json
(fields minutes and spot; about 7 MB per day — please fetch
sequentially). The dates are the ones listed at /sessions. The
computation, in full:
import numpy as np, pandas as pd s = np.array(day["spot"], float) # one session, 389 one-minute prints r = np.diff(np.log(s), prepend=np.nan) rv = pd.Series(r).rolling(30, min_periods=10).std().values * s # trailing move, points left = len(s) - 1 - np.arange(len(s)) # minutes to the close sig = rv * np.sqrt(np.maximum(left, 1)) fmax = np.maximum.accumulate(s[::-1])[::-1] # forward extremes from each minute fmin = np.minimum.accumulate(s[::-1])[::-1] ok = np.isfinite(sig) & (sig > 1e-9) & (left >= 5) up, dn = (fmax - s)[ok] / sig[ok], (s - fmin)[ok] / sig[ok] # per (minutes-left bucket, u): mean over sessions of the session's share of # minutes with up >= u (and dn >= u), pooled
Published session pages summarise each day's levels in prose (archive); the MCP server returns the same summaries to an assistant. Neither is needed for this table — price alone rebuilds it.
Part of gex.live research. Measured on the free session archive; every session is free to replay.