Strasmore Research
Market recaps wey dey break am down Matt ConnorBy Matt Connor · Updated 2026-09-28

June 30, 2026 market recap: numbers wey matter

Quarter end na tech-led up day for market wey mostly red, with memory complex on top and same-day options tape for close. See all figures and SQL.

Tuesday, June 30, 2026, wey be the quarter’s last trading session, na technology-led up day for market wey mostly dey red: QQQ gain 1.63% and SPY 0.73%, but na only 4 out of 10 S&P sector funds close higher (3,349 liquid names up, 3,033 down). For the previous session, read the June 29 recap. Every number wey dey below come from stored query; expand any panel to see the SQL.

The scoreboard

Every change compares June 30's last regular-session minute bar with Monday June 29's.

QuerySPY / QQQ / DIA / IWM: June 30 vs June 29 close, regular hours
tickerprior closeday openday closepct changeday highday lowshares traded m
DIA521.68522.35522.280.12523.14519.592.7
IWM298.95298.56300.420.49300.98297.4419.7
QQQ723.95724.18735.761.63737.62723.9135.7
SPY740.88741.29746.320.73748.02740.8942.7
The exact SQL behind every number
WITH prior AS (
    SELECT ticker, argMax(close, window_start) AS prior_close
    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
),
sess AS (
    SELECT ticker,
           argMin(open, window_start) AS day_open,
           argMax(close, window_start) AS day_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-30 13:30:00' AND window_start < '2026-06-30 20:00:00'
    GROUP BY ticker
)
SELECT
    s.ticker AS ticker,
    round(toFloat64(p.prior_close), 2) AS prior_close,
    round(toFloat64(s.day_open), 2) AS day_open,
    round(toFloat64(s.day_close), 2) AS day_close,
    round((toFloat64(s.day_close) / toFloat64(p.prior_close) - 1) * 100, 2) AS pct_change,
    round(toFloat64(s.day_high), 2) AS day_high,
    round(toFloat64(s.day_low), 2) AS day_low,
    s.shares_traded_m AS shares_traded_m
FROM sess s
JOIN prior p ON s.ticker = p.ticker
ORDER BY s.ticker
Run am yourself

SPY open for $741.29 and e finish for $746.32, close to e high of $748.02. QQQ's 1.63% against DIA's 0.12% na the shape of the day: growth run, blue chips barely move, IWM 0.49%.

Di quarter wey close today

June 30 close di last of 62 sessions for second quarter, and di day’s direction resemble di quarter for small.

QueryQ2 2026 end to end: each index ETF from April 1 open reach June 30 close, regular hours
tickerquarter first sessionquarter sessionsquarter openquarter closequarter pctup sessions
QQQ2026-04-0162581.48735.7626.5338
IWM2026-04-0162249.92300.4220.2135
SPY2026-04-0162653.9746.3214.1336
DIA2026-04-0162466522.2812.0834
The exact SQL behind every number
WITH q2 AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMin(toFloat64(open), window_start) AS d_open,
           argMax(toFloat64(close), window_start) AS d_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
      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 ticker, d
)
SELECT
    ticker,
    toString(min(d)) AS quarter_first_session,
    count() AS quarter_sessions,
    round(argMin(d_open, d), 2) AS quarter_open,
    round(argMax(d_close, d), 2) AS quarter_close,
    round((argMax(d_close, d) / argMin(d_open, d) - 1) * 100, 2) AS quarter_pct,
    countIf(d_close > d_open) AS up_sessions
FROM q2
GROUP BY ticker
ORDER BY quarter_pct DESC, ticker ASC
Run am yourself

From April 1 open reach June 30 close: QQQ +26.53%, IWM 20.21%, SPY 14.13%, DIA 12.08%. QQQ lead for di quarter and for June 30 itself, but di middle position change: SPY pass IWM small for di day, while IWM lead SPY across di quarter. QQQ close higher for 38 out of 62 sessions (di Q2 recap dey show am panel by panel).

Day unusual be?

QuerySPY open-to-close move rank against the trailing month sessions (rank 1 = biggest absolute move)
day move pctabs move ranksessions comparedfirst session
0.687212026-06-01
The exact SQL behind every number
SELECT round(anyIf(oc_pct, d = toDate('2026-06-30')), 2) AS day_move_pct,
       arrayCount(x -> x > abs(anyIf(oc_pct, d = toDate('2026-06-30'))), groupArrayIf(abs(oc_pct), d != toDate('2026-06-30'))) + 1 AS abs_move_rank,
       count() AS sessions_compared,
       toString(min(d)) AS first_session
