Strasmore Research
Learn Matt ConnorBy Matt Connor · Updated 2026-08-13

When Do 0DTE Options Trade? By the Hour

0DTE options trade heaviest in the morning, not at the close: hourly volume, the calls-vs-puts clock, weekday shares and same-day spreads, all measured.

The folk story about 0DTE options is an end-of-day casino: lottery tickets bought in the final hour for one last coin flip. The tape says otherwise. Measured hour by hour, same-day options trade heaviest in the morning, the fastest contract flow arrives in the first thirty minutes, and their share of all options volume ends the day at its low. The panels below measure that rhythm on a heavy 0DTE session (Friday, July 10, 2026) and test it across underlyings, calls and puts, and weekdays.

What time of day do 0DTE options trade most?

The panel splits every options trade on that Friday into same-day contracts (expiring that afternoon) and everything else, bucketed by the New York clock. The 09:00 row covers only a half hour, the session opens at 9:30, so the last column normalises each bucket to contracts per minute, the only fair comparison.

Query0DTE contract volume, share of all options volume, and flow rate by ET hour: Friday, July 10, 2026
et_hoursame_day_contracts_mall_options_contracts_msame_day_pctsame_day_k_per_minute
09:004.478.4452.9148.9
10:007.1913.5852.9119.8
11:005.810.8653.496.7
12:003.998.2148.666.6
13:003.57.4147.258.3
14:003.026.6345.650.3
15:003.759.7838.462.6
The exact SQL behind every number
SELECT
    formatDateTime(toStartOfHour(toTimeZone(sip_timestamp, 'America/New_York')), '%H:%i') AS et_hour,
    round(sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260710') / 1e6, 2) AS same_day_contracts_m,
    round(sum(size) / 1e6, 2) AS all_options_contracts_m,
    round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260710') / sum(size), 1) AS same_day_pct,
    round(sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260710')
          / uniqExact(toStartOfMinute(sip_timestamp)) / 1000, 1) AS same_day_k_per_minute
FROM global_markets.options_trades
WHERE sip_timestamp >= toDateTime64('2026-07-10 13:30:00', 9)
  AND sip_timestamp < toDateTime64('2026-07-10 20:00:00', 9)
GROUP BY et_hour
ORDER BY et_hour
Run this yourself

Flow rate. The opening half hour moved 148.9 thousand same-day contracts per minute, the fastest stretch of the session. Every later bucket is slower: 119.8k a minute at 10, 66.6k by midday, a low of 50.3k in the 14:00 hour, 62.6k in the final hour.

Absolute volume. The biggest bucket is the 10 o'clock hour at 7.19 million contracts, a full hour, not a half, after which volume slides to 3.02M in the 14:00 hour, then rises into the close, to 3.75M. The late-day pickup is real; it lands nowhere near the morning.

Share. The same-day share of ALL options volume opens at 52.9%, peaks in the 11:00 hour at 53.4%, then falls every hour to 38.4% at the close, the day's low. Read that last hour carefully, since it is where the folk story lives: total options volume rises into the bell (9.78M contracts against 6.63M the hour before, the day's third-busiest bucket, behind the 10:00 and 11:00 hours at 13.58M and 10.86M) while the 0DTE share sinks. The close is a busy hour for options, and the least 0DTE-concentrated hour of the session.

Is the morning peak just SPY?

A fair objection: index ETFs list an expiration every trading day, so perhaps "0DTE" is really a story about SPY and QQQ. The next panel breaks that Friday's same-day volume down by underlying, adding each name's own same-day share and how much of it printed before noon.

QuerySame-day options volume by underlying: the ten heaviest names, July 10, 2026
underlyingsame_day_contracts_mpct_of_all_0dtesame_day_pct_of_namepct_traded_before_noon
SPY8.0125.572.154.4
QQQ4.5414.575.551.1
SPXW2.788.972.951.5
NVDA2.748.754.556.3
TSLA2.287.367.750.6
IWM0.92.865.467.4
AAPL0.762.456.556.4
META0.72.247.655.3
MU0.471.55144.5
AMZN0.381.246.960.4
The exact SQL behind every number
WITH by_name AS (
    SELECT substring(ticker, 3, length(ticker) - 17) AS underlying,
           sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260710') AS same_day_size,
           sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260710'
                       AND toHour(toTimeZone(sip_timestamp, 'America/New_York')) < 12) AS morning_size,
           sum(size) AS all_size
    FROM global_markets.options_trades
    WHERE sip_timestamp >= toDateTime64('2026-07-10 13:30:00', 9)
      AND sip_timestamp < toDateTime64('2026-07-10 20:00:00', 9)
      AND ticker NOT LIKE 'O:SPCX%'
    GROUP BY underlying
)
SELECT underlying,
       round(same_day_size / 1e6, 2) AS same_day_contracts_m,
       round(100.0 * same_day_size / sum(same_day_size) OVER (), 1) AS pct_of_all_0dte,
       round(100.0 * same_day_size / all_size, 1) AS same_day_pct_of_name,
       round(100.0 * morning_size / same_day_size, 1) AS pct_traded_before_noon
