Strasmore Research
Market Recap Matt ConnorBy Matt Connor

Market Recap: July 27, 2026, The Day in Numbers

July 27, 2026, measured from the tape: scoreboard, breadth, sector spread, options flow, the quote tape, rates and the calendar, every figure query-backed.

This market recap for Monday, July 27, 2026 reads the whole session from stored queries: SPY's change over Friday's close came to 0.02%, the liquid tape's advancer share to 65.4%, and the options tape printed 64.69 million contracts. Every window below is pinned to explicit dates on both ends, so re-running any panel's SQL returns these same figures.

The scoreboard

Every change compares July 27's last regular-session minute bar with Friday July 24's, consecutive trading sessions separated by a weekend. Rows are alphabetical, so each ETF keeps a fixed position.

QuerySPY / QQQ / DIA / IWM: July 27 vs the July 24 close, regular hours
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-07-24 13:30:00' AND window_start < '2026-07-24 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-07-27 13:30:00' AND window_start < '2026-07-27 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_open) / toFloat64(p.prior_close) - 1) * 100, 2) AS gap_pct,
    round((toFloat64(s.day_close) / toFloat64(s.day_open) - 1) * 100, 2) AS intraday_pct,
    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
FROM sess s LEFT JOIN prior p ON s.ticker = p.ticker
ORDER BY ticker
Run this yourself

DIA moved 0.49%, IWM 0.59%, QQQ -0.32%, and SPY 0.02% to a $739.02 close. Each row splits the move into its two legs: SPY opened 0.82% from Friday's close, a gap that carries the whole weekend, and moved -0.79% open to close. On a Monday the overnight leg is really a two-day leg, and the split between it and the intraday leg is the session's first fingerprint.

Was the day unusual?

One session's number means little without the distribution behind it, so the day is ranked inside its own trailing month on identical logic.

QuerySPY day move in trailing context (open-to-close, June 26 through July 27)
The exact SQL behind every number
SELECT
    round(anyIf(oc_pct, d = toDate('2026-07-27')), 2) AS spy_open_to_close_pct,
    arrayCount(x -> x > abs(anyIf(oc_pct, d = toDate('2026-07-27'))), groupArrayIf(abs(oc_pct), d != toDate('2026-07-27'))) + 1 AS spy_abs_move_rank,
    count() AS spy_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-26 13:30:00')
      AND window_start < toDateTime('2026-07-28 00:00:00')
      AND (toHour(window_start) * 60 + toMinute(window_start)) BETWEEN 810 AND 1199
    GROUP BY d
)
Run this yourself

SPY's open-to-close move of -0.79% ranked 1 of 21 trailing sessions by absolute size, in a window reaching back to 2026-06-26. The rank counts how many other sessions in the window moved more, plus one, so first place would be the biggest move of the trailing month.

Breadth

An index level is one number. Breadth counts how many stocks travelled with it across the weekend gap.

QueryLiquid-tape breadth: July 27 close vs July 24 close, $1M-traded filter
The exact SQL behind every number
SELECT
    countIf(c27 > c24 AND liquid) AS advancers,
    countIf(c27 < c24 AND liquid) AS decliners,
    countIf(c27 = c24 AND liquid) AS unchanged,
    countIf(liquid) AS liquid_tickers,
    countIf(NOT liquid) AS dropped_by_liquidity_filter,
    round(100.0 * countIf(c27 > c24 AND liquid) / countIf(liquid), 1) AS advancer_pct
FROM (
    SELECT ticker, c24, c27, dv27 >= 1000000 AS liquid
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00') AS c24,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00') AS c27,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-27 13:30:00') AS dv27
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-27 20:00:00'
        GROUP BY ticker
        HAVING c24 > 0 AND c27 > 0
    )
)
Run this yourself

Across 5935 names clearing a one-million-dollar regular-hours turnover bar, 3880 closed above Friday's close and 1972 closed below, an advancer share of 65.4%. The filter set aside 5336 thinner names, counted here rather than quietly discarded.

The mega-cap shelf

The same eight mega-cap names appear here every session, alphabetical so each keeps its row. A fixed basket is the point: the reader learns the rows, and no editorial hand picks winners after the fact.