FROM (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           (argMax(toFloat64(close), window_start) / argMin(toFloat64(open), window_start) - 1) * 100 AS oc_pct
    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')
      AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
    GROUP BY d
)
Run am yourself

From open to close inside the session, this one na different way to look am from the close-over-close scoreboard. SPY move 0.68%, and e rank 7 out of 21 trailing sessions by absolute size. The index calm, but the trading underneath no be.

Breadth: small positive edge

QueryAdvancers vs decliners among tickers wey trade at least $1M on June 30
advancersdeclinersunchangedliquid tickerstickers traded both sessionsdropped by liquidity filteradvancer pctsector funds countedsector funds up
3349303388647011525505551.8104
The exact SQL behind every number
WITH per_ticker AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-06-30 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-30 00:00:00')) AS day_close,
        sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-30 00:00:00') AS day_dollar_volume
    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')
       OR (window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00')
    GROUP BY ticker
)
SELECT
    countIf(day_close > prior_close AND day_dollar_volume >= 1000000) AS advancers,
    countIf(day_close < prior_close AND day_dollar_volume >= 1000000) AS decliners,
    countIf(day_close = prior_close AND day_dollar_volume >= 1000000) AS unchanged,
    countIf(day_dollar_volume >= 1000000) AS liquid_tickers,
    count() AS tickers_traded_both_sessions,
    count() - countIf(day_dollar_volume >= 1000000) AS dropped_by_liquidity_filter,
    round(100.0 * countIf(day_close > prior_close AND day_dollar_volume >= 1000000)
        / countIf(day_dollar_volume >= 1000000), 1) AS advancer_pct,
    countIf(ticker IN ('XLB', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')) AS sector_funds_counted,
    countIf(ticker IN ('XLB', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')
        AND day_close > prior_close) AS sector_funds_up
FROM per_ticker
WHERE prior_close > 0 AND day_close > 0
Run am yourself

3,349 advancers, 3,033 decliners, 88 unchanged: 51.8% of the liquid tape rise, and na coin flip under a 1.63% growth-index print. The liquidity filter drop 5,055 of 11,525 dual-session tickers (under $1 million traded). We count dem here; we no hide dem.

Sector wan dey go: where money really land

To count every name as one vote no dey show where money sit. The ten funds below each hold one part of the S&P 500. The gap between the best and worst one show how uneven the session be.

QueryThe ten S&P sector funds on June 30: change vs Monday close, and how far each one dey behind the leader
tickerprior closeday closepct chgis uppts behind leaderday dollar bn
XLK185.44190.422.69101.62
XLI182.77185.221.3411.351.08
XLB50.6650.840.3612.330.41
XLY117.1117.270.1512.540.58
XLF53.753.61-0.1702.851.39
XLE53.5753.14-0.803.491.36
XLV160.74158.67-1.2903.971.78
XLU46.0245.34-1.4804.160.77
XLP84.3783.08-1.5304.210.99
XLRE44.9244.02-204.690.38
The exact SQL behind every number
WITH per_name AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-06-30 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-30 00:00:00')) AS day_close,
        round(sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-30 00:00:00') / 1e9, 2) AS day_dollar_bn
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('XLB', 'XLE', 'XLF', 'XLI', 'XLK', 'XLP', 'XLRE', 'XLU', 'XLV', 'XLY')
      AND ((window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00')
        OR (window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00'))
    GROUP BY ticker
)
SELECT
    ticker,
    round(prior_close, 2) AS prior_close,
    round(day_close, 2) AS day_close,
    round((day_close / prior_close - 1) * 100, 2) AS pct_chg,
    if(day_close > prior_close, 1, 0) AS is_up,
    round(max((day_close / prior_close - 1) * 100) OVER () - (day_close / prior_close - 1) * 100, 2) AS pts_behind_leader,
    day_dollar_bn
FROM per_name
ORDER BY pct_chg DESC, ticker ASC
Run am yourself

Technology (XLK) gain 2.69% and stand alone. Industrials 1.34%, materials 0.36% and discretionary 0.15% na the only other sectors wey close green. The board turn red from financials (-0.17%) reach utilities (-1.48%), staples (-1.53%) and real estate last at -2%. Best minus worst: 4.69 percentage points, with 4 of 10 funds green. Index rise less than one percent, but the spread underneath reach four points: na one sector carry the day.

Market-wide, the biggest movers for the day

Breadth dey count how many names rise. This one show the names wey move pass, with top and bottom five by percentage change among names wey trade $10 million or more.

QueryTop 5 gainers and top 5 decliners among names wey trade $10M+ on June 30 (one reused-symbol listing no dey inside)
boardtickerprior closeday closepct chgabs pct chgdollar volume msplit record dey file
top gainersJEM1.113.96256.76256.761410
top gainersCUPR4.456.5647.4247.421380
top gainersABVX96.17133.2538.5638.569420
top gainersAVXX5.036.8435.9835.98230
top gainersCRCD5.166.9935.4735.47180
top declinersCRCA19.7112.78-35.1635.16560
top declinersCRCG13.278.6-35.1935.19640
top declinersNVCT28.5218.36-35.6235.62510
top declinersUNCY7.74.69-39.0939.09550
top declinersSOC6.963.07-55.8955.893060
The exact SQL behind every number
WITH per_ticker AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-06-30 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-30 00:00:00')) AS day_close,
        sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-30 00:00:00') AS day_dollar_volume
    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')
       OR (window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00')
    GROUP BY ticker
    HAVING prior_close > 1 AND day_close > 0 AND day_dollar_volume >= 10000000 AND ticker NOT IN ('SPCX')
)
SELECT
    board,
    ticker,
    prior_close,
    day_close,
    pct_chg,
    round(abs(pct_chg), 2) AS abs_pct_chg,
    dollar_volume_m,
    if(ticker IN (SELECT ticker FROM global_markets.stocks_splits
                  WHERE execution_date >= '2026-06-29' AND execution_date <= '2026-06-30'), 1, 0) AS split_record_on_file
FROM (
    SELECT 'top gainers' AS board, ticker, round(prior_close, 2) AS prior_close, round(day_close, 2) AS day_close,
           round((day_close / prior_close - 1) * 100, 2) AS pct_chg, round(day_dollar_volume / 1e6, 0) AS dollar_volume_m
    FROM per_ticker
    ORDER BY (day_close / prior_close) DESC, ticker ASC
    LIMIT 5
    UNION ALL
    SELECT 'top decliners' AS board, ticker, round(prior_close, 2) AS prior_close, round(day_close, 2) AS day_close,
           round((day_close / prior_close - 1) * 100, 2) AS pct_chg, round(day_dollar_volume / 1e6, 0) AS dollar_volume_m
    FROM per_ticker
    ORDER BY (day_close / prior_close) ASC, ticker ASC
    LIMIT 5
)
ORDER BY if(board = 'top gainers', 0, 1) ASC, pct_chg DESC, ticker ASC
Run am yourself

None of the two boards look like the index. JEM lead with +256.76% on $141 million traded. SOC lose 55.89% on $306 million. ABVX rise 38.56% on $942 million, the heaviest turnover for either board. NVCT fall 35.62%, while UNCY fall 39.09%. The split-record column keep the board honest. A 1-for-10 reverse split fit print as +900% “gain” for unadjusted tape. Every name here carry a 0: real prints.

Three rows na one trade showing two times. CRCA (-35.16%) and CRCG (-35.19%) fall, while CRCD rise 35.47%. Each one dey close to twice the -17.53% move of the crypto-adjacent name below: leveraged single-stock wrappers.

The main thing for today: semiconductors enter the quarter turn

Six names, one theme, but outcomes dey very different. Data only show say dem move together and by how much; e no explain why.

QueryThe semiconductor and storage names: change vs Monday close, range, and dollar volume
tickerprior closeday closepct chgday highday high ETday lowday low ETrange %day dollar bn
AMD539.28580.827.7584.7315:21545.5709:307.1815.92
INTC131.69139.55.93142.3513:48131.5209:308.2312.9
MU11451151.010.521168.6815:151124.6609:443.9137.41
SNDK2051.292272.5910.792280.815:53207009:3010.1821.19
TSM455.12477.244.8647915:5545309:305.745.87
WDC651.7638.57-2.01663.9810:35630.309:305.344.5
The exact SQL behind every number
WITH per_name AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-06-30 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-30 00:00:00')) AS day_close,
        maxIf(toFloat64(high), window_start >= '2026-06-30 00:00:00') AS day_high,
        minIf(toFloat64(low), window_start >= '2026-06-30 00:00:00') AS day_low,
        argMinIf(window_start, toFloat64(low), window_start >= '2026-06-30 00:00:00') AS low_bar,
        argMaxIf(window_start, toFloat64(high), window_start >= '2026-06-30 00:00:00') AS high_bar,
        round(sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-30 00:00:00') / 1e9, 2) AS day_dollar_bn
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AMD', 'INTC', 'MU', 'SNDK', 'TSM', 'WDC')
      AND ((window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00')
        OR (window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00'))
    GROUP BY ticker
)
SELECT
    ticker,
    round(prior_close, 2) AS prior_close,
    round(day_close, 2) AS day_close,
    round((day_close / prior_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,
    day_dollar_bn
FROM per_name
ORDER BY ticker
Run am yourself

SanDisk jump 10.79%, AMD 7.7%, Intel 5.93%, TSMC 4.86%. MU, wey get the biggest ticket for the tape with $37.41 billion turnover, close only 0.52% higher. Western Digital (-2.01%) no join the move. Na this complex drive technology’s 2.69% sector print (MU for June, tick by tick).

The opposite move show for crypto-adjacent financials, even as the tape dey green:

QueryCrypto-adjacent financials: change vs Monday close, range, and dollar volume
tickerprior closeday closepct chgday highday high ETday lowday low ETrange %day dollar bn
COIN151.66146.19-3.61148.8609:30142.311:064.611.07
CRCL75.9762.65-17.5373.209:3262.5215:5917.082.24
HOOD101.83100.27-1.53103.0611:2999.6614:123.411.53
MSTR92.6886.93-6.288.2610:3083.4211:065.82.52
The exact SQL behind every number
WITH per_name AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-06-30 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-06-30 00:00:00')) AS day_close,
        maxIf(toFloat64(high), window_start >= '2026-06-30 00:00:00') AS day_high,
        minIf(toFloat64(low), window_start >= '2026-06-30 00:00:00') AS day_low,
        argMinIf(window_start, toFloat64(low), window_start >= '2026-06-30 00:00:00') AS low_bar,
        argMaxIf(window_start, toFloat64(high), window_start >= '2026-06-30 00:00:00') AS high_bar,
        round(sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-06-30 00:00:00') / 1e9, 2) AS day_dollar_bn
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('COIN', 'CRCL', 'HOOD', 'MSTR')
      AND ((window_start >= '2026-06-29 13:30:00' AND window_start < '2026-06-29 20:00:00')
        OR (window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00'))
    GROUP BY ticker
)
SELECT
    ticker,
    round(prior_close, 2) AS prior_close,
    round(day_close, 2) AS day_close,
    round((day_close / prior_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,
    day_dollar_bn
FROM per_name
ORDER BY ticker
Run am yourself

CRCL print -17.53%. E reach e low of $62.52 at 15:59 ET, for the final minute of the session. MSTR -6.2%, COIN -3.61% and HOOD -1.53% move alongside am. We observe say dem move together; we no dey claim the cause.

Wetin the news feed carry

A recap wey no wan talk the causes plainly still owe reader wetin dem actually publish that day.

QueryThe news feed on June 30: article count and the last headline of the day for each name wey dey this recap
tickerarticles todaylatest ETpublisher namelatest headline
NVDA2116:28Investing.comThese Stocks Could Benefit as the Robotaxi Race Heats Up
MU715:38Investing.comS&P 500 Earnings Depend on AI Infrastructure Doing the Heavy Lifting
JEM104:00GlobeNewswire Inc.707 Cayman Holdings Appoints New Executive Director
SNDK115:12The Motley FoolWhy Sandisk Stock Is Skyrocketing Today
ABVX0noneno article in our feed this sessionno article in our feed this session
CRCL0noneno article in our feed this sessionno article in our feed this session
SOC0noneno article in our feed this sessionno article in our feed this session
The exact SQL behind every number
SELECT
    names.n AS ticker,
    countIf(has(tickers, names.n)) AS articles_today,
    if(countIf(has(tickers, names.n)) = 0, 'none',
       formatDateTime(toTimeZone(argMaxIf(published_utc, (published_utc, id), has(tickers, names.n)), 'America/New_York'), '%H:%i')) AS latest_et,
    if(countIf(has(tickers, names.n)) = 0, 'no article in our feed this session',
       JSONExtractString(argMaxIf(publisher, (published_utc, id), has(tickers, names.n)), 'name')) AS publisher_name,
    if(countIf(has(tickers, names.n)) = 0, 'no article in our feed this session',
       argMaxIf(title, (published_utc, id), has(tickers, names.n))) AS latest_headline
FROM global_markets.stocks_news
CROSS JOIN (SELECT arrayJoin(['NVDA', 'MU', 'SNDK', 'CRCL', 'SOC', 'ABVX', 'JEM']) AS n) AS names
WHERE published_utc >= '2026-06-30 04:00:00' AND published_utc < '2026-07-01 04:00:00'
GROUP BY names.n
ORDER BY articles_today DESC, ticker ASC
Run am yourself

The name wey dem cover pass na NVDA, with 21 articles. E no dey among the day movers at all. The last piece for the session (16:28 ET, Investing.com) get title "These Stocks Could Benefit as the Robotaxi Race Heats Up". MU get 7 articles. SanDisk get only one article (The Motley Fool), and na the only headline for the whole day wey name an actual move: "Why Sandisk Stock Is Skyrocketing Today".

Na here the finding dey: the day biggest decliner, the strongest gainer and the crypto-adjacent name wey fall pass all get 0, 0 and 0 articles, zero each, inside feed wey get 211 pieces. Coverage no be proxy for price action.

Wey money trade

QueryVolume leaders two ways: top 6 by dollars traded, top 4 by shares traded (one reused-symbol listing no dey inside pending entity verification)
tickerleaderboarddollar volume bndollar value mshares m% of board leader
MUby dollars traded37.41None32.5100
SPYby dollars traded31.84None42.785.1
QQQby dollars traded26.2None35.770
SNDKby dollars traded21.19None9.656.6
NVDAby dollars traded20.69None104.355.3
AMDby dollars traded15.92None27.942.6
SOXSby shares traded1.72None515.5100
YHCby shares traded0.044234066
BIYAby shares traded0.1313327353
TZAby shares traded0.87866226.644
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-30 13:30:00' AND window_start < '2026-06-30 20:00:00'
      AND ticker NOT IN ('SPCX')
    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-30 13:30:00' AND window_start < '2026-06-30 20:00:00'
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker
    ORDER BY shares_m DESC
    LIMIT 4
)
ORDER BY leaderboard ASC, if(leaderboard = 'by dollars traded', dollar_volume_bn, shares_m) DESC
Run am yourself

By dollar value, MU pass everything, including index funds: $37.41 billion against SPY wey get $31.84 billion. Na the second session straight wey e trade pass the flagship index fund (Monday recap get the first one). But share count tell another story: SOXS, one 3x-leveraged inverse semiconductor ETF (515.5 million shares), plus two sub-dollar names wey their value be rounding error compared with MU for the day. Volume fit get two interpretations.

We leave one name out of both boards on purpose. Na June listing be that, and another unrelated company don use the ticker before. So vendor feeds dey tag two different entities with the same three letters (receipts dey here).

QueryShares traded per 30-minute bucket, regular hours, closing auction prints for the final bucket (billions)
ET timeshares bn% of biggest bucket
09:302.0544.3
10:001.5533.5
10:301.3629.4
11:001.1925.7
11:300.9721
12:000.919.5
12:300.8819
13:000.8217.7
13:300.7816.9
14:000.817.3
14:300.9219.9
15:001.0823.3
15:304.63100
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
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-30 13:30:00' AND window_start < '2026-06-30 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-30 20:00:00' AND sip_timestamp < '2026-06-30 20:15:00'
      AND has(conditions, 8)
)
GROUP BY et_time
ORDER BY et_time
Run am yourself

2.05 billion shares trade for the first half hour. E reach 0.78 billion trough at 13:30. Then the biggest bucket for the day, 4.63 billion, enter as quarter-end close near. Na that time closing auction and rebalancing flows dey print. The June 29 deep dive dey under the bars.

The options tape

QueryOne row for the whole options day: volume, same-day expiry, SPY put/call skew by moneyness, the holiday-shifted week
option prints mcontracts mcall % of volumesame-day expiry %Thu Jul 2 expiry contracts mFri Jul 3 expiry printsSPY contracts mQQQ contracts mSPY put-call ratioSPY 0DTE OTM calls mSPY 0DTE ITM calls mSPY 0DTE OTM puts mSPY 0DTE ITM puts mtop contract underlyingtop contract striketop contract typetop contract expirytop contract volumetop contract avg pricetop strike minus spy close
10.0661.9557.32810.52012.047.11.092.281.773.330.63SPY747C2026-06-308213610.6410.68
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-30 00:00:00' AND sip_timestamp < '2026-07-01 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-30 13:30:00' AND window_start < '2026-06-30 20:00:00'
    ) AS spy_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) = '260630') / 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,
    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,
    round(toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'P'))
        / toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'C')), 2) AS spy_put_call_ratio,
    round(toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'C'
        AND substring(ticker, length(ticker) - 14, 6) = '260630' AND toFloat64(strike_price) > spy_close)) / 1e6, 2) AS spy_0dte_otm_calls_m,
    round(toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'C'
        AND substring(ticker, length(ticker) - 14, 6) = '260630' AND toFloat64(strike_price) <= spy_close)) / 1e6, 2) AS spy_0dte_itm_calls_m,
    round(toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'P'
        AND substring(ticker, length(ticker) - 14, 6) = '260630' AND toFloat64(strike_price) < spy_close)) / 1e6, 2) AS spy_0dte_otm_puts_m,
    round(toFloat64(sumIf(size, underlying_symbol = 'SPY' AND option_type = 'P'
        AND substring(ticker, length(ticker) - 14, 6) = '260630' AND toFloat64(strike_price) >= spy_close)) / 1e6, 2) AS spy_0dte_itm_puts_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,
    round(top_contract.7, 3) AS top_contract_avg_price,
    round(top_contract.2 - spy_close, 2) AS top_strike_minus_spy_close
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-06-30 00:00:00' AND sip_timestamp < '2026-07-01 00:00:00'
Run am yourself

