Market Recap: June 29, 2026, The Day in Numbers
June 29, 2026 in numbers: a growth-led index gain, a four-point sector spread, a memory-stock round trip, the 0DTE tape, penny-tight quotes and rates.
Monday, June 29, 2026 was a growth-led up day with a narrow leadership band: QQQ gained 2.57%, SPY 1.62%, 3968 liquid names rose against 2327 decliners, yet nearly half the sector baskets closed red. Every number is read from a stored query; expand any panel for the SQL. The tick-by-tick layer of the same session: the June 29 microstructure deep dive.
The scoreboard
Every change compares June 29's last regular-session minute bar with Friday June 26's.
| ticker | jun26_close | jun29_open | jun29_close | pct_change | pct_of_best_change | day_high | day_low | shares_traded_m |
|---|---|---|---|---|---|---|---|---|
| DIA | 517.5 | 520.63 | 521.68 | 0.81 | 31.5 | 522.975 | 519.4 | 5.5 |
| IWM | 297.61 | 298.11 | 298.95 | 0.45 | 17.5 | 299.16 | 294.68 | 21.7 |
| QQQ | 705.84 | 713.99 | 723.95 | 2.57 | 100 | 724.58 | 705.172 | 38.5 |
| SPY | 729.09 | 736.525 | 740.88 | 1.62 | 63 | 741.56 | 732.09 | 46 |
The exact SQL behind every number
WITH friday AS (
SELECT ticker, argMax(close, window_start) AS friday_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
AND window_start >= '2026-06-26 13:30:00' AND window_start < '2026-06-26 20:00:00'
GROUP BY ticker
),
monday AS (
SELECT ticker,
argMin(open, window_start) AS monday_open,
argMax(close, window_start) AS monday_close,
max(high) AS day_high,
min(low) AS day_low,
round(toFloat64(sum(volume)) / 1e6, 1) AS shares_traded_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
AND window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
GROUP BY ticker
)
SELECT
m.ticker AS ticker,
toFloat64(f.friday_close) AS jun26_close,
toFloat64(m.monday_open) AS jun29_open,
toFloat64(m.monday_close) AS jun29_close,
round((toFloat64(m.monday_close) / toFloat64(f.friday_close) - 1) * 100, 2) AS pct_change,
round(100 * (toFloat64(m.monday_close) / toFloat64(f.friday_close) - 1) / max(toFloat64(m.monday_close) / toFloat64(f.friday_close) - 1) OVER (), 1) AS pct_of_best_change,
toFloat64(m.day_high) AS day_high,
toFloat64(m.day_low) AS day_low,
m.shares_traded_m AS shares_traded_m
FROM monday m
JOIN friday f ON m.ticker = f.ticker
ORDER BY m.tickerSPY opened at $736.525 against Friday's $729.09 close and finished at $740.88, under its $741.56 high. QQQ's +2.57% against DIA's +0.81% marks a growth-and-tech day; small-cap IWM added 0.45%.
Was the day unusual?
A percentage move means little without a yardstick. This panel ranks June 29 against the trailing month by absolute close-over-close size.
| qqq_close_over_close_pct | qqq_abs_move_rank | qqq_sessions_compared | qqq_biggest_move_of_month_pct | qqq_up_sessions | spy_close_over_close_pct | spy_abs_move_rank | spy_sessions_compared | spy_open_to_close_pct | first_session |
|---|---|---|---|---|---|---|---|---|---|
| 2.57 | 5 | 21 | 4.76 | 10 | 1.62 | 4 | 21 | 0.59 | May 29, 2026 |
The exact SQL behind every number
SELECT
round(anyIf(cc_pct, ticker = 'QQQ' AND d = toDate('2026-06-29')), 2) AS qqq_close_over_close_pct,
arrayCount(x -> x > abs(anyIf(cc_pct, ticker = 'QQQ' AND d = toDate('2026-06-29'))), groupArrayIf(abs(cc_pct), ticker = 'QQQ' AND d != toDate('2026-06-29'))) + 1 AS qqq_abs_move_rank,
countIf(ticker = 'QQQ') AS qqq_sessions_compared,
round(max(if(ticker = 'QQQ', abs(cc_pct), 0)), 2) AS qqq_biggest_move_of_month_pct,
countIf(ticker = 'QQQ' AND cc_pct > 0) AS qqq_up_sessions,
round(anyIf(cc_pct, ticker = 'SPY' AND d = toDate('2026-06-29')), 2) AS spy_close_over_close_pct,
arrayCount(x -> x > abs(anyIf(cc_pct, ticker = 'SPY' AND d = toDate('2026-06-29'))), groupArrayIf(abs(cc_pct), ticker = 'SPY' AND d != toDate('2026-06-29'))) + 1 AS spy_abs_move_rank,
countIf(ticker = 'SPY') AS spy_sessions_compared,
round(anyIf(oc_pct, ticker = 'SPY' AND d = toDate('2026-06-29')), 2) AS spy_open_to_close_pct,
concat(monthName(min(d)), ' ', toString(toDayOfMonth(min(d))), ', ', toString(toYear(min(d)))) AS first_session
FROM (
SELECT ticker, d,
(close_px / lagInFrame(close_px) OVER (PARTITION BY ticker ORDER BY d) - 1) * 100 AS cc_pct,
oc_pct
FROM (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMax(toFloat64(close), window_start) AS close_px,
(argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100 AS oc_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
AND window_start >= toDateTime('2026-05-28 00:00:00')
AND window_start < toDateTime('2026-06-30 00:00:00')
AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
GROUP BY ticker, d
)
)
WHERE isFinite(cc_pct)Big, not a record: QQQ's 2.57% move ranks 5 of the 21 sessions since May 29, 2026, in a month whose largest single move measured 4.76%; SPY's 1.62% ranks 4 of 21. Where the move came from matters: SPY's open-to-close grind was only 0.59%, so most of the gain arrived in the overnight gap, before a single regular-hours bar printed. QQQ closed higher on 10 of those sessions: a coin-flip month.
Breadth: how wide was the rally?
An advancer is a ticker whose Monday close beat Friday's, among names trading at least $1 million, a filter dropping 5,108 of 11,475 dual-session tickers.
| advancers | decliners | unchanged | liquid_tickers | tickers_traded_both_sessions | tickers_traded_both_sessions_label | dropped_by_liquidity_filter | dropped_by_liquidity_filter_label | advancer_pct |
|---|---|---|---|---|---|---|---|---|
| 3968 | 2327 | 72 | 6367 | 11475 | 11,475 | 5108 | 5,108 | 62.3 |
The exact SQL behind every number
WITH per_ticker AS (
SELECT
ticker,
toFloat64(argMaxIf(close, window_start, window_start < '2026-06-27 00:00:00')) AS friday_close,
toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-29 00:00:00')) AS monday_close,
sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-29 00:00:00') AS monday_dollar_volume
FROM global_markets.delayed_stocks_minute_aggs
WHERE (window_start >= '2026-06-26 13:30:00' AND window_start < '2026-06-26 20:00:00')
OR (window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00')
GROUP BY ticker
)
SELECT
countIf(monday_close > friday_close AND monday_dollar_volume >= 1000000) AS advancers,
countIf(monday_close < friday_close AND monday_dollar_volume >= 1000000) AS decliners,
countIf(monday_close = friday_close AND monday_dollar_volume >= 1000000) AS unchanged,
countIf(monday_dollar_volume >= 1000000) AS liquid_tickers,
count() AS tickers_traded_both_sessions,
reverse(arrayStringConcat(extractAll(reverse(toString(count())), '[0-9]{1,3}'), ',')) AS tickers_traded_both_sessions_label,
count() - countIf(monday_dollar_volume >= 1000000) AS dropped_by_liquidity_filter,
reverse(arrayStringConcat(extractAll(reverse(toString(count() - countIf(monday_dollar_volume >= 1000000))), '[0-9]{1,3}'), ',')) AS dropped_by_liquidity_filter_label,
round(100.0 * countIf(monday_close > friday_close AND monday_dollar_volume >= 1000000)
/ countIf(monday_dollar_volume >= 1000000), 1) AS advancer_pct
FROM per_ticker
WHERE friday_close > 0 AND monday_close > 03968 advancers, 2327 decliners, 72 unchanged: 62.3% of the liquid tape rose, counted one name at a time, a wide day.
Sector by sector: the rally was narrower than it looked
Counting names equally is one view; weighting them by company size is another. The eleven SPDR sector ETFs are the shorthand for the second, one market-value-weighted basket per sector of the S&P 500. They disagree sharply with the breadth count.
| sector | ticker | pct_change | range_pct | dollar_volume_m | pct_above_worst_sector |
|---|---|---|---|---|---|
| Technology | XLK | 2.52 | 3.91 | 2075 | 4.34 |
| Consumer discretionary | XLY | 2.37 | 2.17 | 1142 | 4.2 |
| Communication services | XLC | 1.66 | 0.78 | 669 | 3.48 |
| Industrials | XLI | 0.89 | 1.23 | 1231 | 2.72 |
| Financials | XLF | 0.28 | 0.64 | 1593 | 2.1 |
| Health care | XLV | 0.26 | 0.76 | 1897 | 2.08 |
| Utilities | XLU | -0.32 | 1.18 | 759 | 1.5 |
| Consumer staples | XLP | -0.38 | 1.23 | 764 | 1.44 |
| Energy | XLE | -0.52 | 1.51 | 1098 | 1.3 |
| Real estate | XLRE | -0.64 | 1.45 | 217 | 1.18 |
| Materials | XLB | -1.82 | 2.28 | 626 | 0 |
The exact SQL behind every number
WITH per_etf AS (
SELECT
ticker,
toFloat64(argMaxIf(close, window_start, window_start < '2026-06-27 00:00:00')) AS friday_close,
toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-29 00:00:00')) AS monday_close,
maxIf(toFloat64(high), window_start >= '2026-06-29 00:00:00') AS day_high,
minIf(toFloat64(low), window_start >= '2026-06-29 00:00:00') AS day_low,
round(sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-29 00:00:00') / 1e6, 0) AS dollar_volume_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('XLB', 'XLC', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')
AND ((window_start >= '2026-06-26 13:30:00' AND window_start < '2026-06-26 20:00:00')
OR (window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'))
GROUP BY ticker
)
SELECT
sector,
ticker,
round((monday_close / friday_close - 1) * 100, 2) AS pct_change,
round((day_high / day_low - 1) * 100, 2) AS range_pct,
dollar_volume_m,
round((monday_close / friday_close - 1) * 100 - min((monday_close / friday_close - 1) * 100) OVER (), 2) AS pct_above_worst_sector
FROM (
SELECT *,
multiIf(ticker = 'XLB', 'Materials',
ticker = 'XLC', 'Communication services',
ticker = 'XLE', 'Energy',
ticker = 'XLF', 'Financials',
ticker = 'XLI', 'Industrials',
ticker = 'XLK', 'Technology',
ticker = 'XLP', 'Consumer staples',
ticker = 'XLRE', 'Real estate',
ticker = 'XLU', 'Utilities',
ticker = 'XLV', 'Health care',
'Consumer discretionary') AS sector
FROM per_etf
)
ORDER BY pct_change DESCTechnology led at 2.52%, consumer discretionary followed at 2.37%; materials closed -1.82% and real estate -0.64%. Best minus worst, the day's sector dispersion, measured 4.34 percentage points, with utilities, staples, energy, real estate and materials all red on a day the index rose. Wide by name count, narrow by weight: that is what an index fund's gain can hide.
The day's highlight: memory and storage
Four names traded the same theme with very different outcomes, co-movement and magnitude only; the data does not say why.
| ticker | jun26_close | jun29_close | pct_chg | day_high | day_high_et | day_low | day_low_et | range_pct |
|---|---|---|---|---|---|---|---|---|
| MU | 1122.92 | 1145 | 1.97 | 1148.79 | 15:59 | 1023.65 | 10:18 | 12.22 |
| SNDK | 2091.08 | 2051.29 | -1.9 | 2090.71 | 09:30 | 1895 | 10:18 | 10.33 |
| STX | 895.27 | 968.4 | 8.17 | 987.57 | 14:48 | 880.01 | 10:00 | 12.22 |
| WDC | 586.32 | 651.7 | 11.15 | 652.98 | 15:59 | 590 | 09:31 | 10.67 |
The exact SQL behind every number
WITH per_name AS (
SELECT
ticker,
toFloat64(argMaxIf(close, window_start, window_start < '2026-06-27 00:00:00')) AS friday_close,
toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-29 00:00:00')) AS monday_close,
maxIf(toFloat64(high), window_start >= '2026-06-29 00:00:00') AS day_high,
minIf(toFloat64(low), window_start >= '2026-06-29 00:00:00') AS day_low,
argMinIf(window_start, toFloat64(low), window_start >= '2026-06-29 00:00:00') AS low_bar,
argMaxIf(window_start, toFloat64(high), window_start >= '2026-06-29 00:00:00') AS high_bar
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('MU', 'SNDK', 'STX', 'WDC')
AND ((window_start >= '2026-06-26 13:30:00' AND window_start < '2026-06-26 20:00:00')
OR (window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'))
GROUP BY ticker
)
SELECT
ticker,
round(friday_close, 2) AS jun26_close,
round(monday_close, 2) AS jun29_close,
round((monday_close / friday_close - 1) * 100, 2) AS pct_chg,
round(day_high, 2) AS day_high,
formatDateTime(toTimeZone(high_bar, 'America/New_York'), '%H:%i') AS day_high_et,
round(day_low, 2) AS day_low,
formatDateTime(toTimeZone(low_bar, 'America/New_York'), '%H:%i') AS day_low_et,
round((day_high / day_low - 1) * 100, 2) AS range_pct
FROM per_name
ORDER BY tickerMU is the textbook case of range versus net change: a 12.22% intraday range, a $1023.65 low at 10:18 ET, a $1148.79 high at 15:59, yet a close 1.97% above Friday. Western Digital rose 11.15% and Seagate 8.17%; SanDisk closed -1.9% across a 10.33% range, the cluster's one lower close. A close hides what holders lived through.
Where the money traded
By dollars traded, Micron (MU) towered over everything, index funds included: $58.47 billion against SPY's $33.97 billion. By share count, a different day.
| ticker | leaderboard | dollar_volume_bn | dollar_value_m | shares_m | pct_of_board_leader |
|---|---|---|---|---|---|
| MU | by dollars traded | 58.47 | None | 53.5 | 100 |
| SPY | by dollars traded | 33.97 | None | 46 | 58.1 |
| QQQ | by dollars traded | 27.67 | None | 38.5 | 47.3 |
| NVDA | by dollars traded | 21.66 | None | 111.8 | 37 |
| TSLA | by dollars traded | 20.66 | None | 51.4 | 35.3 |
| SNDK | by dollars traded | 19.73 | None | 10 | 33.7 |
| SOXS | by shares traded | 2.84 | None | 695.3 | 100 |
| INLF | by shares traded | 0.02 | 23 | 353.8 | 50.9 |
| TZA | by shares traded | 1.3 | None | 330.7 | 47.6 |
| BITO | by shares traded | 2.03 | None | 250.7 | 36.1 |
The exact SQL behind every number
SELECT ticker, leaderboard, dollar_volume_bn, if(dollar_volume_bn < 1, dollar_volume_m, NULL) AS dollar_value_m, shares_m,
round(100 * if(leaderboard = 'by dollars traded', dollar_volume_bn, shares_m)
/ max(if(leaderboard = 'by dollars traded', dollar_volume_bn, shares_m)) OVER (PARTITION BY leaderboard), 1) AS pct_of_board_leader
FROM (
SELECT
'by dollars traded' AS leaderboard,
ticker,
round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 2) AS dollar_volume_bn,
round(sum(toFloat64(close) * toFloat64(volume)) / 1e6, 0) AS dollar_volume_m,
round(sum(toFloat64(volume)) / 1e6, 1) AS shares_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
GROUP BY ticker
ORDER BY dollar_volume_bn DESC
LIMIT 6
UNION ALL
SELECT
'by shares traded' AS leaderboard,
ticker,
round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 2) AS dollar_volume_bn,
round(sum(toFloat64(close) * toFloat64(volume)) / 1e6, 0) AS dollar_volume_m,
round(sum(toFloat64(volume)) / 1e6, 1) AS shares_m
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
GROUP BY ticker
ORDER BY shares_m DESC
LIMIT 4
)
ORDER BY leaderboard ASC, if(leaderboard = 'by dollars traded', dollar_volume_bn, shares_m) DESCShare-count boards mislead: the share leaders were SOXS, a 3x-leveraged inverse semiconductor ETF (695.3 million shares), and INLF, a penny stock whose 353.8 million shares were worth about $23 million all day. Dollar volume shows where money moved; relative volume shows whether a name's activity is unusual for itself.
In 30-minute New York buckets, June 29 traces the classic volume "smile":
| et_time | shares_bn | pct_of_biggest_bucket | pct_above_trough |
|---|---|---|---|
| 09:30 | 2.3 | 59.8 | 199.9 |
| 10:00 | 1.9 | 49.3 | 147.6 |
| 10:30 | 1.42 | 36.9 | 85.1 |
| 11:00 | 1.23 | 32 | 60.6 |
| 11:30 | 1.1 | 28.6 | 43.7 |
| 12:00 | 0.91 | 23.7 | 18.8 |
| 12:30 | 0.85 | 22 | 10.4 |
| 13:00 | 0.92 | 24 | 20.2 |
| 13:30 | 0.77 | 19.9 | 0 |
| 14:00 | 0.82 | 21.2 | 6.4 |
| 14:30 | 0.82 | 21.4 | 7.4 |
| 15:00 | 1.05 | 27.3 | 36.9 |
| 15:30 | 3.85 | 100 | 401.8 |
The exact SQL behind every number
SELECT
et_time,
round(sum(shares) / 1e9, 2) AS shares_bn,
round(100 * sum(shares) / max(sum(shares)) OVER (), 1) AS pct_of_biggest_bucket,
round(100 * (sum(shares) / min(sum(shares)) OVER () - 1), 1) AS pct_above_trough
FROM
(
SELECT
formatDateTime(toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
toFloat64(volume) AS shares
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
UNION ALL
SELECT
'15:30' AS et_time,
toFloat64(size) AS shares
FROM global_markets.stocks_trades
WHERE sip_timestamp >= '2026-06-29 20:00:00' AND sip_timestamp < '2026-06-29 20:15:00'
AND has(conditions, 8)
)
GROUP BY et_time
ORDER BY et_time2.3 billion shares in the opening half hour, a 0.77 billion trough at 13:30, and the biggest bucket, 3.85 billion, in the closing half hour, where closing auctions and index-tracking flows concentrate.
The options tape
Options traded 66.33 million contracts across 11.04 million prints.
| option_prints_m | contracts_m | call_pct_of_volume | same_day_expiry_pct | thu_jul2_expiry_contracts_m | fri_jul3_expiry_prints | premarket_prints | premarket_prints_label | premarket_non_index_prints | premarket_underlyings | spy_contracts_m | qqq_contracts_m | top_contract_underlying | top_contract_strike | top_contract_type | top_contract_expiry | top_contract_volume | top_contract_volume_label | top_contract_avg_price | top_strike_minus_spy_close |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11.04 | 66.33 | 55.7 | 35.8 | 10.73 | 0 | 40621 | 40,621 | 0 | RUTW, SPX, SPXW, VIX, VIXW, XSP | 12.01 | 7.32 | SPY | 741 | C | 2026-06-29 | 788133 | 788,133 | 0.474 | 0.12 |
The exact SQL behind every number
WITH
(
SELECT (any(underlying_symbol), any(toFloat64(strike_price)), any(option_type),
any(toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6)))),
sum(size), count(), round(avg(toFloat64(price)), 3))
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'
GROUP BY ticker
ORDER BY sum(size) DESC
LIMIT 1
) AS top_contract,
(
SELECT round(toFloat64(argMax(close, window_start)), 2)
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
) AS spy_regular_close
SELECT
round(count() / 1e6, 2) AS option_prints_m,
round(toFloat64(sum(size)) / 1e6, 2) AS contracts_m,
round(100.0 * sumIf(size, option_type = 'C') / sum(size), 1) AS call_pct_of_volume,
round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260629') / sum(size), 1) AS same_day_expiry_pct,
round(toFloat64(sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260702')) / 1e6, 2) AS thu_jul2_expiry_contracts_m,
countIf(substring(ticker, length(ticker) - 14, 6) = '260703') AS fri_jul3_expiry_prints,
countIf(sip_timestamp < '2026-06-29 13:30:00') AS premarket_prints,
reverse(arrayStringConcat(extractAll(reverse(toString(countIf(sip_timestamp < '2026-06-29 13:30:00'))), '[0-9]{1,3}'), ',')) AS premarket_prints_label,
countIf(sip_timestamp < '2026-06-29 13:30:00'
AND underlying_symbol NOT IN ('SPX', 'SPXW', 'XSP', 'RUTW', 'VIX', 'VIXW')) AS premarket_non_index_prints,
arrayStringConcat(arraySort(groupUniqArrayIf(underlying_symbol, sip_timestamp < '2026-06-29 13:30:00')), ', ') AS premarket_underlyings,
round(toFloat64(sumIf(size, underlying_symbol = 'SPY')) / 1e6, 2) AS spy_contracts_m,
round(toFloat64(sumIf(size, underlying_symbol = 'QQQ')) / 1e6, 2) AS qqq_contracts_m,
top_contract.1 AS top_contract_underlying,
top_contract.2 AS top_contract_strike,
top_contract.3 AS top_contract_type,
top_contract.4 AS top_contract_expiry,
top_contract.5 AS top_contract_volume,
reverse(arrayStringConcat(extractAll(reverse(toString(assumeNotNull(top_contract.5))), '[0-9]{1,3}'), ',')) AS top_contract_volume_label,
round(top_contract.7, 3) AS top_contract_avg_price,
round(top_contract.2 - spy_regular_close, 2) AS top_strike_minus_spy_close
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-06-29 00:00:00' AND sip_timestamp < '2026-06-30 00:00:00'Calls took 55.7% of contract volume, and 35.8% of everything that traded expired that same Monday, the zero-days-to-expiry (0DTE) share. The busiest single contract anywhere was the same-day SPY $741 call: 788,133 contracts at an average premium of $0.474, with SPY's close landing 0.12 dollars below the strike, the day's most-traded option finished out of the money. SPY traded 12.01 million contracts as an underlying; QQQ 7.32 million.
The panel also counts 40,621 option prints before the 9:30 equity open, every one on a cash-settled index root (RUTW, SPX, SPXW, VIX, VIXW, XSP), with 0 stock or ETF option prints in the same window. That is the rule, not an accident: index options list extended global-trading-hours sessions, options on stocks and ETFs open with the stock market. The stocks trade early, see premarket and after-hours trading, their options do not.
No contract with a Friday, July 3 expiration code printed all day (0 prints), the market is closed that Friday, while the Thursday, July 2 expiry traded 10.73 million.
The quote tape: what the day cost to trade
Every price on this page sits on a quote stream, the National Best Bid and Offer, re-published continuously for every listed name. The gap between best bid and best offer, the bid-ask spread, is what an order pays to cross.
| ticker | nbbo_updates_m | median_spread_bps | open_30min_spread_bps | midday_spread_bps | open_minus_midday_bps | dropped_invalid_quotes |
|---|---|---|---|---|---|---|
| MU | 0.75 | 4.6 | 6.55 | 4.11 | 2.44 | 414 |
| QQQ | 4.42 | 0.84 | 0.98 | 0.55 | 0.42 | 629 |
| SPY | 3.98 | 0.41 | 0.41 | 0.27 | 0.14 | 1544 |
| WDC | 0.12 | 8.2 | 14.33 | 7.55 | 6.78 | 43 |
The exact SQL behind every number
SELECT
ticker,
round(count() / 1e6, 2) AS nbbo_updates_m,
round(quantileExactIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, bid_price > 0 AND ask_price >= bid_price), 2) AS median_spread_bps,
round(quantileExactIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, bid_price > 0 AND ask_price >= bid_price AND sip_timestamp >= '2026-06-29 13:30:00' AND sip_timestamp < '2026-06-29 14:00:00'), 2) AS open_30min_spread_bps,
round(quantileExactIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, bid_price > 0 AND ask_price >= bid_price AND sip_timestamp >= '2026-06-29 17:00:00' AND sip_timestamp < '2026-06-29 17:30:00'), 2) AS midday_spread_bps,
round(quantileExactIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, bid_price > 0 AND ask_price >= bid_price AND sip_timestamp >= '2026-06-29 13:30:00' AND sip_timestamp < '2026-06-29 14:00:00')
- quantileExactIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, bid_price > 0 AND ask_price >= bid_price AND sip_timestamp >= '2026-06-29 17:00:00' AND sip_timestamp < '2026-06-29 17:30:00'), 2) AS open_minus_midday_bps,
countIf(NOT (bid_price > 0 AND ask_price >= bid_price)) AS dropped_invalid_quotes
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'QQQ', 'MU', 'WDC')
AND sip_timestamp >= '2026-06-29 13:30:00' AND sip_timestamp < '2026-06-29 20:00:00'
GROUP BY ticker
ORDER BY tickerSPY's median quoted width was 0.41 basis points of its mid-price, against 0.84 for QQQ, 4.6 for Micron and 8.2 for Western Digital, the widest of the four. One basis point of a $10,000 order is one dollar, so buying and instantly selling $10,000 of SPY at the quote costs about $0.41; the same round trip in Western Digital costs $8.2. The trade size did not change; the name did.
All four quoted wider in the opening half hour than in the midday control window, SPY 0.41 bps against 0.27, Western Digital 14.33 against 7.55, a 6.78 bp opening premium on the widest name. Churn is the other half: 3.98 million NBBO updates on SPY in regular hours, 4.42 million on QQQ.
Rates: the curve barely moved
Treasuries had a quiet Monday. Yields are daily closes, changed against June 26.
| curve_point | jun29_yield_pct | one_day_change_bp |
|---|---|---|
| 1 month | 3.71 | 1 |
| 3 month | 3.87 | 4 |
| 1 year | 3.97 | 3 |
| 2 year | 4.1 | 3 |
| 5 year | 4.14 | 2 |
| 10 year | 4.38 | 0 |
| 30 year | 4.86 | -1 |
| 2s10s spread | 0.28 | -3 |
The exact SQL behind every number
SELECT
t.1 AS curve_point,
round(t.2, 2) AS jun29_yield_pct,
round((t.2 - t.3) * 100) AS one_day_change_bp
FROM (
SELECT arrayJoin([
('1 month', toFloat64(mon.yield_1_month), toFloat64(fri.yield_1_month)),
('3 month', toFloat64(mon.yield_3_month), toFloat64(fri.yield_3_month)),
('1 year', toFloat64(mon.yield_1_year), toFloat64(fri.yield_1_year)),
('2 year', toFloat64(mon.yield_2_year), toFloat64(fri.yield_2_year)),
('5 year', toFloat64(mon.yield_5_year), toFloat64(fri.yield_5_year)),
('10 year', toFloat64(mon.yield_10_year), toFloat64(fri.yield_10_year)),
('30 year', toFloat64(mon.yield_30_year), toFloat64(fri.yield_30_year)),
('2s10s spread', toFloat64(mon.yield_10_year - mon.yield_2_year), toFloat64(fri.yield_10_year - fri.yield_2_year))
]) AS t
FROM (SELECT * FROM global_markets.treasury_yields WHERE date = '2026-06-29') AS mon,
(SELECT * FROM global_markets.treasury_yields WHERE date = '2026-06-26') AS fri
)The 10-year closed at 4.38%, unchanged on the day (0 bp), while the 3-month bill added 4 bp to 3.87%. The 2s10s spread, the 10-year minus the 2-year, closed at 0.28 percentage points (-3 bp): still positive, slightly flatter.
The calendar behind the day
| ex_dividend_records_jun29 | household_name_ex_dividends | household_names_checked | busiest_ex_div_day_of_window | busiest_ex_div_day_records | splits_executed | ipos_listed_jun29 | jul1_ipo_debuts | sec_filings | prospectus_424b2_filings | insider_form4_filings | filings_8k | news_articles | news_publishers | nvda_articles | next_most_covered_articles | nvda_minus_next_most_covered | hon_split_records | hon_split_from | hon_split_to | hon_close_jun26 | hon_close_jun29 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 449 | 0 | 25 | July 1 | 746 | 23 | 0 | BSP, ITG, LIME | 6173 | 1473 | 1277 | 231 | 170 | 3 | 14 | 12 | 2 | 1 | 2 | 1 | 231.3 | 227.71 |
The exact SQL behind every number
WITH
(
SELECT (argMax(d, n), max(n))
FROM (
SELECT ex_dividend_date AS d, count() AS n
FROM global_markets.stocks_dividends
WHERE ex_dividend_date BETWEEN '2026-06-22' AND '2026-07-02'
GROUP BY d
)
) AS peak_ex_div,
(
SELECT (countIf(form_type = '424B2'), countIf(form_type = '4'), countIf(form_type = '8-K'), count())
FROM global_markets.stocks_sec_edgar_index
WHERE filing_date = '2026-06-29'
) AS filings,
(
SELECT (count(), uniqExact(publisher), countIf(has(tickers, 'NVDA')))
FROM global_markets.stocks_news
WHERE toDate(toTimeZone(published_utc, 'America/New_York')) = '2026-06-29'
) AS news,
(
SELECT max(n)
FROM (
SELECT t, count() AS n
FROM (
SELECT arrayJoin(tickers) AS t
FROM global_markets.stocks_news
WHERE toDate(toTimeZone(published_utc, 'America/New_York')) = '2026-06-29'
)
WHERE t NOT IN ('NVDA', 'SPCX')
GROUP BY t
)
) AS runner_up_articles,
(
SELECT (any(split_from), any(split_to), count())
FROM global_markets.stocks_splits
WHERE ticker = 'HON' AND execution_date = '2026-06-29'
) AS hon_split,
(
SELECT (
round(toFloat64(argMaxIf(close, window_start, window_start < '2026-06-27 00:00:00')), 2),
round(toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-29 00:00:00')), 2)
)
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'HON'
AND ((window_start >= '2026-06-26 13:30:00' AND window_start < '2026-06-26 20:00:00')
OR (window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'))
) AS hon_close
SELECT
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date = '2026-06-29') AS ex_dividend_records_jun29,
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date = '2026-06-29'
AND ticker IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'GOOGL', 'GOOG', 'META', 'TSLA', 'JPM', 'JNJ',
'XOM', 'KO', 'PG', 'V', 'MA', 'HD', 'WMT', 'CVX', 'MRK', 'PEP',
'SPY', 'QQQ', 'DIA', 'IWM', 'VTI')) AS household_name_ex_dividends,
length(['AAPL', 'MSFT', 'NVDA', 'AMZN', 'GOOGL', 'GOOG', 'META', 'TSLA', 'JPM', 'JNJ',
'XOM', 'KO', 'PG', 'V', 'MA', 'HD', 'WMT', 'CVX', 'MRK', 'PEP',
'SPY', 'QQQ', 'DIA', 'IWM', 'VTI']) AS household_names_checked,
concat(monthName(peak_ex_div.1), ' ', toString(toDayOfMonth(peak_ex_div.1))) AS busiest_ex_div_day_of_window,
peak_ex_div.2 AS busiest_ex_div_day_records,
(SELECT count() FROM global_markets.stocks_splits WHERE execution_date = '2026-06-29') AS splits_executed,
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date = '2026-06-29') AS ipos_listed_jun29,
(SELECT arrayStringConcat(groupArray(ticker), ', ') FROM (
SELECT ticker FROM global_markets.stocks_ipos WHERE listing_date = '2026-07-01' ORDER BY ticker
)) AS jul1_ipo_debuts,
filings.4 AS sec_filings,
filings.1 AS prospectus_424b2_filings,
filings.2 AS insider_form4_filings,
filings.3 AS filings_8k,
news.1 AS news_articles,
news.2 AS news_publishers,
news.3 AS nvda_articles,
runner_up_articles AS next_most_covered_articles,
news.3 - runner_up_articles AS nvda_minus_next_most_covered,
hon_split.3 AS hon_split_records,
hon_split.1 AS hon_split_from,
hon_split.2 AS hon_split_to,
hon_close.1 AS hon_close_jun26,
hon_close.2 AS hon_close_jun29449 dividend records went ex-dividend on June 29, own the stock before its ex-dividend date or the payment is not yours, yet among 25 household names we checked, 0 appeared. The quarter-end wave crested at 746 records on July 1. 23 splits executed and 0 IPOs listed, Wednesday's debuts (BSP, ITG, LIME) already on the calendar.
The SEC logged 6173 filings dated June 29: 1473 structured-product pricing supplements (form 424B2) and 1277 insider-trade reports (Form 4) dwarf the 231 8-Ks that make headlines. Our news feed carried 170 articles from 3 publishers; excluding one ambiguously-tagged reused symbol (dropped in the query), the most-covered name was NVDA at 14 articles against the runner-up's 12.
Data notes
Weird data gets a note, never silent exclusion, these four touch headline numbers.
- The sector baskets are a declared method. "Sector" means the eleven SPDR sector ETFs, market-value-weighted, the same names every session, not a vendor's per-ticker classification.
- Dollar volume is a per-minute proxy, close × volume summed per minute bar, near but not identical to the sum of print values.
- The volume panel's closing half hour counts the closing auction prints. The one-minute bars leave every auction print out, so the half-hour panel adds each trade carrying the closing-print sale condition, stamped 4:00 to 4:15 p.m. ET on the consolidated tape, to its final bucket.
- Quoted spreads exclude invalid quotes (one-sided or crossed NBBO records); the panel counts what it dropped (1544 on SPY). A median quoted width is a quoting statistic, not a per-trade cost, orders often execute inside the quote.
- A lone print can contaminate a minute bar's high or low. QQQ's 11:07 ET bar carries a $709.58 low while no surrounding bar dipped below $715.09, one print $5.51 under the concurrent market. Every high and low above was cross-checked against adjacent bars; QQQ's $705.172 session low passed.
Full data notes
- Treasury coverage is thinner than the schema. Four advertised maturities (6-month, 3-, 7- and 20-year) have never been populated; the curve shows the seven that exist, plus the 2s10s row.
- A Honeywell "reverse split" the tape contradicts. The feed carries 1 HON record dated June 29: a reverse split converting 2 old shares into 1 new. HON closed $231.3 Friday and $227.71 Monday, no doubling. We did not apply it.
- The news count is one vendor's feed, the 3 publishers we carry, not "all market news".
- The tick-level receipts, crossed quotes, the phantom-volume correction, the truncated FINRA short-volume file (and why short volume is not short interest), sit in the deep dive.
The session, verified
| jul3_spy_bars | first_spy_bar_et | last_spy_bar_et | spy_minute_bars | regular_session_bars | qqq_1107_lone_low | qqq_1107_adjacent_bars_low | qqq_lone_print_below_adjacent |
|---|---|---|---|---|---|---|---|
| 0 | 04:00 | 19:59 | 897 | 390 | 709.58 | 715.09 | 5.51 |
The exact SQL behind every number
WITH
(
SELECT (
round(toFloat64(minIf(low, formatDateTime(toTimeZone(window_start, 'America/New_York'), '%H:%i') = '11:07')), 2),
round(toFloat64(minIf(low, formatDateTime(toTimeZone(window_start, 'America/New_York'), '%H:%i') IN ('11:04', '11:05', '11:06', '11:08', '11:09', '11:10'))), 2)
)
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'QQQ' AND window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00'
) AS qqq_lone
SELECT
(SELECT count() FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-07-03 00:00:00' AND window_start < '2026-07-04 00:00:00') AS jul3_spy_bars,
formatDateTime(min(toTimeZone(window_start, 'America/New_York')), '%H:%i') AS first_spy_bar_et,
formatDateTime(max(toTimeZone(window_start, 'America/New_York')), '%H:%i') AS last_spy_bar_et,
count() AS spy_minute_bars,
countIf(window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00') AS regular_session_bars,
qqq_lone.1 AS qqq_1107_lone_low,
qqq_lone.2 AS qqq_1107_adjacent_bars_low,
round(qqq_lone.2 - qqq_lone.1, 2) AS qqq_lone_print_below_adjacent
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-06-29 00:00:00' AND window_start < '2026-06-30 00:00:00'SPY's bars run 04:00 to 19:59 New York time with exactly 390 regular-window bars, a complete session, verified from the tape (the exchange-calendar dataset carries only upcoming closures). That Friday, July 3, was a full closure, 0 SPY bars printed all day, July 4 landing on a Saturday; the four-session week has its own recap.
FAQ
How did the stock market do on June 29, 2026?
An up day led by growth: QQQ closed 2.57% above Friday, SPY 1.62%, DIA 0.81% and IWM 0.45%, with 62.3% of tickers trading $1m or more finishing higher.
Was June 29, 2026 a big day for the Nasdaq?
Big, not exceptional: QQQ's 2.57% close-over-close move ranked 5 of the trailing month's 21 sessions by absolute size, against a monthly high of 4.76%.
Which sectors led on June 29, 2026?
Technology (2.52%) and consumer discretionary (2.37%) led the eleven SPDR sector baskets; materials was last at -1.82%, a spread of 4.34 percentage points. Utilities, staples, energy and real estate also closed lower.
What share of options volume on June 29, 2026 was 0DTE?
Same-day expiries were 35.8% of the 66.33 million contracts traded; the busiest single contract, a same-day SPY $741 call (788,133 contracts), finished out of the money.
Why do options trade before the stock market opens?
Only index options do. All 40,621 option prints before 9:30 a.m. ET on June 29 sat on cash-settled index roots (RUTW, SPX, SPXW, VIX, VIXW, XSP), which list extended global-trading-hours sessions; stock and ETF option prints in that window numbered 0.
Methodology
- Timestamps are stored in UTC, converted to New York time inside the queries. "Close" is the last regular-session minute bar, not the auction print; day changes compare June 29 with June 26, and the session was verified from the observed bar span.
- The trailing-month rank uses regular-hours close-over-close moves, first session dropped (no prior close inside the window). Option expiries are re-parsed from the OCC ticker (the table's own expiry column is broken).
- Every panel is read once, at authoring time, through the gated read-only path. Warehouse state as of July 13, 2026.
Every panel is a stored query result, chart, table and SQL in one object. Paste any of them into the Strasmore terminal. Next session: June 30.