The second quarter of 2026 was the recovery quarter: after a negative first quarter, every major index ETF rose double digits, led by QQQ at 26.5%. The panels below carry the quarter's shape, the monthly staircase, the rates backdrop, the calendar, and its two data caveats, disclosed inline. Every number is a stored query result; expand any panel for the exact SQL.
The quarter on the board
How big was the swing from Q1? This panel computes both quarters' returns in one query, the Q1 reference is recomputed live on the same definitions, not read from anywhere.
The exact SQL behind every number
SELECT ticker,
round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
/ argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-04-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q2_return_pct,
round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-03-31') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959)
/ argMinIf(toFloat64(open), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-01-01') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS q1_return_pct,
round(argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS q2_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY ticker
ORDER BY tickerQQQ rose 26.5% for the quarter after a -6.9% Q1; SPY 14.1% after -5.2%; IWM 20.2%. Every index that fell in the first quarter more than recovered in the second. The four tell three different stories: the growth index took the deepest Q1 drawdown and posted the biggest recovery; DIA, the price-weighted industrials index, swung from -3.9% to 12.1%; and IWM never really fell at all (0.1% in Q1), so its 20.2% quarter compounded a flat start rather than repairing a drawdown. Recovery and momentum look identical in a quarterly return column; the Q1 column is what tells them apart.
The quarter against every second quarter on the tape
Recovery quarters feel historic from inside them; the tape can say whether this one measures that way. The panels recompute the SAME April-through-June return for every year of minute history in one query, identical arithmetic each year, then rank this quarter against the rest.
The exact SQL behind every number
SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
ticker,
uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
round((argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100, 1) AS q2_return_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
AND window_start >= toDateTime('2003-01-01 00:00:00')
AND window_start < toDateTime('2026-07-01 00:00:00')
AND toMonth(toTimeZone(window_start, 'America/New_York')) BETWEEN 4 AND 6
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY y, ticker
HAVING sessions >= 50
ORDER BY y ASC, ticker ASCThe exact SQL behind every number
SELECT ticker,
round(anyIf(ret, y = 2026), 1) AS q2_2026_pct,
arrayCount(x -> x > anyIf(ret, y = 2026), groupArrayIf(ret, y != 2026)) + 1 AS rank_best,
count() AS q2s_compared,
min(y) AS first_year,
anyIf(sessions, y = 2026) AS sessions_2026
FROM (
SELECT toYear(toTimeZone(window_start, 'America/New_York')) AS y,
ticker,
uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions,
(argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100 AS ret
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
AND window_start >= toDateTime('2003-01-01 00:00:00')
AND window_start < toDateTime('2026-07-01 00:00:00')
AND toMonth(toTimeZone(window_start, 'America/New_York')) BETWEEN 4 AND 6
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY y, ticker
HAVING sessions >= 50
)
GROUP BY ticker
ORDER BY ticker ASCIt measures close to historic: QQQ's 26.5% ranks 2 of 17 comparable second quarters (rank 1 = best), exactly one prior second quarter finished higher, and the by-year table above shows which. SPY's 14.1% ranks 3 of 23 since 2004. Two disclosures ride along: QQQ's series is shorter (the fund traded under a different root symbol for a stretch of years, a session-count guard excludes those years visibly, with per-year counts in the table), and every history query pins its upper bound at this quarter's end, so the comparison set cannot silently grow when later years land. Basis for every rank on this page: regular-hours open-to-close within the calendar quarter.
The monthly staircase
The exact SQL behind every number
SELECT toString(toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York')))) AS period_start, ticker,
round((argMaxIf(toFloat64(close), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) / argMinIf(toFloat64(open), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) - 1) * 100, 1) AS month_return_pct,
round(argMaxIf(toFloat64(close), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199), 2) AS month_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
AND window_start >= toDateTime('2026-04-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY period_start, ticker
ORDER BY period_start, tickerThe quarter was front-loaded: April did the heavy lifting (SPY 9.9%, QQQ 14.8%), May added more (4.9% and 10.3%), and June gave a little back, SPY -1.2%. The June recap carries the month in detail, including the breadth split beneath it.
The tape's leaders, quarter scale
The exact SQL behind every number
SELECT ticker,
round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 1) AS dollar_bn,
round(100 * sum(toFloat64(close) * toFloat64(volume)) / max(sum(toFloat64(close) * toFloat64(volume))) OVER (), 1) AS pct_of_leader
FROM global_markets.delayed_stocks_minute_aggs
WHERE window_start >= toDateTime('2026-04-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
AND ticker NOT IN ('SPCX')
GROUP BY ticker
ORDER BY dollar_bn DESC
LIMIT 8For the full quarter, MU ($2047.5 billion) edged out SPY ($2032 billion) at the top of the tape, a single stock out-trading the flagship index fund across three months, by 99.2% of the leader's total. Behind them: QQQ ($1658.5 billion), then NVDA at $1591.8 billion, whose June alone is dissected tick by tick here, and TSLA at $1198.8 billion. Note what the list is: regular-hours turnover, not performance, a name can dominate the tape in a falling month. The leader's own June is dissected tick by tick in its deep-dive. Basis: April 1–June 30 regular hours; one reused-symbol June listing excluded pending entity verification (its receipts).
Breadth: the day grain
The exact SQL behind every number
SELECT countIf(day_ret > 0) AS up_sessions,
countIf(day_ret < 0) AS down_sessions,
countIf(day_ret = 0) AS flat_sessions,
count() AS sessions_total
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
round((argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100, 2) AS day_ret
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime('2026-04-01 00:00:00')
AND window_start < toDateTime('2026-07-01 00:00:00')
AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
GROUP BY d
)36 of the quarter's 62 sessions closed SPY higher against 26 lower, up-day dominance that matches a double-digit quarter. The ticker-grain count (every advancer and decliner) is bounded at quarter scale: the single whole-market scan exceeds the query budget this page generates under (measured at authoring), so the equal-count breadth lives at month scale, June's advancer/decliner split, where more fell than rose, is in the June recap, and the bound is disclosed here rather than silently narrowed.
The options tape, month by month
The quarter's microstructure story, told at the only scale that can tell it, month over month across the whole listed options tape. Volume rose into quarter-end: 1386.9 million contracts in April to 1477.9 million in June, the quarter's busiest month. The same-day-expiry (0DTE) share rose alongside, from 30.3% to 34.3%, June's share is the highest of the half, and the January-onward evolution is in the H1 recap.
The exact SQL behind every number
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-04-01 00:00:00')
AND window_start < toDateTime('2026-05-01 00:00:00')The exact SQL behind every number
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-05-01 00:00:00')
AND window_start < toDateTime('2026-06-01 00:00:00')The exact SQL behind every number
SELECT round(sum(toFloat64(volume)) / 1e6, 1) AS contracts_mm,
round(100.0 * sumIf(toFloat64(volume), toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) = toDate(toTimeZone(window_start, 'America/New_York'))) / sum(toFloat64(volume)), 1) AS zero_dte_pct,
uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-06-01 00:00:00')
AND window_start < toDateTime('2026-07-01 00:00:00')The cost to trade, sampled monthly
The exact SQL behind every number
SELECT toDate(toTimeZone(sip_timestamp, 'America/New_York')) AS session,
round(quantileDeterministicIf(0.5)((toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000, toUInt64(toUnixTimestamp64Micro(sip_timestamp)), bid_price > 0 AND ask_price >= bid_price), 3) AS med_spread_bps,
round(count() / 1e6, 2) AS quote_updates_m,
countIf(NOT (bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price)) AS invalid_dropped
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY'
AND ((sip_timestamp >= toDateTime64('2026-04-15 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-04-15 20:00:00', 9))
OR (sip_timestamp >= toDateTime64('2026-05-13 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-05-13 20:00:00', 9))
OR (sip_timestamp >= toDateTime64('2026-06-10 13:30:00', 9) AND sip_timestamp < toDateTime64('2026-06-10 20:00:00', 9)))
GROUP BY session
ORDER BY session ASCSPY's median quoted spread on the quarter's monthly sample sessions: 0.286 bps in the April sample, 0.27 in May's, 0.409 in June's, the June sample is the widest. Basis, disclosed: single labeled sample sessions (the second Wednesday of each month), not month-wide medians; invalid quotes are counted in the panel, not dropped.
Rates: the quarter the curve flattened
The exact SQL behind every number
SELECT toString(date) AS d,
round(yield_10_year, 2) AS y10,
round((yield_10_year - yield_2_year) * 100, 0) AS spread_2s10s_bp
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-04-01') AND date <= toDate('2026-06-30')
AND isNotNull(yield_10_year) AND isNotNull(yield_2_year)
ORDER BY dateThe 2s10s spread came into the quarter at 52 basis points and ended at 30, a flattening quarter, with the 10-year finishing at 4.44%. The six-month version of this story is in the H1 recap. Mechanically, a flattening means the short end closed distance on the long end; whether that continues is not answerable from this table, and this page doesn't try.
The calendar, quarter scale
The exact SQL behind every number
SELECT
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-04-01') AND ex_dividend_date <= toDate('2026-06-30')) AS ex_div_events,
(SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-04-01') AND execution_date <= toDate('2026-06-30')) AS splits,
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-04-01') AND listing_date <= toDate('2026-06-30')) AS ipos,
(SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date >= toDate('2026-04-01') AND filing_date <= toDate('2026-06-30')) AS q2_filings,
(SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-04-30')) AS filings_apr30,
(SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-30')) AS filings_jun30105 companies listed in the quarter, 435 splits executed, and 15402 ex-dividend events paid out. The filing count (235075) carries the disclosed gap: the index holds only 31 filings on June 30, the quarter's last day, and 34 on April 30, against thousands on neighboring days, so the quarter total clips TWO month-end days and is understated until the feed backfills. The month-end gap has its own diagnostic note.
The calendar's ramp into quarter-end
The exact SQL behind every number
SELECT m, ipos, splits, ex_divs FROM (
SELECT '2026-04' AS m,
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-04-01') AND listing_date <= toDate('2026-04-30')) AS ipos,
(SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-04-01') AND execution_date <= toDate('2026-04-30')) AS splits,
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-04-01') AND ex_dividend_date <= toDate('2026-04-30')) AS ex_divs, 1 AS o
UNION ALL SELECT '2026-05',
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-05-01') AND listing_date <= toDate('2026-05-31')),
(SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-05-01') AND execution_date <= toDate('2026-05-31')),
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-05-01') AND ex_dividend_date <= toDate('2026-05-31')), 2
UNION ALL SELECT '2026-06',
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-06-01') AND listing_date <= toDate('2026-06-30')),
(SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-06-01') AND execution_date <= toDate('2026-06-30')),
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-06-01') AND ex_dividend_date <= toDate('2026-06-30')), 3
) ORDER BY oThe corporate calendar tightened as the quarter aged: ex-dividend events climbed every month, from 3947 in April to 6651 in June, and splits rose alongside (129 to 164). Listings held steady across the three months, the wave metaphor belongs to dividends, not IPOs, this quarter.
The session receipt
The exact SQL behind every number
SELECT
(SELECT uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-04-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')) AS q2_sessions,
(SELECT uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-04-01 00:00:00') AND window_start < toDateTime('2026-05-01 00:00:00')) AS april_sessions,
(SELECT uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-05-01 00:00:00') AND window_start < toDateTime('2026-06-01 00:00:00')) AS may_sessions,
(SELECT uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-06-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')) AS june_sessions62 sessions, verified from observed bars rather than assumed from the calendar: 21 in April, 20 in May (Memorial Day), 21 in June (Juneteenth). The month-level receipts and closure evidence live in the June recap and the holiday explainer.
Data notes
Full data notes
- Short interest ends at the June 15 settlement as of generation, the end-of-June print is pending; the June recap carries the full disclosure. This post regenerates when it lands.
- The month-end filing-index gap is disclosed inline: June 30 AND April 30 fall inside this quarter, and March 31 shows the same signature, every 2026 month-end whose last calendar day was a weekday is near-empty. The diagnostic note carries the receipts and the bounded diagnosis.
- Microstructure (tick-level plumbing) is deliberately absent here, the June 29 deep-dive carries a full session's tape anatomy.
- Volume-leader exclusion: one reused-symbol June listing excluded pending entity verification.
Methodology
- The period is April 1 – June 30, 2026, 62 sessions, verified from observed bars. Quarterly returns are first regular-hours open to last regular-hours close within the period; the Q1 contrast is recomputed live on identical definitions.
- Timestamps stored UTC, filtered with raw UTC bounds; regular hours 13:30–20:00 UTC across the (EDT) quarter. Dollar volume is minute close times minute volume over regular hours. Multi-year history blocks filter regular hours on the Eastern wall clock (converted per row, the DST-safe convention across decades) and pin their upper bound at this quarter's end; the depth verification (minute history to September 2003) is in the H1 recap's methodology.
- Generation runs through the gated read-only path; the public page never queries live. Warehouse state as of July 5, 2026.
This is the first edition of the standing quarterly recap; Q3's edition will link back here. Month detail: June. The half this quarter completed: H1 2026.