Options traders exchange 61.95 million contracts across 10.06 million prints. Calls make up 57.3% of all volume, while 28% expire that Tuesday. SPY move the opposite way: 12.04 million contracts with a put/call ratio of 1.09. Puts pass calls, even as the fund rise that day.

When we compare SPY same-day expiries with its $746.32 closing price, the skew clear. There are 3.33 million out-of-the-money puts, with strikes below the close, and 2.28 million out-of-the-money calls. There are also 1.77 million in-the-money calls and 0.63 million in-the-money puts. Puts with downside strikes wey expire worthless be the busiest group for SPY 0DTE day. No contract with Friday, July 3 expiry code print at all (0 prints), because market close that Friday. The Thursday weekly get 10.52 million contracts.

QueryThe six busiest option contracts on June 30, by contracts traded
contractexpiresexpires labelna same day?contractsavg premiumpct of busiest
SPY $747 call2026-06-30June 30, 202618213610.641100
SPY $748 call2026-06-30June 30, 202615583470.34668
SPY $746 put2026-06-30June 30, 202615519420.7967.2
SPY $746 call2026-06-30June 30, 202615438040.93666.2
KWEB $29 call2026-12-18December 18, 202605344591.17165.1
SPY $745 call2026-06-30June 30, 202614974501.22760.6
The exact SQL behind every number
SELECT
    concat(underlying, ' $', toString(strike), ' ', if(typ = 'C', 'call', 'put')) AS contract,
    toString(expiry) AS expires,
    formatDateTimeInJodaSyntax(expiry, 'MMMM d, yyyy') AS expires_label,
    if(expiry = toDate('2026-06-30'), 1, 0) AS is_same_day,
    contracts,
    round(avg_px, 3) AS avg_premium,
    round(100 * contracts / max(contracts) OVER (), 1) AS pct_of_busiest
