Where SPXW 0DTE prints actually land in the quote

13,147,178 prints, 36,766,451 contracts, 38 sampled sessions, 2022-2026

Published 2026-08-24 · Sample SPXW 0DTE single-leg prints, regular hours, 38 sessions sampled from 2022-01-03 to 2026-08-03 · Source Muravyev & Pearson (2020), "Options Trading Costs Are Lower than You Think", Review of Financial Studies 33(11), 4973-5014 · Data licensed SPXW trade-and-quote tick tape with the prevailing NBBO carried per print · Status replication — measurement, not a signal

Muravyev and Pearson report that option executions cluster well inside the NBBO, so the effective spread a trader really pays is far below the quoted one: the average effective spread is one quarter smaller than conventional estimates, and for traders who time their executions it is less than 40% of the conventional measure. If that held on SPXW 0DTE, a long list of results on this site would deserve a second look, because the assumed transaction cost is the single parameter that has killed almost every one of them. It does not hold here. On 13,147,178 prints, 92.56% execute exactly on the bid or exactly on the ask, and the effective-to-quoted half-spread ratio is 0.9619 per print and 1.0697 per contract — volume-weighted, SPXW 0DTE prints pay slightly more than the full quoted half-spread, not less.

This is not a refutation of their paper. It is a failure to transfer, and the reason is mechanical rather than behavioural: on 71.91% of prints the quote is one tick wide, and a one-tick quote has no price inside it.

Why this was worth running

The companion measurement on this site prices a round trip in the ATM 0DTE SPX straddle at $34.72 / $35.14 / $36.30 per 1-lot at horizons of 15 / 30 / 60 minutes, charged as the full two-sided quoted spread plus $5.00 of fees (what a 0DTE straddle round trip costs). That cost line, or one like it, appears in every strategy post here, and it is usually the difference between a positive pre-cost number and a negative post-cost one. The honest reason to run this study was the hope that the line was too harsh — that real prints land inside the quote and the charged spread is a caricature. The result runs the other way, which is why it is worth publishing.

The measurement

For every single-leg 0DTE SPXW print in regular hours, with the NBBO prevailing at that print — carried with the print by the data source, not joined approximately from a separate quote file — two numbers:

pythonreproduce
loc = (price - bid) / (ask - bid)          # where the print sits in the quote
eff = |price - mid| / (0.5 * (ask - bid))  # effective half-spread / quoted half-spread

eff = 1 means the print paid the full quoted half-spread. eff = 0 means it executed at the mid. loc = 0 is the bid, loc = 1 is the ask, loc = 0.5 is the mid. Both are reported per print and per contract (volume-weighted). Nothing is tuned: every bucket edge below was fixed before the run.

Where the prints land

location in the quoteshare of printsshare of contracts
at or below the bid47.19%46.51%
… exactly at the bid46.68%
… strictly through the bid0.52%1.15%
at or above the ask46.41%48.66%
… exactly at the ask45.88%
… strictly through the ask0.53%1.24%
at the mid4.71%3.43%
strictly inside the quote6.40%4.83%

"At the mid" is |loc − 0.5| ≤ 0.02. The bid and ask rows overlap the strictly-through rows by construction: at-or-below = exactly-at plus strictly-through.

The headline follows directly. Per print the mean of eff is 0.9619; per contract it is 1.0697. Its deciles per print run 0.9991 / 0.9995 / 0.9999 / 1.0001 / 1.0003 / 1.0004 / 1.0006 / 1.0007 / 1.0009 — every decile sits on 1. (Those are read off a histogram with 0.001-wide bins, so the atom at exactly 1.000 reports as 1.0003; the true value is 1.000.) Only 1.05% of prints and 2.40% of contracts have eff > 1, i.e. traded through the quote. In dollars: the mean quoted half-spread is $0.05721 per print against a mean effective half-spread of $0.05240, a ratio of 0.916; contract-weighted it is $0.05506 quoted against $0.06373 effective, a ratio of 1.1574.

The interior of the spread is not a distribution — it is one point. Restricted to the 841,360 prints that land strictly inside (0 < loc < 1), the deciles of loc are 0.3338 / 0.4993 / 0.4997 / 0.5001 / 0.5003 / 0.5005 / 0.5007 / 0.5009 / 0.6662. Seven of the nine sit between 0.4993 and 0.5009. When an SPXW 0DTE print does land inside the quote, it lands at the mid and nowhere else.

The mechanism: the quote is one tick wide

This is the part worth reading. Price improvement on SPXW 0DTE is not rare because traders are impatient. It is rare because there is no room.

quoted spread, ticksprints% of printscontracts% of contracts
19,454,42771.91%27,561,52574.96%
22,891,60821.99%7,146,38919.44%
3458,5653.49%1,135,1483.09%
4151,0121.15%360,3470.98%
571,1470.54%197,0110.54%
6-1090,5140.69%265,4410.72%
>1029,9050.23%100,5900.27%

A tick is $0.05 below a $3 mid and $0.10 above it.

