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

Market Recap: Week of July 20 2026

We look at how SPY move after July options expiration. See the index scoreboard, sector dispersion, weekly breadth, and where the market dollars flow for this period.

5
The week of July 20, 2026 na the first full week wey follow July monthly options expiration, and e run for 5 sessions without any closure inside. SPY close-over-close change for the week reach -0.59%, and when we measure open-to-close against the trailing year of weeks, e rank 43 out of 53. Every number wey dey below come from one stored query, and every window dey pinned to specific dates, so if you run the SQL again, you go still see the same figures.

Di week for di board

Weekly changes start from Friday July 17 regular close reach Friday July 24. Di last column show di week wey pass, so di two dey side-by-side. Rows follow alphabetical order.

QuerySPY / QQQ / DIA / IWM: week of July 20 vs July 17 close, plus how e be last week
tickerprice wey week startprice wey week endweek change (%)last week change (%)
DIA520.76518.79-0.38-0.95
IWM294.09291.2-0.98-0.63
QQQ695.3684.22-1.59-4.17
SPY743.2738.85-0.59-1.55
The exact SQL behind every number
SELECT ticker,
    round(argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00'), 2) AS prior_week_close,
    round(argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00'), 2) AS week_close,
    round((argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00')
         / argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00') - 1) * 100, 2) AS week_change_pct,
    round((argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
         / argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-10 13:30:00' AND window_start < '2026-07-10 20:00:00') - 1) * 100, 2) AS prior_week_change_pct
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'QQQ', 'DIA', 'IWM')
  AND ((window_start >= '2026-07-10 13:30:00' AND window_start < '2026-07-10 20:00:00')
    OR (window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
    OR (window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00'))
GROUP BY ticker
ORDER BY ticker
Run am yourself

For di week: DIA move -0.38%, IWM -0.98%, QQQ -1.59%, and SPY -0.59% reach one $738.85 close. Di readings for di week before, for di same alphabetical order, na -0.95%, -0.63%, -4.17%, and -1.55%. How far di four indexes dey from each other na di first tin wey scoreboard dey measure, and e no dey small all di time.

The week against the trailing year

One week number no mean much if you no look at the distribution wey dey behind am. This panel dey recompute every trailing week using the same logic, from open-to-close throughout the regular session, and e dey rank this one inside am.

QuerySPY week inside trailing-year context (open-to-close weekly returns)
open-to-close (%)rank wey bestweeks wey we comparefirst weekdays wey market open
-1.143532025-07-215
The exact SQL behind every number
SELECT round(anyIf(ret, wk = toDate('2026-07-20')), 2) AS week_open_to_close_pct,
       arrayCount(x -> x > anyIf(ret, wk = toDate('2026-07-20')), groupArrayIf(ret, wk != toDate('2026-07-20'))) + 1 AS rank_best,
       count() AS weeks_compared,
       toString(min(wk)) AS first_week,
       anyIf(sessions_measured, wk = toDate('2026-07-20')) 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_measured,
           (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-07-21 00:00:00')
      AND window_start < toDateTime('2026-07-25 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_measured >= 3
)
Run am yourself

If you measure am like that, SPY return -1.1% and e rank 43 out of 53 weeks wey go back reach 2025-07-21. Make you note the difference for the definition: this figure start from the first regular-session open of the week, but the scoreboard wey dey up so start from the close of the week before. We label both of dem everywhere wey dem appear.

Five sessions, one arc

QuerySPY per session: close, change, and share volume, July 20-24
dateSPY closechange (%)SPY shares (m)
2026-07-20742.1-0.1540.1
2026-07-21748.320.8425.6
2026-07-22747.39-0.1226.6
2026-07-23738.24-1.2248
2026-07-24738.850.0840.1
The exact SQL behind every number
SELECT toString(d) AS date,
       round(c, 2) AS spy_close,
       round((c / prev_c - 1) * 100, 2) AS change_pct,
       round(shares_m, 1) AS spy_shares_m
FROM (
    SELECT d, c, shares_m,
           lagInFrame(c) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_c
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
               argMax(toFloat64(close), window_start) AS c,
               toFloat64(sum(volume)) / 1e6 AS shares_m
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY'
          AND ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-24 20:00:00'))
          AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
        GROUP BY d
    )
)
WHERE d >= '2026-07-20'
ORDER BY date
Run am yourself

Session by session, SPY change read -0.15% for Monday, 0.84% for Tuesday, -0.12% for Wednesday, -1.22% for Thursday, and 0.08% for Friday, wey come finish at $738.85 on top 40.1 million shares. We measure Monday figure against the July 17 close, wey be the session wey come just before this period.

Breadth, session by session

Index level na just one number. Breadth dey count how many stocks follow am move, and na that number dey decide weda the green week wide or e narrow.

QueryAdvancers and decliners per session, names wey get $5M+ volume, July 20-24
datestocks wey go upstocks wey go downstocks wey no movenames wey we check
2026-07-2012682632453945
2026-07-2125161450414007
2026-07-2215952332333960
2026-07-2312322815304077
2026-07-2422731635423950
The exact SQL behind every number
SELECT toString(d) AS date, advancers, decliners, unchanged, measured_names
FROM (
    SELECT d,
           countIf(c > prev_c) AS advancers,
           countIf(c < prev_c) AS decliners,
           countIf(c = prev_c) AS unchanged,
           count() AS measured_names
    FROM (
        SELECT d, c, dv,
               lagInFrame(c) OVER (PARTITION BY ticker ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_c
        FROM (
            SELECT ticker,
                   toDate(toTimeZone(window_start, 'America/New_York')) AS d,
                   argMax(toFloat64(close), window_start) AS c,
                   sum(toFloat64(close) * toFloat64(volume)) AS dv
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
                OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-24 20:00:00'))
              AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
            GROUP BY ticker, d
        )
    )
    WHERE d >= '2026-07-20' AND prev_c > 0 AND dv >= 5000000
    GROUP BY d
)
ORDER BY date
Run am yourself

For Monday, 1268 out of 3945 measured names rise and 2632 fall. By Friday, the split show 2273 up against 1635 down, out of 3950. We dey exclude names wey no get close for both sides of a session, na why the measured count dey shift small-small everyday.

The same question wey we ask one time, for the whole week:

QueryWeekly breadth: July 24 regular close vs July 17 regular close, names wey get $5M+ volume for week
stocks wey go upstocks wey go downstocks wey no movenames wey we checkliquidity filter comot amadvancer (%)
24373630336100509940
The exact SQL behind every number
SELECT
    countIf(cw > cp AND liquid) AS advancers,
    countIf(cw < cp AND liquid) AS decliners,
    countIf(cw = cp AND liquid) AS unchanged,
    countIf(liquid) AS measured_names,
    countIf(NOT liquid) AS dropped_by_liquidity_filter,
    round(100.0 * countIf(cw > cp AND liquid) / countIf(liquid), 1) AS advancer_pct
FROM (
    SELECT ticker, cp, cw, dv >= 5000000 AS liquid
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start < '2026-07-18 00:00:00') AS cp,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00') AS cw,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-20 13:30:00') AS dv
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-25 00:00:00'))
          AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
        GROUP BY ticker
        HAVING cp > 0 AND cw > 0
    )
)
Run am yourself

Across 6100 names wey clear the five-million-dollar regular-hours turnover bar, 2437 close above their July 17 close and 3630 close below, wey give us advancer share of 40%. The liquidity filter comot another 5099 names wey trade under that bar during the week. We count dem here instead of just throway dem.

Di sector scoreboard

Di eleven SPDR sector ETFs, from July 17 close go reach July 24, wey dem rank from best go worst.

QuerySector ETFs, full-week change: July 24 close vs July 17 close
sectorweek (%)points wey e dey behind best
Energy3.330
Utilities2.50.83
Industrials1.781.55
Materials1.471.86
Real Estate1.122.21
Health Care0.912.42
Technology0.183.15
Financials0.133.2
Staples-1.274.6
Communications-3.967.29
Consumer Discretionary-5.28.53
The exact SQL behind every number
SELECT sector, week_pct, round(max(week_pct) OVER () - week_pct, 2) AS points_behind_best
FROM (
    SELECT multiIf(ticker = 'XLK', 'Technology', ticker = 'XLC', 'Communications', ticker = 'XLE', 'Energy',
                   ticker = 'XLF', 'Financials', ticker = 'XLI', 'Industrials', ticker = 'XLB', 'Materials',
                   ticker = 'XLP', 'Staples', ticker = 'XLRE', 'Real Estate', ticker = 'XLU', 'Utilities',
                   ticker = 'XLV', 'Health Care', 'Consumer Discretionary') AS sector,
           round((cw / cp - 1) * 100, 2) AS week_pct
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start < '2026-07-18 00:00:00') AS cp,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00') AS cw
        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-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00'))
        GROUP BY ticker
        HAVING cp > 0 AND cw > 0
    )
)
ORDER BY week_pct DESC
Run am yourself

Energy stand for top of di board at 3.33%. Consumer Discretionary stand for bottom at -5.2%, 8.53 percentage points behind am. Dat gap na di sector dispersion for di week, and e dey important make person look am well: one week wey all eleven sector land within one point of each oda dey very different from one market wey di spread reach double digits.

Where the dollars go

QueryTop names by regular-hours dollar volume, full week July 20-24
tickerweek dollar (bn)leader (%)
MU158.1100
SPY133.984.7
QQQ101.564.2
NVDA93.959.4
SNDK81.451.5
TSLA79.150
AMD57.936.6
AAPL54.634.5
The exact SQL behind every number
SELECT ticker, week_dollar_bn, round(100 * week_dollar_bn / max(week_dollar_bn) OVER (), 1) AS pct_of_leader
FROM (
    SELECT ticker,
           round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 1) AS week_dollar_bn
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-24 20:00:00'
      AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker
    ORDER BY week_dollar_bn DESC
    LIMIT 8
)
ORDER BY week_dollar_bn DESC
Run am yourself

MU print 158.1 billion dollars of regular-hours turnover across the five sessions, e pass SPY wey get 133.9 billion and QQQ wey get 101.5 billion. Number eight for the board, AAPL, trade 34.5% of wetin the leader trade. Turnover dey show where the market spend the week dey argue, and e no mean say the market must gree with the price. The version of this measure for every single name na relative volume.

Di biggest movers for di week

Splits dey change di print but e no dey change di value: reverse split dey create fake four-digit gain, while forward split dey create fake collapse of di same size. Di week carry 26 reverse splits and 12 forward splits, and di two boards wey dey below exclude any name wey im split execute between di July 17 close and di July 24 close, wey be the exact interval wey we take measure di change. Di two boards also require five million dollars of regular-hours turnover.

QueryWeekly movers: ten biggest gainers and decliners, regular-hours closes, $5M+ traded, splits no dey inside
tickerboardweek (%)week dollar (m)days wey dem tradedollar max (%)
STAKgainers383.7251.6526
ADVBgainers277.1875.7590.3
WLDSgainers157.2104.6510.8
ZYBTgainers123.8294.6530.4
CJMBgainers111.3131.8513.6
LVWRgainers107.8131.6513.6
OMHgainers99.8436.6545
PNgainers97.589.759.3
UTZgainers95.4969.55100
GOROgainers92.350.355.2
LBGJdecliners-98.847.754.9
SXTCdecliners-97.440.654.2
WETOdecliners-86.48.850.9
GVHdecliners-78.817.251.8
VEEEdecliners-66.665.256.7
CLBKdecliners-53.5953.7598.4
BIYAdecliners-53.4266.9527.5
LESLdecliners-52.26.850.7
QMLSdecliners-48.737.253.8
VCIGdecliners-47.89.551
The exact SQL behind every number
SELECT ticker, board, week_pct, week_dollar_m, sessions_traded,
       round(100 * week_dollar_m / max(week_dollar_m) OVER (), 1) AS pct_of_dollar_max
FROM (
    SELECT 'gainers' AS board, ticker, round((cw / cp - 1) * 100, 1) AS week_pct,
           round(dv / 1e6, 1) AS week_dollar_m, sessions_traded
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start < '2026-07-18 00:00:00') AS cp,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00') AS cw,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-20 13:30:00') AS dv,
               uniqExactIf(toDate(toTimeZone(window_start, 'America/New_York')), window_start >= '2026-07-20 13:30:00') AS sessions_traded
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker NOT IN ('SPCX')
          AND ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits WHERE execution_date > '2026-07-17' AND execution_date <= '2026-07-24')
          AND ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-25 00:00:00'))
          AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
        GROUP BY ticker
        HAVING cp > 0 AND cw > 0 AND dv >= 5000000
    )
    ORDER BY week_pct DESC
    LIMIT 10
    UNION ALL
    SELECT 'decliners' AS board, ticker, round((cw / cp - 1) * 100, 1) AS week_pct,
           round(dv / 1e6, 1) AS week_dollar_m, sessions_traded
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start < '2026-07-18 00:00:00') AS cp,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00') AS cw,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-20 13:30:00') AS dv,
               uniqExactIf(toDate(toTimeZone(window_start, 'America/New_York')), window_start >= '2026-07-20 13:30:00') AS sessions_traded
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker NOT IN ('SPCX')
          AND ticker NOT IN (SELECT ticker FROM global_markets.stocks_splits WHERE execution_date > '2026-07-17' AND execution_date <= '2026-07-24')
          AND ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-25 00:00:00'))
          AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
        GROUP BY ticker
        HAVING cp > 0 AND cw > 0 AND dv >= 5000000
    )
    ORDER BY week_pct ASC
    LIMIT 10
)
ORDER BY board DESC, abs(week_pct) DESC
Run am yourself