FROM (
    SELECT any(underlying_symbol) AS underlying,
           any(toFloat64(strike_price)) AS strike,
           any(option_type) AS typ,
           any(toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6)))) AS expiry,
           sum(size) AS contracts,
           avg(toFloat64(price)) AS avg_px,
           any(ticker) AS occ
    FROM global_markets.options_trades
    WHERE sip_timestamp >= '2026-06-30 00:00:00' AND sip_timestamp < '2026-07-01 00:00:00'
    GROUP BY ticker
    ORDER BY contracts DESC, occ ASC
    LIMIT 6
)
ORDER BY contracts DESC, contract ASC
Run am yourself

The busiest contract for the whole market na same-day SPY $747 call. E trade 821,361 contracts for average option premium of $0.641. E finish $0.68 above SPY last regular bar, but e expire worthless. The activity around am show the main lesson: five of the six busiest contracts for the whole tape be same-day SPY strikes wey dey one dollar apart around the close (SPY $748 call next). Each one trade for just cents. The exception, with 65.1% of the leader volume, na KWEB $29 call wey expire December 18, 2026. E no be same-day contract. Na one six-month position among five afternoon lottery tickets.

Rates: long end rise as half-year dey close

QueryThe Treasury curve, June 30 close vs June 29 (only maturities wey get data)
curve pointJun30 yield pctone day change bp
1 month3.7-1
3 month3.870
1 year3.981
2 year4.144
5 year4.195
10 year4.446
30 year4.915
2s10s spread0.32
The exact SQL behind every number
SELECT
    t.1 AS curve_point,
    round(t.2, 2) AS jun30_yield_pct,
    round((t.2 - t.3) * 100) AS one_day_change_bp
