The first half of 2026 was two different markets stitched together: a first quarter in which every major index ETF fell or went nowhere, and a second quarter that more than repaired it. SPY finished the half up 8.8%; QQQ up 18.7% — all of it, and more, earned after March. The rates market told its own story: the 2s10s spread flattened from 72 basis points to 30 across the half. Every number here is a stored query result; expand any panel for the SQL.
The half on the board
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-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 h1_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)
/ 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-06-30') AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS h1_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 tickerThe two-quarter split is the half's defining shape: SPY -5.2% then 14.1%; QQQ -6.9% then 26.5%. IWM was the half's quiet leader at 21.3% — small caps beat every large-cap index over the six months. The quarter detail lives in the Q2 recap. A note on the arithmetic of halves: SPY's 8.8% for the six months is far less than its Q2 alone, since the half chains a drawdown and a recovery — the compounding of -5.2% and 14.1% lands where the table says, and any 'first-half return' headline quietly encodes that whole round trip.
Month by month
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(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) / argMinIf(toFloat64(open), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) - 1) * 100, 1) AS month_return_pct,
round(argMaxIf(toFloat64(close), window_start, (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959), 2) AS month_close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ')
AND window_start >= toDateTime('2026-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')
GROUP BY period_start, ticker
ORDER BY period_start, tickerThe staircase runs up a little, down, down, sharply up, up, down a little: April was the half's pivot (SPY 9.9%, QQQ 14.8% — QQQ's best month of the six), and June closed the half quietly at -1.2% for SPY. June's own recap, with the breadth split behind that quiet number, is here. Reading the table month by month: the year opened nearly flat (SPY 0.9% in January), slid through February (-0.5%) and March (-4.2%), then April reversed the run in a single month, May extended it (4.9%), and June eased. Three of six months were negative — a coin-flip month count for a half that finished solidly positive, which is the usual shape of equity halves and worth remembering when a single month reads as a verdict.
Rates: forty basis points of flattening
The exact SQL behind every number
SELECT
round(argMin(yield_10_year, date), 2) AS y10_start,
round(argMax(yield_10_year, date), 2) AS y10_end,
round((argMax(yield_10_year, date) - argMin(yield_10_year, date)) * 100, 0) AS y10_change_bp,
round(argMin(yield_2_year, date), 2) AS y2_start,
round(argMax(yield_2_year, date), 2) AS y2_end,
round((argMax(yield_2_year, date) - argMin(yield_2_year, date)) * 100, 0) AS y2_change_bp,
round((argMin(yield_10_year - yield_2_year, date)) * 100, 0) AS s2s10_start_bp,
round((argMax(yield_10_year - yield_2_year, date)) * 100, 0) AS s2s10_end_bp
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30')
AND isNotNull(yield_10_year) AND isNotNull(yield_2_year)Both ends of the curve rose, unevenly: the 10-year climbed 25 basis points (from 4.19% to 4.44%) while the 2-year climbed 67 (from 3.47% to 4.14%). The short end rising faster than the long end is what a flattening IS — the 2s10s spread compressed from 72 to 30 basis points — that arithmetic, nothing more mysterious.
The exact SQL behind every number
SELECT toString(date) AS d, round((yield_10_year - yield_2_year) * 100, 0) AS spread_2s10s_bp
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-01-01') AND date <= toDate('2026-06-30')
AND isNotNull(yield_10_year) AND isNotNull(yield_2_year)
ORDER BY dateThe daily series shows the flattening was not one event but a grind — 124 prints stepping down through the half, with the spread starting the year at 72 basis points and ending at 30.
The half's IPO wave, month by month
The exact SQL behind every number
SELECT toString(toStartOfMonth(listing_date)) AS m, count() AS listings
FROM global_markets.stocks_ipos
WHERE listing_date >= toDate('2026-01-01') AND listing_date <= toDate('2026-06-30')
GROUP BY m
ORDER BY mThe listing wave was front-loaded and uneven: February was the half's busiest month at 47 listings and March its quietest at 17 — the famous June mega-listing arrived in a month of otherwise ordinary volume (35 listings).
The half's calendar
The exact SQL behind every number
SELECT
(SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-01-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-01-01') AND execution_date <= toDate('2026-06-30')) AS splits,
(SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-01-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-01-01') AND filing_date <= toDate('2026-06-30')) AS h1_filings,
(SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-03-31')) AS filings_mar31,
(SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-30')) AS filings_jun30205 companies came public in the half — a listing wave whose largest June debut has its own receipt-by-receipt post — alongside 830 splits and 28356 ex-dividend events. For scale, that is more than one new listing per trading session across the half. The filing total carries a double disclosure: BOTH quarter-end index days are near-empty in the vendor feed (55 filings indexed on March 31 and 31 on June 30, against thousands on neighboring days), so half-year filing counts are understated until the feed backfills.
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-01-01 00:00:00') AND window_start < toDateTime('2026-07-01 00:00:00')) AS h1_sessionsData notes
Full data notes
- Short interest ends at the June 15 settlement as of generation (end-of-June print pending — full disclosure in the June recap; this post regenerates when it lands).
- Both 2026 quarter-end filing-index days are near-empty in the vendor feed — disclosed inline with the counts. Prior-year quarter-ends carry thousands of filings, so this is a feed gap, not a filing holiday.
- No whole-market volume leaderboard at half scale: a six-month market-wide scan exceeds the query budget this page is generated under; the Q2 and June recaps carry the leaders at their scales.
- Microstructure lives in the June 29 deep-dive.
Methodology
- The period is January 1 – June 30, 2026 — 123 sessions, verified from observed bars. Returns are first regular-hours open to last regular-hours close within each window, all computed in the same queries shown.
- Timestamps stored UTC with raw UTC bounds; regular hours are 14:30–21:00 UTC in EST months and 13:30–20:00 UTC in EDT months — the minute-of-day filter used here (13:30–20:00 UTC) matches EDT; EST-month figures use the same clock convention for comparability and the convention is stated here.
- Generation runs through the gated read-only path; the public page never queries live. Warehouse state as of July 4, 2026.
This is the first edition of the standing semiannual recap; the full-year edition follows in January. Quarter detail: Q2 2026.