To enter any of di boards, di move must be real. Di smallest gainer wey show rise 92.3%, and di smallest decliner print -47.8%. For di extremes, STAK move 383.7% on 251.6 million dollars traded, and LBGJ move -98.8% on 47.7 million. Dat decline dey close to the total quoted value of the name, so the board carry im own receipt: LBGJ print regular-hours bars on 5 of the five sessions, and no split execute against am between the two closes wey the board measure.

The quoted spread, session by session

Price na the main tin. The cost to finish one trade na the quoted spread, wey we measure for SPY one session at a time, straight from the raw NBBO tape instead of any summary.

QuerySPY median quoted spread and NBBO updates per session, regular hours, July 20-24
datemedian spread (bps)quote updates (m)one sided quote countcrossed quote count
2026-07-200.273.8901084
2026-07-210.272.290333
2026-07-220.272.510747
2026-07-230.275.105906
2026-07-240.274.402777
The exact SQL behind every number
SELECT toString(toDate(sip_timestamp)) AS date,
       round(quantileExactIf(0.5)(
           10000 * (toFloat64(ask_price) - toFloat64(bid_price)) / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2),
           bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price), 2) AS median_spread_bps,
       round(count() / 1e6, 2) AS quote_updates_m,
       countIf(bid_price <= 0 OR ask_price <= 0) AS one_sided_quote_count,
       countIf(bid_price > ask_price AND bid_price > 0 AND ask_price > 0) AS crossed_quote_count
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'SPY'
  AND sip_timestamp >= '2026-07-20 13:30:00'
  AND sip_timestamp < '2026-07-24 20:00:00'
  AND (toHour(sip_timestamp) * 60 + toMinute(sip_timestamp)) BETWEEN 810 AND 1199