FROM (
    SELECT arrayJoin([
        ('1 month',  toFloat64(d.yield_1_month),  toFloat64(p.yield_1_month)),
        ('3 month',  toFloat64(d.yield_3_month),  toFloat64(p.yield_3_month)),
        ('1 year',   toFloat64(d.yield_1_year),   toFloat64(p.yield_1_year)),
        ('2 year',   toFloat64(d.yield_2_year),   toFloat64(p.yield_2_year)),
        ('5 year',   toFloat64(d.yield_5_year),   toFloat64(p.yield_5_year)),
        ('10 year',  toFloat64(d.yield_10_year),  toFloat64(p.yield_10_year)),
        ('30 year',  toFloat64(d.yield_30_year),  toFloat64(p.yield_30_year)),
        ('2s10s spread', toFloat64(d.yield_10_year - d.yield_2_year), toFloat64(p.yield_10_year - p.yield_2_year))
    ]) AS t
    FROM (SELECT * FROM global_markets.treasury_yields WHERE date = '2026-06-30') AS d,
         (SELECT * FROM global_markets.treasury_yields WHERE date = '2026-06-29') AS p
)
Run am yourself

Long end rise for the final day of the half-year: the 10-year rise 6 bp reach 4.44%, the 2-year rise 4 bp reach 4.14%, and 2s10s spread steepen 2 bp reach 0.3 points. Long yields rise during session wey the weakest sector, real estate (-2%), and the third-weakest, utilities (-1.48%), both dey classically sensitive to rates. Na co-occurrence wey worth noting, but no be mechanism wey this data fit prove (H1 recap carry the half-year curve).