FROM by_name
ORDER BY same_day_size DESC
LIMIT 10
Run this yourself

Index products dominate, but do not monopolise. SPY alone took 25.5% of every same-day contract traded market-wide, QQQ another 14.5%; with the S&P 500 index series (SPXW) and the small-cap ETF (IWM), index products fill four of the top six slots. The other two are single stocks, NVDA at 8.7%, TSLA at 7.3%.

The same_day_pct_of_name column shows how 0DTE-heavy each name's own options market was: 72.1% of SPY's options volume that day expired the same afternoon, against 46.9% for AMZN at the foot of the table.

The morning skew holds for all ten. The pre-noon window is 2.5 of the session's 6.5 hours, 38% of the clock, and every name printed more than that share of its same-day volume inside it: heaviest IWM at 67.4%, lightest MU at 44.5%, SPY at 54.4%, NVDA at 56.3%. The tilt belongs to the product, not to one ETF.

Do calls and puts follow the same clock?

The natural suspicion is that puts run late, that the close is thick with hedges against an overnight gap. The tape says the two sides keep almost the same clock.

QuerySame-day calls vs. puts by ET hour, and the put share of 0DTE volume: July 10, 2026
et_hourcall_contracts_mput_contracts_mput_share_pct
09:002.911.5634.9
10:004.13.0943
11:003.362.4442.1
12:002.371.6240.6
13:002.061.4441.1
14:001.741.2842.5
15:002.191.5741.7
The exact SQL behind every number
SELECT formatDateTime(toStartOfHour(toTimeZone(sip_timestamp, 'America/New_York')), '%H:%i') AS et_hour,
       round(sumIf(size, substring(ticker, length(ticker) - 8, 1) = 'C') / 1e6, 2) AS call_contracts_m,
       round(sumIf(size, substring(ticker, length(ticker) - 8, 1) = 'P') / 1e6, 2) AS put_contracts_m,
       round(100.0 * sumIf(size, substring(ticker, length(ticker) - 8, 1) = 'P') / sum(size), 1) AS put_share_pct
FROM global_markets.options_trades
WHERE sip_timestamp >= toDateTime64('2026-07-10 13:30:00', 9)
  AND sip_timestamp < toDateTime64('2026-07-10 20:00:00', 9)
  AND substring(ticker, length(ticker) - 14, 6) = '260710'
GROUP BY et_hour
ORDER BY et_hour
Run this yourself

Both sides peak in the same 10 o'clock bucket, 4.1M calls against 3.09M puts, both slide through the afternoon, both tick up into the close. The put share of same-day volume is the interesting column: lowest in the opening bucket (34.9%), it jumps to 43% at 10, then holds a narrow band, finishing at 41.7%.

The mix effect runs opposite to the hedging story: the opening rush is the most call-tilted stretch of the day, and puts claw back a few points of share once it passes. No late-day put surge appears.

Does the pattern hold on a Tuesday?

The hourly rhythm rides on a daily one: how much 0DTE trading a session can have depends on what expires that day. Friday is the fat end of the expiration calendar, weeklies, monthlies and the daily ETF series all land on it, while Tuesday offers only daily-expiry names. The panel pools six weeks of sessions by weekday.

QuerySame-day share of options volume by weekday: all sessions, June 1 to July 10, 2026
dowweekdaysessionsavg_same_day_contracts_msame_day_pct_of_volume
1Monday622.9134.5
2Tuesday618.9229.2
3Wednesday622.7234.2
4Thursday624.5935.4
5Friday436.146.1
The exact SQL behind every number
WITH sessions AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
           sumIf(volume, substring(ticker, length(ticker) - 14, 6)
                         = formatDateTime(toDate(toTimeZone(window_start, 'America/New_York')), '%y%m%d')) AS same_day_vol,
           sum(volume) AS all_vol
    FROM global_markets.options_minute_aggs
    WHERE window_start >= toDateTime64('2026-06-01 13:30:00', 9)
      AND window_start < toDateTime64('2026-07-10 20:00:00', 9)
      AND toHour(toTimeZone(window_start, 'America/New_York')) BETWEEN 9 AND 15
    GROUP BY session_date
)
SELECT toDayOfWeek(session_date) AS dow,
       formatDateTime(session_date, '%W') AS weekday,
       count() AS sessions,
       round(avg(same_day_vol) / 1e6, 2) AS avg_same_day_contracts_m,
       round(100.0 * sum(same_day_vol) / sum(all_vol), 1) AS same_day_pct_of_volume