GROUP BY toDate(sip_timestamp)
HAVING countIf(bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price) > 0
ORDER BY toDate(sip_timestamp)
Run am yourself

SPY median quoted spread measure 0.27 basis points of mid on Monday and 0.27 on Friday, base on 3.89 million and 4.4 million NBBO updates. The last two columns na the disclosure instead of the finding: 0 one-sided quotes and 1084 crossed quotes dem count out of Monday median instead of make dem just comot am quietly. One crossed quote, wey bid dey higher pass ask, na normal tin wey dey happen for consolidated feed wey dem join together from many venues for nanosecond resolution.

The options week afta monthly expiration

July monthly expiration bin happen for the Friday before this week start, so everi contract wey dey trade for these five sessions na survivor of that event. Expiration timing dey set the rhythm wey the same-day crowd dey follow trade.

QueryOptions contracts, same-day share, and call share per session, July 20-24
datecontracts (m)pct 0dtepct callpct expiring jul24
2026-07-206440.255.315.1
2026-07-2157.329.553.917
2026-07-2255.836.156.419.9
2026-07-2366.226.453.426.4
2026-07-2471.14953.549
The exact SQL behind every number
SELECT toString(toDate(sip_timestamp)) AS date,
       round(toFloat64(sum(size)) / 1e6, 1) AS contracts_m,
       round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = formatDateTime(toDate(sip_timestamp), '%y%m%d')) / sum(size), 1) AS pct_0dte,
       round(100.0 * sumIf(size, substring(ticker, length(ticker) - 8, 1) = 'C') / sum(size), 1) AS pct_call,
       round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260724') / sum(size), 1) AS pct_expiring_jul24
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-07-20 00:00:00' AND sip_timestamp < '2026-07-25 00:00:00'
GROUP BY toDate(sip_timestamp)
ORDER BY toDate(sip_timestamp)
Run am yourself