Calendar wey dey behind the day

QueryJune 30 corporate calendar and information flow, all for one row (the filing-index gap dey show)
ex-dividend recordssplits executedIPOs listedSEC filingsinsider Form 4 filings8-K filingsIPO namesnews articlesnews publishersmost covered tickermost covered articlesfilings for prior session
704723100AACU — Ares Acquisition Corp III; OSPRU — Osprey Acquisition Corp. III2113NVDA214439
The exact SQL behind every number
WITH
    (
        SELECT (count(), uniqExact(publisher))
        FROM global_markets.stocks_news
        WHERE toDate(toTimeZone(published_utc, 'America/New_York')) = '2026-06-30'
    ) AS news,
    (
        SELECT (argMax(t, n), 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-30'
            )
            WHERE t != 'SPCX'
            GROUP BY t
        )
    ) AS top_news
SELECT
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date = '2026-06-30') AS ex_dividend_records,
    (SELECT count() FROM global_markets.stocks_splits WHERE execution_date = '2026-06-30') AS splits_executed,
    (SELECT count() FROM global_markets.stocks_ipos WHERE listing_date = '2026-06-30') AS ipos_listed,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = '2026-06-30') AS sec_filings,
    (SELECT uniqExactIf(accession_number, form_type = '4') FROM global_markets.stocks_sec_edgar_index WHERE filing_date = '2026-06-30') AS insider_form4_filings,
    (SELECT uniqExactIf(accession_number, form_type = '8-K') FROM global_markets.stocks_sec_edgar_index WHERE filing_date = '2026-06-30') AS filings_8k,
    (SELECT arrayStringConcat(groupArray(concat(ticker, ' — ', issuer_name)), '; ') FROM (
        SELECT ticker, issuer_name FROM global_markets.stocks_ipos WHERE listing_date = '2026-06-30' ORDER BY ticker
    )) AS ipo_names,
    news.1 AS news_articles,
    news.2 AS news_publishers,
    top_news.1 AS most_covered_ticker,
    top_news.2 AS most_covered_articles,
    (SELECT uniqExact(accession_number) FROM global_markets.stocks_sec_edgar_index WHERE filing_date = toDate('2026-06-29')) AS filings_prior_session