A one-tick quote has no price inside it. Improvement is not merely unlikely on 71.91% of prints and 74.96% of contracts — it is arithmetically impossible. So the fair test is the restriction to quotes with room in them: on the 3,692,751 prints (9,204,926 contracts) whose quote is at least two ticks wide, the at-mid share rises to 16.78% per print and 13.72% per contract, against 4.71% overall. The behaviour Muravyev and Pearson describe does exist on this tape. It simply has almost nowhere to happen.

The two cuts their mechanism predicts, both running the wrong way

A headline number failing is weak evidence: samples differ, definitions differ, and a single mean can miss for uninteresting reasons. A mechanism failing on its own predicted cuts is stronger. Their story says improvement is captured by traders with discretion over timing, which predicts a time-of-day pattern and a size pattern. Neither appears.

Time of day is flat. Seven hourly buckets, no open effect, no close effect:

hour (ET)printscontractseff, per printat the mid
09:30-09:591,436,4753,795,2420.96384.72%
102,568,7587,024,9500.96544.51%
111,829,2595,057,2140.95874.91%
121,583,6824,524,2980.95964.82%
131,504,6104,397,7990.95835.13%
141,931,9125,631,4440.96284.76%
152,292,4826,335,5040.96264.40%

The whole range is 0.9583 to 0.9654 — seven hundredths of one percent of the half-spread between the best and worst hour of the day.

Size runs backwards. If large traders were the patient ones capturing the mid, eff would fall with size. It rises, steeply, and it rises the same way at the money:

trade size, contractsprintscontractseff, all strikeseff, ATM only
18,481,5208,481,5200.94660.9425
2-53,392,25910,101,0990.97400.9753
6-201,113,55810,945,6791.01361.0167
21-100153,3685,912,4131.13831.1855
101-5006,2391,116,0481.58042.1199
>500234209,6924.48514.1192

ATM is |K − F|/F < 0.25%, F from per-minute put-call parity on the tape's own quotes. The ATM print counts run 4,314,432 / 1,928,358 / 570,215 / 45,152 / 1,316 / 33 down the same buckets.

The 1-lot is the only bucket that beats the quoted half-spread, at 0.9466, and it beats it by five percent. Everything above 20 contracts pays more than the full half-spread, and above 500 contracts a print pays 4.49 times it. Large SPXW 0DTE trades print through the quote; they do not capture improvement. That is the opposite of the size gradient the improvement story requires, and it holds on the ATM subsample where the liquidity is.

Stability

Nothing here is a property of one year or one session.

yearprintscontractseff, per printat the mid
2022954,3543,216,2980.92146.27%
20231,536,4384,779,8140.95805.38%
20242,373,3607,366,0300.95975.11%
20254,013,50710,657,7080.96404.63%
20264,269,51910,746,6010.97173.98%

The ratio drifts, and it drifts up toward 1 as quotes tighten and the one-tick share grows: the at-mid share falls from 6.27% in 2022 to 3.98% in 2026. Across the 38 individual sessions the per-print ratio runs from 0.877 (2022-04-01) to 1.0109 (2025-02-03) — a band that never approaches the 0.75, let alone the 0.40, that the paper's effect sizes would imply.

Translating it back into the round trip

The companion study charges the full two-sided quoted spread. Replace that with the measured one. At the ATM cell — 6,859,506 prints, 17,346,952 contracts — the mean quoted half-spread is $0.06183 per contract against a mean effective half-spread of $0.06347, so the contract-weighted ratio is r = 1.0265. The round-trip cost is $5.00 of fees plus a spread component S; the improvement-adjusted version is $5.00 + r × S.

horizonfull-spread costspread component Sradjusted costchange
15 minutes$34.72$29.721.0265$35.51−$0.79
30 minutes$35.14$30.141.0265$35.94−$0.80
60 minutes$36.30$31.301.0265$37.13−$0.83

"Change" is negative because the adjustment makes the trade more expensive: 79 to 83 cents worse per 1-lot. As a share of the mean absolute mid-to-mid P&L the cost goes from 21.8% to 22.3%, 13.1% to 13.4%, and 7.8% to 8.0%.

An independent cross-check that the two studies are measuring the same market: a straddle round trip crosses four half-spreads (call and put, in and out), so at the measured ATM quote that is 4 × $0.06183 × 100 = $24.73 per 1-lot, against the companion study's implied spread component of $29.72 / $30.14 / $31.30. Same order, the companion slightly larger, which is what a slightly wider ATM definition and a different sample window should produce.

One assumption would have been needed for any relief, and it is worth stating even though the sign makes it moot. eff measures where the average print lands. A backtest fill is not an average print: the measured population contains patient limit orders resting inside the spread and dealer-to-dealer prints, and a taker who must trade at a specific moment — which is what every signal backtest on this site requires — has no claim on their improvement. The adjusted column is therefore a lower bound on cost and an upper bound on relief. Here the adjustment is negative to begin with, so the caveat only makes the conclusion firmer: the cost line in the companion study was slightly generous, not too harsh.