QueryEight mega-caps: change vs July 24 and regular-hours dollars, July 27
The exact SQL behind every number
WITH per_name AS (
    SELECT
        ticker,
        toFloat64(argMaxIf(close, window_start, window_start < '2026-07-27 00:00:00')) AS prior_close,
        toFloat64(argMaxIf(close, window_start, window_start >= '2026-07-27 00:00:00')) AS day_close,
        round(sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-27 00:00:00') / 1e9, 2) AS day_dollar_bn
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL', 'AMZN', 'AVGO', 'GOOGL', 'META', 'MSFT', 'NVDA', 'TSLA')
      AND ((window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00')
        OR (window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 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,
    day_dollar_bn
FROM per_name
ORDER BY ticker
Run this yourself

AAPL moved 1.16%, META -0.21%, MSFT 1.94%, and NVDA -5.04% on 25.42 billion dollars of regular-hours turnover, with TSLA at -1.2%. The dollar column shows how much of the tape these eight names carry on their own; the breadth panel above is the check on how far the rest of the market travelled with them.

The day's movers

Both boards require five million dollars of regular-hours turnover, exclude any name whose split executed between the two closes they measure, and exclude one reused symbol under the house ambiguity guard described in the notes.

QueryBiggest gainers and decliners: July 27 close vs July 24 close, $5M+ traded, splits excluded
The exact SQL behind every number
SELECT ticker, board, day_pct, day_dollar_m
FROM (
    SELECT 'gainers' AS board, ticker, round((c27 / c24 - 1) * 100, 1) AS day_pct, round(dv / 1e6, 1) AS day_dollar_m
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00') AS c24,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00') AS c27,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-27 13:30:00') AS dv
        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-24' AND execution_date <= '2026-07-27')
          AND window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-27 20:00:00'
        GROUP BY ticker
        HAVING c24 > 0 AND c27 > 0 AND dv >= 5000000
    )
    ORDER BY day_pct DESC
    LIMIT 8
    UNION ALL
    SELECT 'decliners' AS board, ticker, round((c27 / c24 - 1) * 100, 1) AS day_pct, round(dv / 1e6, 1) AS day_dollar_m
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-24 20:00:00') AS c24,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00') AS c27,
               sumIf(toFloat64(close) * toFloat64(volume), window_start >= '2026-07-27 13:30:00') AS dv
        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-24' AND execution_date <= '2026-07-27')
          AND window_start >= '2026-07-24 13:30:00' AND window_start < '2026-07-27 20:00:00'
        GROUP BY ticker
        HAVING c24 > 0 AND c27 > 0 AND dv >= 5000000
    )
    ORDER BY day_pct ASC
    LIMIT 8
)
ORDER BY board DESC, abs(day_pct) DESC
Run this yourself

The top gainer on the board, DFNS, moved 214.9% on 486.4 million dollars traded. The steepest decliner, MPLT, printed -72.9% on 83.3 million. This page records the sizes and the receipts; it attaches no story to them.

Sector dispersion

The eleven SPDR select-sector funds, July 27's close over July 24's, ranked best to worst. The basket is declared and fixed, not a vendor classification.

QuerySector ETFs, July 27 close vs July 24 close, ranked
The exact SQL behind every number
SELECT sector, day_pct, round(max(day_pct) OVER () - day_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((c27 / c24 - 1) * 100, 2) AS day_pct
    FROM (
        SELECT ticker,
               argMaxIf(toFloat64(close), window_start, window_start < '2026-07-27 00:00:00') AS c24,
               argMaxIf(toFloat64(close), window_start, window_start >= '2026-07-27 00:00:00') AS c27
        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-24 13:30:00' AND window_start < '2026-07-24 20:00:00')
            OR (window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00'))
        GROUP BY ticker
        HAVING c24 > 0 AND c27 > 0
    )
)
ORDER BY day_pct DESC
Run this yourself

Staples topped the board at 1.5%, and Energy sat at the bottom at -2.06%, 3.56 percentage points behind. That spread is the day's sector dispersion: a tape where all eleven land within a point reads very differently from one stretched across several.

Where the dollars traded

QueryTop 6 by dollars traded, top 4 by shares traded: July 27 regular hours
The exact SQL behind every number
SELECT leaderboard, ticker, dollar_volume_bn, shares_m,
    round(1000 * dollar_volume_bn / shares_m, 2) AS implied_avg_price
FROM (
    SELECT
        'by dollars traded' AS leaderboard,
        ticker,
        round(sum(toFloat64(close) * toFloat64(volume)) / 1e9, 2) AS dollar_volume_bn,
        round(sum(toFloat64(volume)) / 1e6, 1) AS shares_m
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 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(volume)) / 1e6, 1) AS shares_m
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00'
      AND ticker NOT IN ('SPCX')
    GROUP BY ticker
    ORDER BY shares_m DESC
    LIMIT 4
)
ORDER BY leaderboard, if(leaderboard = 'by shares traded', shares_m, dollar_volume_bn) DESC
Run this yourself