FROM sessions
GROUP BY dow, weekday
ORDER BY dow
Run this yourself

Across 6 Mondays, 6 Tuesdays, 6 Wednesdays, 6 Thursdays and 4 Fridays, the split is stark. Friday ran a 46.1% same-day share of all options volume and averaged 36.1 million same-day contracts a session, the highest of the five on both measures. Tuesday was the lightest (29.2%, 18.92M); the midweek days cluster tightly (34.5% on Monday, 34.2% on Wednesday, 35.4% on Thursday). Same-day trading is an every-session phenomenon, even the lightest weekday runs 29.2% of the options tape, but the level is a calendar fact, and the Friday in the panels above sits near the top of that range. The hourly shape generalises; the height of the curve does not.

Why the morning, mechanically

A same-day option's entire life is one session, so whoever wants that exposure, day-range traders, event hedgers, premium sellers harvesting the last day of decay, has the most product to work with at the open: the most hours, the most premium, the widest daily range unresolved. Every hour burns the product itself, and the afternoon's falling share is that product expiring in real time.

What actually trades in the final hour?

The standard assumption is that the last hour's residue is deep in-the-money contracts converging to stock, plus pennies-wide lottery strikes. The panel tests it, bucketing same-day trades by premium paid, a stand-in for moneyness on expiration day, since a contract with hours to live priced at $0.05 is far out of the money and one above $10 is deep in it.

QueryWhat the last hour trades: same-day volume by premium paid, 10am hour vs. closing hour, July 10, 2026
premium_bucketpct_of_10am_contractspct_of_3pm_contractspct_of_3pm_premium_dollars
under $0.1017.133.80.8
$0.10-0.502734.96.1
$0.50-237.419.613.5
$2-1015.19.125.4
$10 and up3.42.654.2
The exact SQL behind every number
SELECT multiIf(price < 0.10, 'under $0.10', price < 0.50, '$0.10-0.50', price < 2, '$0.50-2', price < 10, '$2-10', '$10 and up') AS premium_bucket,
       round(100.0 * sumIf(size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 10)
             / sum(sumIf(size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 10)) OVER (), 1) AS pct_of_10am_contracts,
       round(100.0 * sumIf(size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 15)
             / sum(sumIf(size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 15)) OVER (), 1) AS pct_of_3pm_contracts,
       round(100.0 * sumIf(price * size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 15)
             / sum(sumIf(price * size, toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 15)) OVER (), 1) AS pct_of_3pm_premium_dollars
FROM global_markets.options_trades
WHERE sip_timestamp >= toDateTime64('2026-07-10 13:30:00', 9)
  AND sip_timestamp < toDateTime64('2026-07-10 20:00:00', 9)
  AND substring(ticker, length(ticker) - 14, 6) = '260710'
  AND toHour(toTimeZone(sip_timestamp, 'America/New_York')) IN (10, 15)
GROUP BY premium_bucket
ORDER BY min(price)
Run this yourself

The mix shifts hard toward the cheap end. In the 10 o'clock hour the modal bucket is $0.50-2, at 37.4% of contracts, with the sub-dime bucket on 17.1%. By the closing hour the sub-dime bucket has roughly doubled its share, to 33.8%, $0.10-0.50 adds 34.9%, and $0.50-2 contracts drop to 19.6%. Most of what trades into the bell costs under fifty cents.

The final column is the corrective. Those expensive contracts are rare, the $10 and up bucket is 2.6% of last-hour contracts, yet they carry 54.2% of the premium dollars traded in that hour, against 0.8% for the sub-dime bucket. Both halves of the folk picture are there, in different currencies: counted in contracts the last hour is a lottery-ticket market; counted in dollars, a thin tape of deep in-the-money contracts converging on the stock (the 0DTE guide follows one such last-hour lottery strike). Which side of that split a strike ends up on is settled by where the underlying closes, and the max pain strike, the level at which holders collect the least at expiry, is the usual attempt to guess that landing spot in advance.

When are 0DTE spreads tightest?

