Strasmore Research
Market Recap

Market Recap: Week of June 29, 2026

Matt ConnorBy Matt Connor Updated 2026-07-25

Last week for June na four-session week: market trade from Monday June 29 reach Thursday July 2, den e close Friday July 3 for Independence Day — July 4 fall for Saturday, so dem observe di holiday for di Friday before. Di receipts for dat closure, and for everi oda tin here, dey inside di panels. Di week most notable measured fact siddon for di volume table: one memory-chip maker put $190.2 billion through di tape for four days — e be half again as much as SPY itself. Everi number for dis page na stored query result; expand any panel for di exact SQL.

Di week for board

Di tape recover di drop wey happen di week before, or e extend am? Di scoreboard show say e recover: dis panel dey calculate each index ETF week-over-week change and, for contrast, di week before am — both sides fresh from di same query.

QueryWeek-over-week: di four index ETFs against di prior Friday close
The exact SQL behind every number
SELECT ticker,
    round(argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-26') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199), 2) AS prior_friday_close,
    round(argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-06-29') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199), 2) AS week_close,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-06-29') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199)
         / argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-26') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) - 1) * 100, 1) AS week_change_pct,
    round((argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-26') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199)
         / argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-18') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) - 1) * 100, 1) AS prior_week_change_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
  AND window_start >= toDateTime('2026-06-15 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')
GROUP BY ticker
ORDER BY ticker

SPY finish di week for $744.8, e up 2.2% from di Friday before — afta one -2.3% week before am. QQQ rise 1% afta one -4.6% prior week, DIA gain 2%, and IWM close for 297.530% for di week, e flat while di large-cap indexes rise.

Di week against di trailing year

QueryDis week against di trailing year of weeks: SPY, open-to-close inside each week (rank 1 = best; short weeks dem exclude)
The exact SQL behind every number
SELECT round(anyIf(ret, wk = toDate('2026-06-29')), 2) AS week_2026_pct,
       arrayCount(x -> x > anyIf(ret, wk = toDate('2026-06-29')), groupArrayIf(ret, wk != toDate('2026-06-29'))) + 1 AS rank_best,
       count() AS weeks_compared,
       toString(min(wk)) AS first_week,
       anyIf(sessions, wk = toDate('2026-06-29')) AS sessions_this_week
FROM (
    SELECT toStartOfWeek(toDate(toTimeZone(window_start, 'America/New_York')), 1) AS wk,
           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 = 'SPY'
      AND window_start >= toDateTime('2025-06-29 00:00:00')
      AND window_start < toDateTime('2026-07-03 00:00:00')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY wk
    HAVING sessions >= 3
)

Measure from open-to-close inside di week — Monday first regular-hours bar reach Thursday last, e be small different lens from di Friday-close scoreboard wey dey up, and di receipt state am — SPY week rank na 14 out of di trailing 53 weeks (rank 1 = best): e dey middle of di pack, for one trailing year wey contain both di selloff and di recovery. Weeks wey get fewer than three sessions dem dey exclude am by one session guard; dis one get 4. Historical context dey scale with di window — di month, quarter, and half recaps dey rank dia periods against every year of di minute tape.

Four sessions, then holiday

Five-day trading week na assumption, no be fact — dis one get four sessions. Di receipt panel check di closure from di tape itself: zero SPY bars print for July 3 against 1560 regular-session bars across di four traded days.

QueryDi session receipt: four traded days, one Friday closure, verify from di tape
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-06-29 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')) AS sessions_in_week,
    (SELECT countIf((toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) FROM global_markets.delayed_stocks_minute_aggs
     WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-06-29 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')) AS regular_bars_week,
    (SELECT count() FROM global_markets.delayed_stocks_minute_aggs
     WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-07-03 00:00:00') AND window_start < toDateTime('2026-07-04 00:00:00')) AS jul3_spy_bars
QuerySession by session: SPY close, change, and full-day volume
The exact SQL behind every number
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
    round(argMaxIf(toFloat64(close), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199), 2) AS spy_close,
    round((argMaxIf(toFloat64(close), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) / any(prev) - 1) * 100, 1) AS change_pct,
    round(toFloat64(sum(volume)) / 1e6, 1) AS shares_m
FROM global_markets.delayed_stocks_minute_aggs
INNER JOIN (
    SELECT d, lagInFrame(c) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, argMaxIf(toFloat64(close), window_start, (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) AS c
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-06-26 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')
        GROUP BY d
    )
) AS p ON toDate(toTimeZone(window_start, 'America/New_York')) = p.d
WHERE ticker = 'SPY' AND window_start >= toDateTime('2026-06-29 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')
GROUP BY et_date
ORDER BY et_date

All four sessions run di full regular schedule — di 1560 regular bars work out to exactly four 390-minute sessions. Di week close essentially flat (-0.1%) on 2026-07-02, as we dey head into di holiday — di week gains show for im first three sessions.

Breadth: how much of di market go up

One index wey dey rise fit hide market wey dey fall. Dis panel dey count every ticker wey get close for both sides of di week, with di ones wey dem remove dey show, not just silently drop.

QueryAdvancers and decliners for di week, with di liquidity filter wey dem disclose
The exact SQL behind every number
SELECT
    countIf(chg > 0 AND NOT dropped) AS advancers,
    countIf(chg < 0 AND NOT dropped) AS decliners,
    countIf(chg = 0 AND NOT dropped) AS unchanged,
    countIf(dropped) AS dropped_by_liquidity_filter,
    count() AS tickers_with_both_closes
FROM (
    SELECT ticker,
        argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-06-29') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199)
      - argMaxIf(toFloat64(close), window_start, toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-26') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) AS chg,
        sumIf(toFloat64(close) * toFloat64(volume), toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-06-29')) < 1e6 AS dropped
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= toDateTime('2026-06-26 00:00:00') AND window_start < toDateTime('2026-07-03 00:00:00')
    GROUP BY ticker
    HAVING countIf(toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-26') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) > 0
       AND countIf(toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-06-29') AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199) > 0
)

5047 tickers rise for di week against 3525 wey fall (39 no change) — di advance broad, no be just index-level. Di liquidity filter comot 3163 tickers wey trade under $1M all week; dem dey counted here, dem no hide.

Di tape leaders: one stock wey pass di ETFs

QueryRegular-hours dollar volume, week of June 29 (dem exclude one reused-symbol listing pending entity verification)
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-06-29 00:00:00') AND window_start < toDateTime('2026-07-03 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 8

MU lead di whole tape wit $190.2 billion for regular-hours dollar volume — SPY, di biggest ETF, do 66.4% of dat one. One single company wey trade pass di market default index fund for one full week na di week standout measured fact; dis page report di size of di flow, no be di reason for am. Basis: June 29–July 2 regular hours; dem exclude one reused-symbol June listing pending entity verification — im receipts dey for im own deep-dive.

Di holiday move di weeklies

Wia Friday weekly expiry dey go wen Friday no open? Di options tape dey answer directly: dis panel dey bring out di expiry date from every contract wey dem trade during di week and rank dem.

QueryContracts wey dem trade during di week, by expiry date (single-pass scan; batch-generated)
The exact SQL behind every number
SELECT concat('20', substring(expiry_raw, 1, 2), '-', substring(expiry_raw, 3, 2), '-', substring(expiry_raw, 5, 2)) AS expiry,
    round(sum(size) / 1e6, 1) AS contracts_m,
    round(100 * sum(size) / max(sum(size)) OVER (), 1) AS pct_of_biggest
FROM (
    SELECT substring(ticker, length(ticker) - 14, 6) AS expiry_raw, size
    FROM global_markets.options_trades
    WHERE sip_timestamp >= toDateTime64('2026-06-29 00:00:00', 9) AND sip_timestamp < toDateTime64('2026-07-03 00:00:00', 9)
)
GROUP BY expiry
ORDER BY contracts_m DESC
LIMIT 6

Di busiest expiry for di week na 2026-07-02 — na Thursday — at 74.1 million contracts, 42.2% ahead of di next date. As July 3 close, di week "Friday" expiration settle for Thursday instead; Monday-go-Wednesday daily expiries and di July 17 monthly complete di table. Dem dey re-parse expiry dates from each contract OCC symbol (di tape own expiry column no dey reliable); di mechanics of expiry weeks like dis one dey inside di holiday explainer.

Rates: di 10-year don back up

QueryTreasury yields through di week (July 2 print neva enter as at generation)
The exact SQL behind every number
SELECT toString(date) AS d,
    round(yield_10_year, 2) AS y10,
    round(yield_2_year, 2) AS y2,
    round((yield_10_year - yield_2_year) * 100, 0) AS spread_2s10s_bp
FROM global_markets.treasury_yields
WHERE date >= toDate('2026-06-26') AND date <= toDate('2026-07-02')
ORDER BY date

Di 10-year move from 4.38% for di Friday wey pass go 4.48% by 2026-07-01, as di 2s10s spread still dey near 31 basis points. One disclosure: di July 2 yield print neva enter wen dem generate dis page (4 rows reach July 1) — di panel go carry am for di next regeneration.

Di calendar: one quarter don end, one filing day just vanish

QueryDi week corporate calendar — with di June 30 filing-index gap on display
The exact SQL behind every number
SELECT
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= toDate('2026-06-29') AND ex_dividend_date <= toDate('2026-07-02')) AS ex_div_events,
    (SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= toDate('2026-06-29') AND execution_date <= toDate('2026-07-02')) AS splits,
    (SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= toDate('2026-06-29') AND listing_date <= toDate('2026-07-02')) AS ipos,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-29')) AS filings_jun29,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-30')) AS filings_jun30,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-07-01')) AS filings_jul1,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-07-02')) AS filings_jul2,
    (SELECT count() FROM global_markets.stocks_news WHERE published_utc >= toDateTime('2026-06-29 00:00:00') AND published_utc < toDateTime('2026-07-03 00:00:00')) AS news_articles

Di week carry 2217 ex-dividend events, 48 splits, and 7 new listings enter di quarter turn. Di filing columns hold di week data-quality find: di SEC filing index show 4439 filings for June 29 and 4282 for July 1, but only 31 for June 30 — di quarter final day. Prior-year quarter-end days dey carry thousands. Di gap dey inside di data feed, no be wetin companies file; any June or Q2 filing count wey include June 30 no complete until di index backfill. E be part of one 2026 month-end pattern — di diagnostic note carry di receipts — dem disclose am here and for di June and Q2 recaps.

Di shorts: one file wey dem cut short, three wey complete

QueryFINRA off-exchange short volume by session: coverage and marked-short share
The exact SQL behind every number
SELECT toString(date) AS d,
    uniqExact(ticker) AS tickers_on_file,
    max(ticker) AS alphabetical_end,
    round(100 * sum(toFloat64(short_volume)) / sum(toFloat64(total_volume)), 1) AS marked_short_pct
FROM (
    SELECT date, ticker, any(short_volume) AS short_volume, any(total_volume) AS total_volume
    FROM global_markets.stocks_short_volume
    WHERE date >= toDate('2026-06-29') AND date <= toDate('2026-07-02')
    GROUP BY date, ticker
)
GROUP BY date
ORDER BY date

Off-exchange volume bin dey marked short for roughly 48.8% mid-week — na normal market-maker plumbing, no be squeeze signal. Di coverage columns get disclaimer: di June 29 file na truncated one for di whole market (5489 tickers wey stop for "SSUS" against like 15,000 wey stop for "ZYME" for days wey complete), so June 29 45.8% na from partial file dem calculate am. Di June 29 deep-dive get di full market-wide probe.

Data notes

Full data notes
  • July 3 na FULL closure, no be early close. July 4, 2026 fall for Saturday; NYSE and Nasdaq observe di holiday for Friday July 3 — 0 SPY bars print dat day. One dataset note wey show wen dis page regenerate: di exchange-calendar table na rolling upcoming-holidays feed, and di July 3 row don age comot from am once di holiday pass (e dey for dis page first edition), so di closure receipt na di tape zero-bar day; di mechanics dey inside di holiday explainer.
  • Short interest end for di June 15 settlement. Di end-of-June bi-monthly settlement neva publish wen dem generate dis page; nothing here dey use am, and di June recap carry di disclosure in full. Dis post go regenerate when e land.
  • Di June 30 filing-index gap dem disclose am inline for up; di July 2 treasury print dey pending ingestion.
  • Di June 29 FINRA short-volume file don truncate market-wide; dem show im ratio with im coverage inline.
  • Volume-leader exclusion: one June listing dey trade under one reused symbol and dem exclude am from di leaderboard pending entity verification (im own post carry di receipts).

How We Do Am

  • Di period na June 29 reach July 2, 2026 — di four trading days for di week; July 3 na market holiday. We check session boundaries from wetin we see for bars, we no dey guess (di exchange-calendar dataset only get upcoming holidays — check di data note).
  • We dey store timestamps for UTC and filter dem with raw UTC boundaries; regular hours for dis (EDT) week na 13:30–20:00 UTC. Closes na di last regular-hours minute bar; dollar volume na minute close times minute volume, we sum am over regular hours.
  • Week-over-week figures dey compare against di prior Friday close, wey we compute fresh inside di same query as dis week own — we no dey ever read am from stored value. Di trailing-year rank dey recompute every week di same way (Eastern-wall-clock regular hours, minimum-session guard, upper bound wey dey pinned at dis week end).
  • Generation dey run through di gated read-only path; di public page no dey ever query live. Warehouse state as of July 5, 2026.

Dis na di first edition of di standing weekly recap — next week edition go cover July 6–10 and go link back here. Di June 29 daily recap dey cover Monday with day-level detail.