MU led the dollar board at 35.71 billion of regular-hours turnover, with SPY at 27.03 billion behind it. The share board answers a different question: KIDZ topped it at 198.3 million shares with an implied average price of $0.66. Dollar volume finds the market's attention, share volume finds its churn, and the per-name version of this measure is relative volume.

The options tape

QueryOptions tape: contracts, call share, same-day share vs Friday, busiest SPY contract
The exact SQL behind every number
WITH
    (
        SELECT (strike, typ, vol_m, is_0dte)
        FROM (
            SELECT toFloat64(any(strike_price)) AS strike, any(option_type) AS typ,
                   round(toFloat64(sum(size)) / 1e6, 2) AS vol_m,
                   if(substring(ticker, length(ticker) - 14, 6) = '260727', 1, 0) AS is_0dte
            FROM global_markets.options_trades
            WHERE sip_timestamp >= '2026-07-27 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00'
              AND underlying_symbol = 'SPY'
            GROUP BY ticker
            ORDER BY vol_m DESC, strike ASC
            LIMIT 1
        )
    ) AS top_spy,
    (
        SELECT round(toFloat64(argMax(close, window_start)), 2)
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'SPY' AND window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00'
    ) AS spy_regular_close,
    (
        SELECT round(toFloat64(sum(size)) / 1e6, 2)
        FROM global_markets.options_trades
        WHERE sip_timestamp >= '2026-07-24 00:00:00' AND sip_timestamp < '2026-07-25 00:00:00'
    ) AS jul24_contracts_m,
    (
        SELECT round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260724') / 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 jul24_pct_0dte
SELECT
    round(count() / 1e6, 2) AS option_prints_m,
    round(toFloat64(sum(size)) / 1e6, 2) AS contracts_m,
    jul24_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) = '260727') / sum(size), 1) AS pct_0dte,
    jul24_pct_0dte,
    spy_regular_close,
    top_spy.1 AS top_spy_strike,
    top_spy.2 AS top_spy_type,
    top_spy.3 AS top_spy_contracts_m,
    top_spy.4 AS top_spy_is_0dte,
    round(top_spy.1 - spy_regular_close, 2) AS top_spy_strike_minus_close
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-07-27 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00'
Run this yourself

The options tape printed 11.07 million trades for 64.69 million contracts, beside Friday's 71.14 million. Calls took 55.1% of contract volume. Contracts expiring the same session, the zero-days-to-expiry crowd, took 39.3% against Friday's 49%, a rhythm set by expiration timing. The busiest SPY contract was the 740 C at 0.59 million contracts, its strike sitting 0.98 dollars from SPY's $739.02 regular close, measured strike minus close.

The quote tape

The quote data is this desk's scarcest dataset, and it is measured every session. Ordinary days go on the record too.

QueryStocks NBBO update count: July 27 vs July 24, with named-ticker updates (millions)
The exact SQL behind every number
SELECT
    round(countIf(toDate(sip_timestamp) = toDate('2026-07-27')) / 1e6, 2) AS jul27_updates_m,
    round(countIf(toDate(sip_timestamp) = toDate('2026-07-24')) / 1e6, 2) AS jul24_updates_m,
    round((countIf(toDate(sip_timestamp) = toDate('2026-07-27')) / countIf(toDate(sip_timestamp) = toDate('2026-07-24')) - 1) * 100, 1) AS session_over_session_pct,
    round(countIf(toDate(sip_timestamp) = toDate('2026-07-27') AND ticker = 'SPY') / 1e6, 2) AS jul27_spy_updates_m,
    round(countIf(toDate(sip_timestamp) = toDate('2026-07-27') AND ticker = 'QQQ') / 1e6, 2) AS jul27_qqq_updates_m,
    round(countIf(toDate(sip_timestamp) = toDate('2026-07-27') AND ticker = 'NVDA') / 1e6, 2) AS jul27_nvda_updates_m