Contract volume bin reach 64 million for Monday and 71.1 million for Friday. The same-day share, wey mean contracts wey dey expire for the same session wey dem trade am, bin read 40.2% for Monday against 49% for Friday, wey be the expiry session for the week. Calls bin take 53.5% of Friday contract volume. And the pull of that Friday bin dey clear from the opening session: 15.1% of Monday volume don already dey inside contracts wey get expiry date for that day. Before expiry wey get that kain heavy open interest, some traders dey watch max pain, the strike price wey the expiring chain go pay holders the least amount, even though whether settlement go truly land near that price na question wey you suppose check instead of just assume.

Rates across the week

QueryTreasury curve per session, July 17 print reach July 24
dateyield 2y (%)yield 10y (%)yield 30y (%)spread 2s10s (bp)chg 10y from prior close (bp)
2026-07-174.184.555.06370
2026-07-204.214.65.11395
2026-07-214.264.635.13378
2026-07-224.314.675.153612
2026-07-234.374.715.173416
2026-07-244.334.695.163614
The exact SQL behind every number
SELECT toString(date) AS date,
       round(toFloat64(yield_2_year), 2) AS yield_2y_pct,
       round(toFloat64(yield_10_year), 2) AS yield_10y_pct,
       round(toFloat64(yield_30_year), 2) AS yield_30y_pct,
       round((toFloat64(yield_10_year) - toFloat64(yield_2_year)) * 100) AS spread_2s10s_bp,
       round((toFloat64(yield_10_year) - (SELECT toFloat64(any(yield_10_year)) FROM global_markets.treasury_yields WHERE date = '2026-07-17')) * 100) AS chg_10y_from_prior_close_bp