Run am yourself

704 dividend records went ex-dividend for the quarter’s last day. Na quarter-end wave be this, as most US companies dey pay quarterly. E get 7 splits and 2 new listings (AACU — Ares Acquisition Corp III; OSPRU — Osprey Acquisition Corp. III). The filing column na the main data-quality headline. The SEC index hold 31 filings for June 30: 0 insider Form 4s, 0 8-Ks, against 4439 the session before. The feed show month-end pattern, as the month-end gap note explain. Any count wey include this day still low until the backfill complete.

Session wey dem verify

QuerySession check: SPY observed minute-bar span
first SPY bar ETlast SPY bar ETSPY minute barsregular session barsday sessions
04:0019:598603901
The exact SQL behind every number
SELECT
    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-30 13:30:00' AND window_start < '2026-06-30 20:00:00') AS regular_session_bars,
    uniqExactIf(toDate(toTimeZone(window_start, 'America/New_York')), window_start >= '2026-06-30 13:30:00' AND window_start < '2026-06-30 20:00:00') AS day_sessions
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start >= '2026-06-30 00:00:00' AND window_start < '2026-07-01 00:00:00'
Run am yourself

SPY bars dey run from 04:00 to 19:59 New York time, with exactly 390 bars for regular trading window. Na complete session, and tape don verify am. Exchange-calendar dataset only get closures wey dey come.