FROM global_markets.cache_stocks_quotes
WHERE sip_timestamp >= '2026-07-24 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00'
Run this yourself

The stock-quote tape carried 553.53 million NBBO updates against 500.88 million on Friday, a session-over-session change of 10.5%. SPY logged 4.84 million updates, QQQ 6.78 million, NVDA 2.93 million.

QuerySeven names: RTH median quoted spread in basis points, with quote-quality counts, July 27
The exact SQL behind every number
SELECT ticker,
       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 IN ('AAPL', 'DIA', 'IWM', 'NVDA', 'QQQ', 'SPY', 'TSLA')
  AND sip_timestamp >= '2026-07-27 13:30:00' AND sip_timestamp < '2026-07-27 20:00:00'
GROUP BY ticker
HAVING countIf(bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price) > 0
ORDER BY ticker
Run this yourself

SPY's regular-hours median quoted spread measured 0.27 basis points of mid, QQQ's 0.59 and NVDA's 1.02. The last two columns are the disclosure: one-sided and crossed quotes are counted per name and set aside from the median rather than silently dropped. A crossed quote, bid above ask, is an ordinary artifact of a consolidated feed stitched from many venues at nanosecond resolution.

QuerySPY's median spread ranked against every July session through the 27th, tightest first
The exact SQL behind every number
SELECT round(anyIf(spread_bps, d = toDate('2026-07-27')), 2) AS jul27_median_spread_bps,
       arrayCount(x -> x < anyIf(spread_bps, d = toDate('2026-07-27')), groupArrayIf(spread_bps, d != toDate('2026-07-27'))) + 1 AS rank_tightest,
       count() AS sessions_compared,
       toString(min(d)) AS first_session
FROM (
    SELECT toDate(sip_timestamp) AS d,
           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) AS spread_bps
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'SPY'
      AND sip_timestamp >= '2026-07-01 13:30:00' AND sip_timestamp < '2026-07-27 20:00:00'
      AND (toHour(sip_timestamp) * 60 + toMinute(sip_timestamp)) BETWEEN 810 AND 1199
    GROUP BY d
    HAVING countIf(bid_price > 0 AND ask_price > 0 AND ask_price >= bid_price) > 0
)
Run this yourself

Ranked against every July session on identical logic, the day's SPY median spread of 0.27 basis points came in 18 of 18, counted from the tightest, in a window starting 2026-07-01. On a quiet tape that sentence is the point of the panel: an ordinary day for liquidity is a finding, published and bounded.

QueryOptions NBBO tape: total updates vs the stock tape, plus the SPY root slice, July 27
The exact SQL behind every number
WITH
    (SELECT count() FROM global_markets.cache_options_quotes WHERE sip_timestamp >= '2026-07-27 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00') AS jul27_options_rows,
    (SELECT count() FROM global_markets.cache_stocks_quotes WHERE sip_timestamp >= '2026-07-27 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00') AS jul27_stock_quote_rows
SELECT
    round(jul27_options_rows / 1e9, 2) AS jul27_options_bn,
    round(jul27_options_rows / jul27_stock_quote_rows, 1) AS options_to_stock_ratio,
    round((SELECT count() FROM global_markets.cache_options_quotes WHERE ticker >= 'O:SPY26' AND ticker < 'O:SPY27' AND sip_timestamp >= '2026-07-27 13:30:00' AND sip_timestamp < '2026-07-27 20:00:00') / 1e6, 0) AS jul27_spy_options_m
Run this yourself

The options NBBO tape ran 10.38 billion updates, 18.8 times the stock quote tape, with the SPY root alone at 440 million regular-hours updates.

Rates

QueryTreasury curve prints on file, July 22 through July 27
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
FROM global_markets.treasury_yields
WHERE date >= '2026-07-22' AND date <= '2026-07-27'
ORDER BY date
Run this yourself

Treasury's file runs about a session behind the tape, so this panel reports the prints it holds: 4 dated rows in the July 22 through July 27 window. The latest, dated 2026-07-27, put the two-year at 4.31%, the ten-year at 4.65% and the thirty-year at 5.12%, a two-to-ten-year spread of 34 basis points.

The calendar behind the day

