Do SPX option returns change sign from day to night?
Muravyev & Ni (2020) on our tape: 1,082 sessions, 3,779,175 delta-hedged contract-windows
The paper makes one of the cleanest falsifiable claims in the option literature: the entire short-volatility premium in S&P 500 options is earned overnight. Their delta-hedged index option returns average −0.7%/day, and the decomposition is −1.0%/day close-to-open against +0.3%/day open-to-close. Option prices, they argue, fail to account for volatility being much higher intraday than overnight, so the premium sits entirely in the night.
For this site that claim is worth more than most. If it holds, it explains in one line why every intraday short-volatility variant we have tested has died — they were all fighting a +0.3%/day headwind — and it says 0DTE is the worst possible vehicle for harvesting the premium, because a contract born and killed inside one session has no overnight leg at all. That is a statement about our whole research direction, which is why it ranked first in the literature sweep.
It does not transfer. On 1,082 SPX sessions and 3,779,175 hedged contract-windows, there is no measurable day/night split. The naive pooled specification does print one — and prints it with the sign reversed, +1.005% overnight and −1.614% intraday — but two diagnostics in this study show that reversal is an artefact of how the return is measured, not a fact about the tape. On the specifications immune to either artefact, night and day are both statistically zero. A post that reported the reversal as a finding would be making exactly the mistake this study caught itself making, so the headline is the null: the split is not there, in either direction.
What is being tested, and what is excluded
The paper's object must survive a night to have an overnight return at all. A 0DTE contract does not, so 0DTE is structurally outside this test and is excluded by construction. That exclusion is the whole reason the study exists: it is the only way to find out whether the thing 0DTE supposedly misses is actually there.
The maturity band is 5 to 30 calendar days to expiry, measured at the
anchor snapshot (the close of session t), and it was chosen from what the chain
store carries rather than from any return. Across 23,355 chain files the per-DTE count is
dense and near-flat from DTE 1 to DTE 30 — at least 580 files per DTE — and then collapses:
383 at DTE 30, 252 at 31, 85 at 33, single digits past 34. So 30 is the store's own natural
ceiling; 5 is a floor that keeps four more nights of life in the contract after the window
being measured. Moneyness band |ln(K/F)| ≤ 0.10. The bands were set once,
before any return was computed, and never revisited.
The windows: overnight is the last valid stamp of session t to the first valid stamp of session t+1; intraday is that first stamp to the last stamp of t+1. The same contract must be quoted two-sided and invertible at all three snapshots, so the day and the night are measured on an identical contract set and are directly comparable. Overnight windows whose calendar gap exceeds one day — weekends, holidays, archive gaps — are flagged and reported separately throughout. A three-day gap is not a night, and it is never pooled into one here.
What that leaves: 19,551 chain files read, 18,424 (session, expiry) pairs in band with both snapshots, 3,779,175 contract-windows — 2,993,759 single-night and 785,416 multi-day. Mean DTE 16.9 days, mean option mid $113.21, mean overnight window 27.73 hours against a mean intraday window of 6.44 hours. Standard errors are day-clustered everywhere: all contract-windows sharing a calendar day collapse to one equal-weighted daily observation first, and every mean, SE and t below is computed across days.
The hedge, because a shortcut here would have made the number
No delta column exists anywhere in this repo, and the surface store holds two days out
of 1,084 — so delta is derived from the chain itself, and the derivation is the part of
this study most able to fabricate a result. It is done as follows. At every snapshot, for
every expiry, the discount factor and forward are recovered from put-call parity by
regressing call-minus-put mid on strike across ATM strikes:
mid_call(K) − mid_put(K) = D·F − D·K. The fit uses only strikes quoted
two-sided on both rights within ±2.5% of the zero-crossing strike, at least six of them, and
is rejected unless R² > 0.999 and D lands in (0.90, 1.02).
Implied vol is then inverted from the mid by Black-76, and delta is the Black-76
forward delta.
The hedge instrument is the expiry-matched synthetic forward — the
option is hedged with its own expiry's synthetic, which is what an SPX hedger actually
trades, and which makes the hedge exact instead of approximate. Hedging in spot would have
required a dividend assumption; the forward is observable. The size of what that shortcut
would have cost is easy to state concretely: on 2026-08-17 at 12:00 the September forward
comes out at 7790.3 against a spot of 7772.1 — about 2.9%
annualised carry that a spot hedge at r = 0 would have silently dumped into the
option, every day, in one direction.
Returns are scaled per dollar of the option's own price: R = [P(t1) − P(t0) −
Δ(t0)·(F(t1) − F(t0))] / P(t0). That is the paper's convention and it is what makes
−1.0%/day a percentage of the premium rather than of the notional. It is also, as the next
two sections show, the convention that does the damage.
The headline
Delta-hedged return, percent of the option's price per window, mid-to-mid, day-clustered. Positive means a long option position made money.
| specification | windows | overnight % | t | intraday % | t |
|---|---|---|---|---|---|
| pooled | 3,779,175 | +1.005 (0.369) | +2.73 | −1.614 (0.452) | −3.57 |
| calls | 1,903,235 | +1.523 (0.325) | +4.68 | −1.931 (0.459) | −4.20 |
| puts | 1,875,940 | +0.499 (0.478) | +1.04 | −1.298 (0.544) | −2.38 |
| single-night only | 2,993,759 | +0.819 (0.264) | +3.10 | −0.866 (0.550) | −1.58 |
| multi-day gap only | 785,416 | +1.639 (1.351) | +1.21 | −4.153 (0.657) | −6.32 |
| mid ≥ $1 at all three | 3,505,557 | +0.206 (0.319) | +0.65 | −0.905 (0.361) | −2.51 |
| ATM, |k| ≤ 0.02 | 1,314,423 | +0.177 (0.223) | +0.80 | −0.285 (0.337) | −0.85 |
| price-weighted | all windows | +0.064 (0.098) | +0.65 | −0.133 (0.089) | −1.50 |
Standard error in brackets, day-clustered across 1,081 days (835 single-night days, 246 multi-day). Price-weighted is sum of hedged gains over sum of option prices, so a $2 contract does not count as much as a $200 one.
Nothing in the paper's direction survives anywhere in that table: no cut is negative overnight and positive intraday. The pooled row instead points the other way with t = +2.73 and −3.57. But look at the last two rows. The moment small-premium contracts stop dominating the average — either by requiring a $1 price at all three snapshots, by restricting to ATM, or by weighting by price — the split collapses toward zero and every t falls below 2. Two rows disagree with the other six, and the two are the ones that are not exposed to a mean-of-ratios problem.
Why the pooled number is not the finding
Scaling by the option's own price is standard and it is what the paper does, but it turns a cheap contract into a lever. Break the same windows down by moneyness and the whole pooled result is visible in one row:
| bucket, k = ln(K/F) | windows | overnight % | intraday % | median mid $ | median spread % |
|---|---|---|---|---|---|
| k < −0.05 | 801,911 | +0.908 (t +1.42) | −2.213 (t −4.44) | 24.15 | 4.03 |
| −0.05 ≤ k < −0.02 | 891,760 | +0.406 (t +1.19) | −0.905 (t −1.95) | 77.50 | 4.76 |
| |k| ≤ 0.02 (ATM) | 1,314,423 | +0.177 (t +0.80) | −0.285 (t −0.85) | 69.15 | 4.71 |
| 0.02 < k ≤ 0.05 | 520,384 | +3.649 (t +7.34) | −3.560 (t −5.00) | 40.40 | 6.38 |
| k > 0.05 | 250,697 | +9.387 (t +7.87) | −7.002 (t −5.91) | 2.95 | 9.09 |
The far out-of-the-money calls print ±7 to 9 percent per window on a median mid of $2.95 with a median quoted spread of 9.09% — and a mean quoted spread of 23.85%. That is not a return, it is a small denominator. A one-cent move in the mid of a three-dollar option is a third of a percent; a tick of quote noise that reverses the next morning is a large positive number in one window and a large negative number in the next, and the equal-weighted mean of ratios happily reports the pair as a day/night split. The two specifications built to be immune to that — ATM and price-weighted — say +0.177 / −0.285 and +0.064 / −0.133, with every t under 1.5.
The closing mark manufactures day/night splits
This is the most transferable thing in the study, and anyone measuring a day/night effect in options should read it before trusting their own number. Our last chain stamp is 16:00, the cash close, on 3,733,621 of the windows. SPX options trade on to 16:15. Any systematic bias in the 16:00 mid relative to the next morning's 09:35 mid appears as +X overnight and −X intraday — a split out of nothing, with the sign determined by which way the mark is stale.
So the whole study was re-run with the closing snapshot forced to 15:55 or earlier, everything else identical. The first thing that moves is the quotes themselves: mean relative quoted spread at the close drops from 7.76% to 5.30% (median 4.93% → 2.93%). The 16:00 book is measurably wider than the 15:55 book. The second thing that moves is most of the result.
| specification | close at 16:00 | close at 15:55 or earlier |
|---|---|---|
| pooled, overnight | +1.005 (t +2.73) | +0.305 (t +0.85) |
| pooled, intraday | −1.614 (t −3.57) | −0.950 (t −2.12) |
| single-night, overnight | +0.819 (t +3.10) | +0.114 (t +0.44) |
| ATM, overnight | +0.177 (t +0.80) | +0.030 (t +0.13) |
| ATM, intraday | −0.285 (t −0.85) | −0.136 (t −0.41) |
| k > 0.05, overnight | +9.387 (t +7.87) | +6.873 (t +5.30) |
| price-weighted, overnight | +0.064 (t +0.65) | +0.019 (t +0.19) |
| full day, close to close | −1.499 (t −2.64) | −1.474 (t −2.67) |
| mean relative quoted spread | 7.76% | 5.30% |
Read the last two rows together with the first. Roughly 70% of the split is the 16:00 mark — the pooled overnight number falls from +1.005 to +0.305 and stops being significant, single-night falls from +0.819 to +0.114 — while the daily total is untouched at −1.499 versus −1.474. Moving the close moves how the day is cut in two and does not move what the day was. That is the signature of a measurement artefact rather than an economic effect, and it is exactly what a stale closing mid would do.
The daily total is worth a line of its own, because it is the one place this tape agrees with the paper. Close-to-close, a delta-hedged long option position loses money — pooled −1.499% per day, the same sign as their −0.7%/day and larger. What fails to transfer is the decomposition, not the total. And the total is itself concentrated in the same cheap contracts:
| full day, close(t) → close(t+1) | mid-to-mid % | t |
|---|---|---|
| pooled | −1.499 (0.569) | −2.64 |
| mid ≥ $1 at all three | −0.993 (0.473) | −2.10 |
| calls | −1.310 (0.552) | −2.37 |
| puts | −1.697 (0.706) | −2.40 |
| ATM, |k| ≤ 0.02 | −0.233 (0.371) | −0.63 |
What it costs to actually do it
Every number above is marked at mid, which is what the published claim almost certainly is. Charge the full quoted option spread at both ends of every window — buy at the ask, sell at the bid, which is what a trader who closes at the bell and reopens at the open pays — and the arithmetic ends the discussion:
| crossing the spread | overnight % | intraday % |
|---|---|---|
| pooled | −6.610 (t −19.40) | −8.164 (t −19.93) |
| ATM, |k| ≤ 0.02 | −4.359 (t −20.05) | −4.923 (t −15.28) |
| cost drag vs mid | −7.616 pp | −6.550 pp |
That is −14.166 pp per full day of round-trip cost, against a mid-marked edge that the honest specifications put at a fraction of one point. The full day crossing the spread is −16.349% (t = −29.59). And the hedge leg is charged nothing in that calculation, so even −14.166 pp understates it. Costs are roughly ten times any mid-marked effect in this study, in a specification where the effect is not statistically distinguishable from zero to begin with — the same conclusion the round-trip cost study reached from the other end.
The premise is right, and the market has already priced it
The null headline is not the whole result. The mechanism the paper describes is real on this tape, measured directly, and it is the part of the study that stands up.
First, the variance asymmetry, computed from the index alone — overnight is the squared close-to-open log return, intraday the sum of squared one-minute log returns:
| window | mean variance | RMS move % | annualised vol % | hours | days |
|---|---|---|---|---|---|
| overnight, all | 4.713e-05 | 0.6865 | 12.20 | 27.73 | 1,081 |
| overnight, single night | 3.615e-05 | 0.6012 | 13.45 | 17.50 | 835 |
| overnight, multi-day gap | 8.442e-05 | 0.9188 | 10.52 | 66.77 | 246 |
| intraday | 6.231e-05 | 0.7894 | 29.10 | 6.44 | 1,081 |
Per hour, intraday variance is 9.670e-06 against an overnight 1.700e-06 — a ratio of 5.69×. In annualised terms the index runs at 29.10% vol while the market is open and 12.20% while it is shut. The paper's premise is confirmed, and it is confirmed without touching an option.
Second, the bill. Black-76 theta accrued over the window, as a percent of the option's price, is −9.023% overnight against −2.483% intraday pooled (ATM: −4.876 against −1.351). Calendar decay charges roughly 3.6 times as much for the night as for the day, while the night delivers a fifth of the variance per hour. That mismatch is precisely the setup for the paper's overnight loss.
And yet nothing shows up in the returns — because the quotes move first. ATM implied vol rises +0.416 vol points overnight (t = +15.51) and gives back −0.423 intraday (t = −15.94):
| ATM implied vol change, vol points | overnight | t | intraday | t |
|---|---|---|---|---|
| pooled | +0.416 (0.027) | +15.51 | −0.423 (0.027) | −15.94 |
| single night | +0.166 (0.022) | +7.55 | −0.423 (0.030) | −14.17 |
| multi-day gap | +1.263 (0.067) | +18.77 | −0.425 (0.058) | −7.33 |
Mean ATM implied vol runs 15.03% at the close, 15.39% at the next open, 15.00% at the next close. It is a daily cycle, it is enormous in t-statistic terms — by far the most significant thing in this study — and it points in exactly the direction that cancels the theta-versus-variance mismatch. The option gets marked up over the quiet night and marked back down over the noisy day, and the two legs of the hedged return come out to roughly nothing.
That is this post's actual contribution. The asymmetry the paper identified is real and measurable on 2022–2026 SPX. What is no longer available is the money: on this tape the market quotes the night at a premium to the day, and the day/night return split that premium was supposed to leave behind is gone.
Every regime, same answer
Split by year and by half. If the published effect were here in any regime, one of these rows would be negative overnight and positive intraday. None is.
| period | days | overnight % | t | intraday % | t |
|---|---|---|---|---|---|
| 2022 | 174 | +0.515 (0.567) | +0.91 | +0.174 (1.205) | +0.14 |
| 2023 | 250 | +0.229 (0.361) | +0.64 | −1.504 (0.666) | −2.26 |
| 2024 | 252 | +1.746 (0.711) | +2.46 | −1.982 (0.943) | −2.10 |
| 2025 | 249 | +1.175 (1.208) | +0.97 | −1.638 (1.122) | −1.46 |
| 2026 | 156 | +1.327 (0.872) | +1.52 | −3.154 (1.158) | −2.72 |
| pre-2024 | 424 | +0.347 (0.315) | +1.10 | −0.815 (0.632) | −1.29 |
| post-2024 | 657 | +1.430 (0.571) | +2.51 | −2.130 (0.622) | −3.43 |
Every overnight cell is positive, which is the wrong sign for the paper, and every intraday cell after 2022 is negative, which is also the wrong sign. Run the same split on the ATM specification — the one not contaminated by penny wings — and no year reaches t = 2 in either window: the largest is 2022 overnight at +0.711 (t = +1.82) and 2026 intraday at −1.134 (t = −1.50). The multi-day gaps behave the same way and are kept out of every "night": gap = 1 day is +0.819, gap = 3 days is +0.303 (t = +0.32), gap = 4 days is +0.421 (t = +0.19). The gap = 2 bucket prints +17.400 on 19 days with a standard error of 13.869 — 19 days is not a sample, and it is reported here only because leaving it out of the table would have been a choice.
What this changes for our own programme
The sweep's inference was that 0DTE is the worst possible vehicle for the volatility premium because it misses an overnight leg where all the money is. That inference is not supported here. On this tape there is no overnight premium to miss, so a 0DTE structure is not forgoing one. Whatever kills intraday short volatility on SPX, it is not the absence of a night — it is the spread, at −14.166 pp per round trip against a mid-marked edge that is statistically zero. That reorders what is worth testing next: not "hold it overnight to capture the premium", but "stop paying the spread".
What it does not say
This is 2022–2026 SPX only, against a paper with a much longer and much broader sample — index options plus equity options, ending before the daily-expiry regime began. This is therefore a failure to transfer, not a refutation of their result on their data. Their sample is pre-2020 by construction; ours starts in 2022. Both statements can be true: the premium was there and is not any more, or it is there in instruments and years we do not observe. Nothing here tests either possibility. What this study can say is that a trader operating on SPX between 2022 and 2026 would not have found the day/night split described.
The mid-fill caveat cuts both ways: our mid-marked nulls are as gross as their mid-marked −1.0%, and neither is a tradable number. The hedge is static within each window, rebalanced only at the open and the close, which is the paper's own construction — the intra-window gamma P&L is deliberately inside the return, since that is where realised variance gets paid. The forward hedge carries one night of carry (~1bp) inside the overnight window, which is inside the noise of everything reported. Delta is derived, not observed; the parity fits that produce it are rejected below R² = 0.999, but a derived delta is still a modelled delta.
Full exclusion counts, so nothing is hidden: 980,904 contracts dropped by the moneyness band, 900,725 dropped for not being quoted at all three snapshots, 507 session-expiry pairs missing a snapshot, 7 expiry-snapshots whose open stamp fell after 09:45, 5 whose close fell before 15:45, 4 that failed the parity fit, 2 sessions dropped by the contiguity walk, 0 sessions without chain files. The span holds 1,133 business days against 1,082 sessions archived; the 51 absent days are US holidays plus a handful of archive gaps, and they appear as gap = 2 and gap = 4 overnight windows, reported separately and never pooled into a night. Nothing on this page is investment advice; see the Terms.
Reproduce it
The option side is licensed data and cannot be made free here. Redoing the return tables requires a ThetaData subscription (thetadata.net) carrying the SPX/SPXW chain — five-minute full-chain quotes with bid, ask, sizes and expiration, 09:30 to 16:00 ET. Reproducible does not mean free. What a reader with that data needs is the construction, which is stated here in full, because the derived delta is where a replication would diverge:
import numpy as np # 1. discount factor and forward, per (stamp, expiry), from put-call parity. # NOT assumed: measured off the chain, so no dividend or rate input is needed. m = chain.pivot_table(index="strike", columns="right", values="mid").dropna() K = m.index.values.astype(float) d = (m["CALL"] - m["PUT"]).values # = D*F - D*K, linear in K K0 = K[np.argmin(np.abs(d))] # zero crossing = the ATM strike sel = np.abs(K / K0 - 1.0) <= 0.025 # ATM +-2.5%, at least 6 strikes b, a = np.polyfit(K[sel], d[sel], 1) D, F = -b, a / -b # reject unless R2 > 0.999 and 0.90 < D < 1.02 # 2. implied vol inverted from the MID by Black-76 (60-step bisection on 1e-3 .. 5.0). # T is ACT/365 calendar time to 16:00 ET on the expiry date. sig = bisect(lambda v: b76(F, K, T, v, D, is_call) - mid, 1e-3, 5.0) # 3. Black-76 FORWARD delta. The hedge instrument is the expiry-matched synthetic # forward from step 1 -- exact, not approximate, and no dividend assumption. d1 = (np.log(F / K) + 0.5 * sig * sig * T) / (sig * np.sqrt(T)) delta = D * N(d1) if is_call else D * (N(d1) - 1.0) # 4. hedged gain over a window, per dollar of the option's own price G = P1 - P0 - delta * (F1 - F0) R = G / P0 # overnight: last stamp of t -> first stamp of t+1. intraday: that stamp -> last of t+1. # same contract must be invertible at all three, else the day and night are not comparable.
The variance decomposition in the mechanism section — the 5.69× ratio, the whole table —
needs price alone, and price is free on this site. Every finished session's
JSON at https://gex.live/snapshots/YYYY-MM-DD.json carries the per-minute index
series as minutes and spot, 09:30 to 15:59 ET; the dates are listed
at /sessions. That is the same series the table above was built
from:
import json, urllib.request, numpy as np def day(d): # about 7 MB per session -- fetch sequentially u = "https://gex.live/snapshots/" + d + ".json" return json.load(urllib.request.urlopen(u)) s = np.array(day("2026-08-11")["spot"], float) # 09:30 .. 15:59, one print per minute rv_intraday = (np.diff(np.log(s)) ** 2).sum() # sum of squared 1-minute log returns rv_overnight = np.log(s[0] / prev_close) ** 2 # prev_close = previous session spot[-1] # average each over the sessions, then divide by hours: 6.44 intraday, 27.73 overnight. # gaps > 1 calendar day are a weekend or a holiday, not a night -- keep them separate.
Run that over the archive and the intraday-to-overnight variance ratio per hour comes out at 5.69×, with no option data at all. The half of this study that needed a licence is the half that found nothing.
Part of gex.live research. Measured on the free session archive; every session is free to replay.