Volume is one measure of liquidity; the cost of crossing the market is the one a trader pays. The panel reads every quote update on that Friday's SPY 0DTE contracts and reports the median bid-ask spread by hour, restricted to contracts quoted between $1 and $10, a like-for-like premium band (the contracts inside it change as the day ages; such is an expiring product).

QueryMedian bid-ask spread on SPY same-day contracts quoted $1-$10, by ET hour: July 10, 2026
et_hourquote_updates_mmedian_spread_usdmedian_spread_pct_of_mid
09:000.80.030.8
10:001.40.030.89
11:000.90.031
12:000.30.031.57
13:000.10.12.17
14:000.10.112.38
15:000.10.112.67
The exact SQL behind every number
SELECT formatDateTime(toStartOfHour(toTimeZone(sip_timestamp, 'America/New_York')), '%H:%i') AS et_hour,
       round(count() / 1e6, 1) AS quote_updates_m,
       round(quantileDeterministic(0.5)(toFloat64(ask_price - bid_price), toUInt64(sequence_number)), 3) AS median_spread_usd,
       round(quantileDeterministic(0.5)(toFloat64(ask_price - bid_price) / toFloat64(bid_price + ask_price) * 200,
                                        toUInt64(sequence_number)), 2) AS median_spread_pct_of_mid
FROM global_markets.cache_options_quotes
WHERE ticker LIKE 'O:SPY260710%'
  AND sip_timestamp >= toDateTime64('2026-07-10 13:30:00', 9)
  AND sip_timestamp < toDateTime64('2026-07-10 20:00:00', 9)
  AND bid_price > 0
  AND toFloat64(bid_price + ask_price) / 2 BETWEEN 1 AND 10
GROUP BY et_hour
ORDER BY et_hour
Run this yourself

The spread widens as the session ages. The median same-day SPY contract in that band was quoted 0.8% of its mid-price wide in the opening half hour, the day's tightest bucket, and 2.67% in the closing hour, the widest: more than double the cost of crossing, same product, same premium band, six hours later. In cash the median spread goes from $0.03 to $0.11, midday in between (1.57% at 12:00). Quote traffic moves the same way, 1.4 million updates in the 10 o'clock hour against 0.1M in the last: market makers refresh far less often as contracts approach zero time value, and quote wider when they do.

So what: the practical reading

The measured picture is a morning instrument on a decaying clock:

  • The heaviest, fastest and cheapest-to-cross stretch of a 0DTE contract's life is its first two hours. Every hour after that quotes wider and trades thinner.
  • It is no artifact of index ETFs: all ten of the heaviest underlyings tilt their same-day volume into the morning, and calls and puts keep the same clock.
  • The last hour is real but small, two markets at once: very many very cheap contracts, very few very expensive ones carrying most of the dollars.
  • The weekday matters: Friday's same-day share sits far above any midweek day's.

None of this says whether to trade a product whose premium can go to zero in an afternoon; it says when the market for it is deepest and cheapest to cross. The DTE vocabulary page holds the wider expiration spectrum.

FAQ

Are 0DTE options more active at the close?

Not relative to the rest of the market. On July 10, 2026 same-day contracts fell to 38.4% of all options volume in the closing hour, the day's lowest share, even as total options volume rose to 9.78 million contracts, the session's third-busiest hour (behind 13.58M at 10:00 and 10.86M at 11:00). 0DTE volume does tick up into the bell (3.75M against the 7.19M morning peak), but the rest of the market rises more. The heaviest same-day flow came in the opening half hour, at 148.9 thousand contracts a minute.

What percentage of options volume is 0DTE on an average day?

It depends on the weekday. Over the six weeks to July 10, 2026, same-day contracts were 46.1% of all options volume on Fridays and 29.2% on Tuesdays, every trading day carries meaningful 0DTE volume, and the expiration calendar sets how much.

Do puts and calls trade 0DTE at the same times?

Near enough: both peaked in the same 10 o'clock hour on July 10, 2026 and both faded through the afternoon. The put share of same-day volume was lowest in the opening bucket (34.9%) and ended at 41.7%, no late-day hedging surge appears.

Is the morning peak the same for SPY as for single stocks?

Yes. On that Friday every one of the ten heaviest underlyings, ETFs and single stocks alike, printed a larger share of its same-day volume before noon than the 38% of the session clock that window covers: 56.3% for the single stock NVDA, 54.4% for SPY.


Every figure above is a stored, versioned query over the full options tape, expand any panel to read the SQL, or slice another session on the Strasmore terminal.