QueryEx-dividends, splits, listings, news, and the July 27 SEC filing mix
The exact SQL behind every number
WITH
    (
        SELECT (argMax(t, (n, t)), max(n))
        FROM (
            SELECT t, count() AS n
            FROM (
                SELECT arrayJoin(tickers) AS t
                FROM global_markets.stocks_news
                WHERE published_utc >= '2026-07-27 04:00:00' AND published_utc < '2026-07-28 04:00:00'
            )
            WHERE t != 'SPCX'
            GROUP BY t
        )
    ) AS top_news,
    (
        SELECT (count(), uniqExact(cik), countIf(form_type = '4'), countIf(form_type = '8-K'), countIf(form_type = '424B2'), countIf(form_type = '10-Q'))
        FROM global_markets.stocks_sec_edgar_index
        WHERE filing_date = '2026-07-27'
    ) AS fil
SELECT
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date = '2026-07-27') AS ex_dividend_records,
    (SELECT countIf(toFloat64(split_from) > toFloat64(split_to)) FROM global_markets.stocks_splits WHERE execution_date = '2026-07-27') AS reverse_splits,
    (SELECT countIf(toFloat64(split_to) > toFloat64(split_from)) FROM global_markets.stocks_splits WHERE execution_date = '2026-07-27') AS forward_splits,
    (SELECT count() FROM global_markets.stocks_ipos WHERE listing_date = '2026-07-27') AS listings,
    (SELECT count() FROM global_markets.stocks_news WHERE published_utc >= '2026-07-27 04:00:00' AND published_utc < '2026-07-28 04:00:00') AS news_articles,
    (SELECT uniqExact(JSONExtractString(publisher, 'name')) FROM global_markets.stocks_news WHERE published_utc >= '2026-07-27 04:00:00' AND published_utc < '2026-07-28 04:00:00') AS news_publishers,
    top_news.1 AS top_news_ticker,
    top_news.2 AS top_news_n,
    fil.1 AS fil_total,
    fil.2 AS fil_filers,
    fil.3 AS fil_form4,
    fil.4 AS fil_8k,
    fil.5 AS fil_424b2,
    fil.6 AS fil_10q
Run this yourself

91 dividend records went ex-dividend on July 27, 7 reverse and 1 forward splits executed, and 0 new listings hit the tape. The news feed carried 166 articles from 2 publishers, with MSFT the most-covered ticker in this one feed's window at 12 articles. The EDGAR daily index holds 3997 filings for the date from 2163 distinct filers: 587 insider Form 4 reports, 226 8-K current reports, 555 424B2 pricing supplements and 23 10-Q quarterly reports. That index lands on its own schedule, and this panel reports whatever it holds at generation time.

On deck

The rest of the week, Tuesday July 28 through Friday July 31, read from the same tables and deliberately looking past the period.

QueryJuly 28 through 31 on the calendar: closures, ex-dividends, splits, the Friday expiry, and the short-interest lag
The exact SQL behind every number
SELECT
    (SELECT count() FROM global_markets.stocks_market_holidays WHERE date >= '2026-07-28' AND date <= '2026-07-31' AND status != 'open') AS closures_rest_of_week,
    (SELECT count() FROM global_markets.stocks_dividends WHERE ex_dividend_date >= '2026-07-28' AND ex_dividend_date <= '2026-07-31') AS exdiv_records_rest_of_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-28' AND ex_dividend_date <= '2026-07-31') AS household_exdivs,
    (SELECT count() FROM global_markets.stocks_splits WHERE execution_date >= '2026-07-28' AND execution_date <= '2026-07-31') AS splits_rest_of_week,
    round(100.0 * sumIf(size, substring(ticker, length(ticker) - 14, 6) = '260731') / sum(size), 1) AS jul31_expiry_pct_of_mon_volume,
    (SELECT toString(max(settlement_date)) FROM global_markets.stocks_short_interest WHERE settlement_date <= '2026-07-27') AS latest_short_interest_settlement
FROM global_markets.options_trades
WHERE sip_timestamp >= '2026-07-27 00:00:00' AND sip_timestamp < '2026-07-28 00:00:00'
Run this yourself

The holiday table shows 0 closures across the four remaining sessions of the week. 843 dividend records go ex-dividend across those sessions, 0 of them among ten checked household names, and 18 splits are scheduled to execute. Of Monday's option volume, 17.1% already sat in contracts dated to expire Friday, July 31. The newest short-interest settlement on file is 2026-07-15, a file that publishes on a lag long enough to have its own explainer.