FROM global_markets.treasury_yields
WHERE date >= '2026-07-17' AND date <= '2026-07-24'
ORDER BY date
Run am yourself

If we measure from the July 17 print, the ten-year move na 14 basis points to reach 4.69% for the last print wey dey file, while the two-year dey at 4.33% and the thirty-year dey at 5.16%. The two-to-ten-year spread finish the series at 36 basis points. Treasury file dey run roughly one session behind the tape, so this panel carry 6 prints, and we put the date for each one inside the table.

The shorts: the daily files

FINRA dey publish daily short-sale volume file. Short volume na gross daily flow, e no be position. Sometimes these files dey come truncated, so we must measure coverage before we quote any ratio from dem.

QueryDaily short-volume file coverage: tickers wey dey file and short shares, July 20-24
datetickers wey dey fileshort shares (bn)pct of fullest file
2026-07-20150984.71100
2026-07-21151025.28100
2026-07-22149844.5999.2
2026-07-2348161.7431.9
2026-07-24150624.2799.7
The exact SQL behind every number
SELECT date, tickers_on_file, short_shares_bn,
       round(100.0 * tickers_on_file / max(tickers_on_file) OVER (), 1) AS pct_of_fullest_file
FROM (
    SELECT toString(date) AS date,
           uniqExact(ticker) AS tickers_on_file,
           round(sum(short_shares) / 1e9, 2) AS short_shares_bn
    FROM (
        SELECT date, ticker, max(short_volume) AS short_shares
        FROM global_markets.stocks_short_volume
        WHERE date >= '2026-07-20' AND date <= '2026-07-24'
        GROUP BY date, ticker
    )
    GROUP BY date
)
ORDER BY date
Run am yourself