Sampling and exclusions

This is a print-level study over 20 million rows, so the archive is sampled rather than swept, and the rule was fixed before anything was run. For each year 2022-2026, take the first available session on or after the 1st of each of eight months — January, February, April, May, July, August, October, November. The four skipped months are the quarter-end ones, whose triple-witching sessions carry atypical 0DTE flow. The calendar is the SPXW expiration list (1,129 dates in the window), not the archive's session list, because a 0DTE study can only run on a day that is itself an expiry. A session that failed to load or yielded fewer than 1,000 usable prints would have been replaced by the next in the calendar and the replacement reported: 38 sessions, zero replacements.

Of 20,709,094 raw prints, 7,559,103 were multi-leg legs (a condition code counts as multi-leg when at least 80% of its prints share an exact timestamp with two or more distinct contracts), 2,807 carried a zero-width quote, and 6 fell outside regular hours. No crossed quotes, no non-finite quotes, no non-positive asks. 13,147,178 prints and 36,766,451 contracts retained.

Stale quotes would bias this study toward more apparent improvement, not less: if the NBBO recorded with a print is old, a print at the true mid can look like it beat the quote. Restricting to prints whose quote is under one second old leaves 12,945,798 prints and 35,415,585 contracts, and changes nothing — mean eff 0.9616 per print and 1.0722 per contract against 0.9619 and 1.0697 on the full set.

What it does not say

It does not refute Muravyev and Pearson. Their paper is about a broad cross-section of equity and index options over a long window; this is SPXW 0DTE only, on 38 sampled sessions, in a contract that barely existed when their data was collected. The correct reading is that their result does not transfer to this instrument, and the tick table says why: their mechanism needs a quote with room inside it, and SPXW 0DTE mostly does not have one. On their own data, on their own universe, nothing here speaks to their finding at all.

It is 38 sessions, not the full archive — the reason is cost, not convenience: each session is roughly half a million usable prints and the study reads over 20 million rows. The sample is spread across five years and every year gives the same answer, but a rule fixed on the 1st of eight months is still a rule, and a different rule would give slightly different decimals. The moneyness cut uses a forward from per-minute put-call parity on the tape's own quotes, because no independent SPX spot series exists on disk for the sampled sessions. And nothing here says anything about what a specific order would have been filled at — only about where the population of prints landed. Nothing on this page is investment advice; see the Terms.

Reproduce it

This one is honestly not free, and there is no free path to it. Measuring where a print lands inside the quote requires the trade tape with the prevailing NBBO attached to each print — not a quote file joined to a trade file after the fact, which introduces exactly the staleness this study has to rule out. The tape behind this post is licensed: ThetaData (thetadata.net), at the subscription tier that serves /v3/option/history/trade_quote for SPXW. That endpoint returns price, size, condition, bid, ask, bid_size, ask_size and a quote_timestamp per print, which is the whole input. With that subscription the study is an afternoon's work:

pythonreproduce
import numpy as np, pandas as pd

# one session of SPXW 0DTE prints from /v3/option/history/trade_quote,
# columns: price, size, condition, bid, ask, quote_timestamp, trade_timestamp
t = pd.read_parquet("spxw_2026-08-03.parquet")

t = t[(t.ask > t.bid) & np.isfinite(t.bid) & np.isfinite(t.ask)]   # drop zero-width, crossed
t = t[(t.trade_timestamp >= 34200000) & (t.trade_timestamp < 57600000)]  # 09:30-16:00 ET
# drop multi-leg: a condition is multi-leg if >= 80% of its prints share an exact
# timestamp with 2+ distinct contracts -- tag it once per session, then filter
t = t[~t.condition.isin(multileg_conditions(t))]

mid  = 0.5 * (t.bid + t.ask)
half = 0.5 * (t.ask - t.bid)
loc  = (t.price - t.bid) / (t.ask - t.bid)     # 0 = bid, 0.5 = mid, 1 = ask
eff  = (t.price - mid).abs() / half            # 1 = paid the full quoted half-spread

print(np.average(eff), np.average(eff, weights=t["size"]))          # 0.9619, 1.0697
print(((loc <= 0) | (loc >= 1)).mean())                             # 0.9256 of prints
ticks = np.where(mid < 3, 0.05, 0.10)
print(((t.ask - t.bid) / ticks).round().eq(1).mean())               # 0.7191 one tick wide

What is free on our side is everything the cost translation is applied to. The finished sessions are listed at /sessions, and each one's per-minute series is in its JSON at https://gex.live/snapshots/YYYY-MM-DD.json — including straddle, the ATM 0DTE straddle mid in index points, which is the premium the $34.72 / $35.51 above is charged against. Those files carry mids, not quotes, so they can reproduce the premium and the P&L of the companion study but not the spread: this post's entire subject is the one thing a mid-only file cannot see.

Part of gex.live research. Measured on the free session archive; every session is free to replay.