The session, verified

QuerySession verification: first/last SPY bar ET, regular-bar count, holiday receipts, next closure
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,
    countIf(window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00') AS regular_session_bars,
    uniqExactIf(toDate(toTimeZone(window_start, 'America/New_York')), window_start >= '2026-07-27 13:30:00' AND window_start < '2026-07-27 20:00:00') AS day_sessions,
    (SELECT count() FROM global_markets.stocks_market_holidays WHERE date = '2026-07-27') AS jul27_holiday_rows,
    (SELECT toString(min(date)) FROM global_markets.stocks_market_holidays WHERE date > '2026-07-27' 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-27' 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-27 00:00:00' AND window_start < '2026-07-28 00:00:00'
Run this yourself

A full regular session: first SPY bar 04:00 ET, last 19:59 ET, 390 regular-hours bars, 1 session in the window, and 0 holiday rows for the date. The next scheduled closure is Labor Day on 2026-09-07.

FAQ

How did the stock market do on Monday, July 27, 2026?

SPY changed 0.02% from Friday's close to $739.02, with QQQ at -0.32%, DIA at 0.49% and IWM at 0.59%. Among liquid names, 3880 rose and 1972 fell.

Which sector topped the board on July 27, 2026?

Staples, at 1.5%, measured across the eleven SPDR select-sector funds. The weakest of the eleven, Energy, printed -2.06%.

How busy was the options market on July 27, 2026?

64.69 million contracts traded, beside 71.14 million the prior session. Same-day contracts took 39.3% of volume and calls took 55.1%.

Which stock traded the most dollars on July 27, 2026?

MU, at 35.71 billion of regular-hours dollar volume, ahead of SPY at 27.03 billion.

Data notes

This edition backfills a Monday session in the resumed daily series, published August 1. The daily before it by session date is July 10, 2026, the July 29 edition covers the Wednesday of this same week, and the weekly recap carries the week ending Friday, July 24, the session every comparison on this page rests on. Named per-ticker panels are ordered alphabetically so prose references point at fixed rows; leaderboards and mover boards are value-ordered, and every positional claim they carry is encoded as a sanity bound. The mega-cap basket and the eleven-fund sector basket are declared, fixed sets, not vendor classifications. The mover boards apply a five-million-dollar regular-hours turnover bar, exclude any name whose split executed between the two closes they measure, and exclude one reused symbol under the house ambiguity guard, so a callout always falls through to a verifiable name. Every close-over-close figure here spans the weekend, Friday July 24 to Monday July 27, and the scoreboard's gap column carries that whole span. The quote panels count one-sided and crossed quotes per name instead of dropping them silently. Treasury's file and the EDGAR daily index land on their own schedules, so those panels report what they hold rather than assuming arrival. No implied-volatility index appears here: those series are not licensed into this warehouse, so volatility is read off the tape through ranges, same-day options share and quote behavior.

Methodology

  • Market data source: consolidated tape. delayed_stocks_minute_aggs for prices and volumes, options_trades for the options tape, cache_stocks_quotes and cache_options_quotes for the NBBO panels.
  • Close: the last regular-session minute bar, never an assumed 16:00 print and never an extended-hours print.
  • Time zone handling: all stored timestamps are UTC; WHERE clauses use raw UTC literals, and toTimeZone appears only in SELECT lists for ET labels.
  • Session verification: from the holiday table plus observed bars, never assumed from the calendar.
  • Prior-session comparisons: computed in-query from Friday, July 24, the prior trading session across the weekend, never carried over from a previous post.
  • Decimals: price, size and volume columns are cast to Float64 before any division or product.
  • Deterministic aggregates: exact quantiles and tuple-keyed tie-breaks throughout; every ordering or sign claim in prose is encoded as a sanity bound.
  • Warehouse as-of date: August 1, 2026, five days after the session, past the tape's usual one-to-two-day ingest lag; the bounded receipts above hold the post if a dataset is found missing at generation.

Cross-links: the previous daily recap, the July 29 edition, the weekly recap, when options expire, what a bid-ask spread is, and the two-to-ten-year spread.

Every query above runs unchanged on the Strasmore terminal if you want to re-point a window at a different session.