5 daily files dey on hand for the week. The first one get 15098 tickers and 4.71 billion short-marked shares; the last one get 15062 tickers, or 99.7% of the fullest file's ticker count. Any short-volume claim for one name wey come from file wey dey far below im neighbors no fit verify until dem refile that file.

The calendar wey dey behind the week

QuerySEC filings per session and form type, July 20-24
datefilingsform4form8kf424b2
2026-07-203013632166663
2026-07-2132755032501083
2026-07-223461549279569
2026-07-233551545369626
2026-07-243844644223623
The exact SQL behind every number
SELECT toString(filing_date) AS date,
       count() AS filings,
       countIf(form_type = '4') AS form4,
       countIf(form_type = '8-K') AS form8k,
       countIf(form_type = '424B2') AS f424b2
FROM global_markets.stocks_sec_edgar_index
WHERE filing_date >= '2026-07-20' AND filing_date <= '2026-07-24'
GROUP BY filing_date
ORDER BY date
Run am yourself

The first session wey dey on file get 3013 filings, 632 of dem na insider Form 4 reports and 166 of dem na 8-Ks. The last one get 3844, with 644 Form 4s and 223 8-Ks. 5 of the sessions for the week get EDGAR daily index on file; that index dey follow im own schedule, wey sometimes dey trail the tape.

QueryCorporate calendar for di week: dividends, splits, listings, and news
filings for weekdays wey filing don deyex dividends for weekhousehold ex dividends for weekreverse splits for weekforward splits for weeklistings for weeknews for weeknews publishers for week
1714455941261248522
The exact SQL behind every number
SELECT
    (SELECT count() FROM global_markets.stocks_sec_edgar_index WHERE filing_date >= '2026-07-20' AND filing_date <= '2026-07-24') AS filings_week,
    (SELECT uniqExact(filing_date) FROM global_markets.stocks_sec_edgar_index WHERE filing_date >= '2026-07-20' AND filing_date <= '2026-07-24') AS filing_days_on_file,
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= '2026-07-20' AND ex_dividend_date <= '2026-07-24') AS ex_dividends_week,
    (SELECT countIf(ticker IN ('AAPL', 'MSFT', 'JPM', 'KO', 'JNJ', 'XOM', 'CVX', 'PG', 'WMT', 'HD')) FROM global_markets.stocks_dividends WHERE ex_dividend_date >= '2026-07-20' AND ex_dividend_date <= '2026-07-24') AS household_ex_dividends_week,
    (SELECT countIf(toFloat64(split_from) > toFloat64(split_to)) FROM global_markets.stocks_splits WHERE execution_date >= '2026-07-20' AND execution_date <= '2026-07-24') AS reverse_splits_week,
    (SELECT countIf(toFloat64(split_to) > toFloat64(split_from)) FROM global_markets.stocks_splits WHERE execution_date >= '2026-07-20' AND execution_date <= '2026-07-24') AS forward_splits_week,
    (SELECT count() FROM global_markets.stocks_ipos WHERE listing_date >= '2026-07-20' AND listing_date <= '2026-07-24') AS listings_week,
    (SELECT count() FROM global_markets.stocks_news WHERE published_utc >= '2026-07-20 04:00:00' AND published_utc < '2026-07-25 04:00:00') AS news_week,
    (SELECT uniqExact(JSONExtractString(publisher, 'name')) FROM global_markets.stocks_news WHERE published_utc >= '2026-07-20 04:00:00' AND published_utc < '2026-07-25 04:00:00') AS news_publishers_week