Wetin the session add up to

One 0.73% SPY print with 51.8% names higher, 4 of 10 sector funds green, and 4.69 points between the best and worst no be broad rally. Na one sector rally wey dey wear index clothes, plus e happen during the heaviest half-hour of a quarter-end auction. Index change na average, and technology carry this one while most sectors fall. Check the dispersion before you trust the direction.

FAQ

How stock market do for June 30, 2026?

E close higher: SPY gain 0.73% and QQQ gain 1.63% compared with June 29 closing. Market breadth narrow pass: 51.8% of liquid names rise, while 4 of 10 S&P sector funds close green.

Which sector lead market for June 30, 2026?

Technology: XLK gain 2.69%. Industrials follow with 1.34%, while real estate come last with -2%. Difference between the best and worst na 4.69 points.

Which stocks move pass for June 30, 2026?

Among names wey trade $10 million or more, JEM gain pass with +256.76%, while SOC lose pass with 55.89%. No split record dey for either one. So, na real price moves be this, no be corporate-action artifacts.

How stock market do for Q2 2026?

From April 1 opening to June 30 closing, across 62 sessions: QQQ +26.53%, IWM 20.21%, SPY 14.13%, DIA 12.08%. Quarter na growth-led one, and growth-led day na how e end.

Why volume dey trade plenty for the last half hour?

The final half hour carry 4.63 billion shares, compared with 2.05 billion for the open. Closing auction set each stock official closing price through one crossing. Index funds trade for that auction to match the closing price. Quarter-end rebalancing also concentrate the flow.

Data notes and method

  • The baskets. Sector board na the ten SPDR sector funds wey panel name, and na the same basket every session, so dispersion number fit compare across days. Mover boards dey require $10 million turnover and previous close above $1. Dem exclude the reused-symbol listing wey dey above, and dem carry split-record column.
  • The caveats. Dollar volume na per-minute proxy (close × volume for each bar). June 30 filing index almost empty; month-end gap note explain why. News counts come from one vendor feed only: if article no dey here, e no prove say nobody publish am anywhere.
  • The volume panel's closing half hour counts the closing auction prints. One-minute bars no include auction prints, so half-hour panel add every trade wey carry closing-print sale condition, timestamped 4:00 to 4:15 p.m. ET for consolidated tape, to the final bucket.
  • The method. Na one session (1, verified from observed bars); timestamps dey stored for UTC and queries convert dem to New York time; "close" na the last regular minute bar, no be auction print. Dem re-parse option expiries from OCC ticker because table own column spoil; dem measure moneyness against SPY last regular bar. Panels run once, when author dey prepare am, through gated read-only path. Warehouse as of July 13, 2026.

Every panel na stored query result, chart, table and SQL inside one object. Paste any of dem into Strasmore terminal. Next session: July 1.

#recap#daily#spy#qqq#market structure