Run am yourself

The remaining paperwork for the week: 17144 SEC filings across 5 indexed days, 594 ex-dividend records, 1 of dem come from the ten household names wey this panel dey check, 26 reverse and 12 forward splits, 4 new listings, and 852 articles from 2 publishers. That last pair dey measure the attention of one feed, e no be the whole world media.

The sessions, wey dem verify

QuerySession verification: sessions, bars, holiday rows, up and down closes, plus next closure
sessions wey dey weekfirst sessionlast sessionregular bars for weekholiday rows for weekup sessionsdown sessionsnext closure datenext closure name
52026-07-202026-07-2419500232026-09-07Labor Day
The exact SQL behind every number
WITH spy AS (
    SELECT d, c, lagInFrame(c) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS p
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
               argMax(toFloat64(close), window_start) AS c
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY'
          AND ((window_start >= '2026-07-17 13:30:00' AND window_start < '2026-07-17 20:00:00')
            OR (window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-24 20:00:00'))
          AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
        GROUP BY d
    )
)
SELECT
    uniqExact(toDate(toTimeZone(window_start, 'America/New_York'))) AS sessions_in_week,
    toString(min(toDate(toTimeZone(window_start, 'America/New_York')))) AS first_session,
    toString(max(toDate(toTimeZone(window_start, 'America/New_York')))) AS last_session,
    count() AS regular_bars_in_week,
    (SELECT count() FROM global_markets.stocks_market_holidays WHERE date >= '2026-07-20' AND date <= '2026-07-24') AS holiday_rows_in_week,
    (SELECT countIf(c > p) FROM spy WHERE d >= '2026-07-20') AS up_sessions,
    (SELECT countIf(c < p) FROM spy WHERE d >= '2026-07-20') AS down_sessions,
    (SELECT toString(min(date)) FROM global_markets.stocks_market_holidays WHERE date > '2026-07-24' AND date <= '2026-12-31' AND status = 'closed') AS next_closure_date,
    (SELECT argMin(name, date) FROM global_markets.stocks_market_holidays WHERE date > '2026-07-24' AND date <= '2026-12-31' AND status = 'closed') AS next_closure_name
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
  AND window_start >= '2026-07-20 13:30:00' AND window_start < '2026-07-24 20:00:00'
  AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
Run am yourself

5 sessions, from 2026-07-20 go reach 2026-07-24, with 0 holiday rows inside the window. SPY print 1950 regular-session minute bars across dem. 2 sessions close above the prior close and 3 close below. The next scheduled closure na Labor Day for 2026-09-07.

Wetin dey come

Next week, check our tables for the details:

QueryNext week calendar: closures, ex-dividends, splits, and expiry pull
closures for next weekex dividends wey go show next weekhousehold ex div wey go show next weeksplits wey go show next weekjul31 expiry % of friday volumelatest short interest settlement wey dem do
093402614.22026-07-15
The exact SQL behind every number
SELECT
    (SELECT count() FROM global_markets.stocks_market_holidays WHERE date >= '2026-07-27' AND date <= '2026-07-31' AND status != 'open') AS closures_next_week,
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= '2026-07-27' AND ex_dividend_date <= '2026-07-31') AS ex_dividends_next_week,
    (SELECT countIf(ticker IN ('AAPL', 'MSFT', 'JPM', 'KO', 'JNJ', 'XOM', 'CVX', 'PG', 'WMT', 'HD')) FROM global_markets.stocks_dividends WHERE ex_dividend_date >= '2026-07-27' AND ex_dividend_date <= '2026-07-31') AS household_ex_div_next_week,
    (SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= '2026-07-27' AND execution_date <= '2026-07-31') AS splits_next_week,
    (SELECT round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260731') / sum(size), 1) FROM global_markets.options_trades WHERE sip_timestamp >= '2026-07-24 00:00:00' AND sip_timestamp < '2026-07-25 00:00:00') AS jul31_expiry_pct_of_friday_volume,
    (SELECT toString(max(settlement_date)) FROM global_markets.stocks_short_interest WHERE settlement_date <= '2026-07-24') AS latest_short_interest_settlement
Run am yourself

The holiday table show 0 closures for the next week. 934 ex-dividend records dey inside, 0 from the household set, join with 26 scheduled splits. For Friday options volume, 14.2% don already dey inside contracts wey go expire the next Friday. The last short-interest settlement date wey we get na 2026-07-15, one file wey dey publish with delay wey long reach to get its own explainer.

FAQ

How the stock market perform for the week of July 20, 2026?

SPY change -0.59% close over close from July 17 go July 24, with QQQ for -1.59%, DIA for -0.38%, and IWM for -0.98%. Among liquid names, 2437 rise and 3630 fall.

Which sector lead for the week of July 20, 2026?

Energy, at 3.33%. The weakest of the eleven SPDR sector ETFs na Consumer Discretionary at -5.2%, 8.53 percentage points behind.

How many trading sessions dey for the week of July 20, 2026?

5, wey run from 2026-07-20 go 2026-07-24, with 0 holiday rows inside the window. The next scheduled closure na Labor Day.

Which ticker trade the most dollars for the week of July 20, 2026?

MU, at 158.1 billion dollars of regular-hours turnover, ahead of SPY at 133.9 billion.

Data notes

All stored timestamps na UTC; regular hours na 13:30-20:00 UTC per session, and week boundaries start from July 17 regular close go reach July 24. Every close-over-close panel for here dey read the last regular-hours minute bar for each side of the comparison, so extended-hours print no fit set weekly close. The trailing-year rank dey use open-to-close weekly returns, so e no go match the close-over-close scoreboard; we label both definitions where dem dey appear. Weekly breadth and the mover boards dey apply five-million-dollar regular-hours turnover filter, and breadth dey publish the count of names wey that filter comot. Mover boards no dey include any name wey e split execute after July 17 close and reach July 24, the exact interval wey dem dey measure the change, wey dey catch split wey dem stamp for the weekend or session; dem no dey exclude leveraged and inverse ETFs, wey fit dominate board for directional week. The bottom of the decliner board fit sit close to total loss of quoted value for the week, and that board dey publish how many of the five sessions each name print inside. The SPY spread panel dey count one-sided and crossed quotes instead of just comot dem, and the median na wetin dem take from the remaining valid quotes. Treasury file dey run about one session behind the tape and the EDGAR daily index dey land on im own schedule, so the rates and filings panels dey report how many days dem actually hold. No implied-volatility index dey here: those series no get license for this warehouse, so volatility na from the tape we dey read am through ranges, same-day options share, and quote behavior.

Metodoloji

  • Market data source: consolidated tape. delayed_stocks_minute_aggs for prices and volumes, cache_stocks_quotes for the NBBO panel, options_trades for the options week.
  • Close: the last regular-session minute bar of the session, no be assumed 16:00 print and no be extended-hours print.
  • Sessions: we verify am from the holiday table plus observed bars, we no dey assume am from the calendar.
  • Time zone handling: WHERE clauses dey use raw UTC literals, and toTimeZone dey appear only for SELECT lists for ET labels.
  • Decimals: we dey cast price, size, and volume columns to Float64 before any division or product.
  • Deterministic aggregates: exact quantiles throughout, and every ordering or sign claim wey dey the prose, we encode am as a sanity bound.
  • Warehouse as-of date: July 26, 2026.

Cross-links: the previous edition of this weekly series, what a bid-ask spread is, when options expire, short interest versus short volume, and the two-to-ten-year spread.

Every query wey dey up so dey run unchanged for the Strasmore terminal if you want re-point a window to a different week.

#recap#weekly#spy#sectors#options#market structure