Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

Index Rebalance Day and the Closing Auction

Index rebalance day puts the year's biggest size through the closing auction. How the S&P and Russell rebalances print, with measured volume multiples.

On index rebalance day, the closing auction carries more size than any other session of the quarter. Index funds are measured against the index's own official closing price, and the auction is the one venue that guarantees that price in size. The dates are published months ahead, which makes rebalance day the most crowded and the most predictable print on the calendar.

Why index rebalances concentrate in the closing auction

An index fund's job is to match an index, not to beat it. The index is valued once a day, at the official closing price of every member, so a fund holding the index's exact weights at that print matches the index exactly. A fund that bought at 2:15 p.m. instead owns the stock at a price the index never used, and that difference shows up as tracking error, the gap between a fund's return and its benchmark's.

That puts the closing auction at the center of the day. The auction is a single call at 4:00 p.m. ET: market-on-close orders, limit-on-close orders and eligible continuous-book interest cross at one price, and that price becomes the official close. No other venue can promise it.

A rebalance also arrives as a dated instruction. The index provider announces that a member's share count, float factor or membership changes effective a named session, and every fund tracking that index needs its old weight gone and its new weight on by that session's close. Thousands of funds reading one instruction with one deadline queue into the same few seconds.

The index rebalance calendar: which dates matter

As of October 2026, four recurring events produce most of the outlier closes.

  • S&P quarterly rebalance. S&P Dow Jones Indices refreshes share counts and float factors across the S&P 500 and its siblings each quarter, effective after the close of the third Friday in March, June, September and December. The fund trade prints in that Friday's auction, the same session as triple witching expiration.
  • Russell reconstitution. FTSE Russell rebuilds the Russell 1000 and Russell 2000 from scratch once a year, effective at the open after the last Friday in June. Recon Friday's close is the auction most market-structure desks point to for the year's largest prints.
  • MSCI index reviews. MSCI implements its quarterly reviews as of the close of the last business day of February, May, August and November, with May and November the larger pair. The trade lands in that day's closing auction.
  • Single-name index changes. An add or a delete announced between scheduled reviews takes effect before the open of a named session, so the fund trade prints in the session before. Small in aggregate, enormous in the one name changing hands.

The Nasdaq-100 annual reconstitution in December follows the same shape, effective before the open after the third Friday.

How much bigger is the close on index rebalance day?

Rather than assert that it is huge, measure it. The panel below takes three household names across four rebalance sessions, two Russell recon Fridays and two S&P quarterly Fridays, and compares the shares that printed in the 4:00 p.m. minute bar against the median of that same minute over the name's previous twenty sessions.

QueryClosing-minute volume on four rebalance sessions vs each name's 20-session median
labelclose_minute_shares_mmtypical_close_shares_mmclose_volume_multiple
MSFT Russell recon Jun-202616.090.3348.1
AAPL S&P quarterly Dec-202519.280.5733.6
AAPL Russell recon Jun-20269.850.3329.7
KO Russell recon Jun-20250.510.163.3
AAPL Russell recon Jun-20252.50.783.2
AAPL S&P quarterly Mar-20261.40.473
MSFT S&P quarterly Dec-20250.920.342.7
MSFT S&P quarterly Mar-20260.430.261.7
MSFT Russell recon Jun-20250.520.311.7
KO S&P quarterly Dec-20250.440.281.5
KO S&P quarterly Mar-20260.170.220.8
KO Russell recon Jun-202600.110
The exact SQL behind every number
WITH close_minute AS
(
    SELECT
        ticker,
        toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
        toFloat64(sum(volume))                               AS close_volume
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL', 'MSFT', 'KO')
      AND window_start >= '2025-05-01'
      AND window_start <  '2026-06-29'
      AND toHour(toTimeZone(window_start, 'America/New_York'))   = 16
      AND toMinute(toTimeZone(window_start, 'America/New_York')) = 0
    GROUP BY ticker, session_date
),
ranked AS
(
    SELECT
        ticker,
        session_date,
        close_volume,
        row_number() OVER (PARTITION BY ticker ORDER BY session_date) AS n
    FROM close_minute
),
events AS
(
    SELECT
        ticker,
        close_volume,
        n,
        multiIf(session_date = '2025-06-27', 'Russell recon Jun-2025',
                session_date = '2025-12-19', 'S&P quarterly Dec-2025',
                session_date = '2026-03-20', 'S&P quarterly Mar-2026',
                                             'Russell recon Jun-2026') AS event
    FROM ranked
    WHERE session_date IN ('2025-06-27', '2025-12-19', '2026-03-20', '2026-06-26')
)
SELECT
    concat(e.ticker, ' ', e.event)                                             AS label,
    round(e.close_volume / 1e6, 2)                                             AS close_minute_shares_mm,
    round(quantileDeterministic(0.5)(b.close_volume, b.n) / 1e6, 2)            AS typical_close_shares_mm,
    round(e.close_volume / quantileDeterministic(0.5)(b.close_volume, b.n), 1) AS close_volume_multiple
FROM events AS e
INNER JOIN ranked AS b ON b.ticker = e.ticker
WHERE b.n >= e.n - 20
  AND b.n <= e.n - 1
GROUP BY e.ticker, e.event, e.close_volume
ORDER BY close_volume_multiple DESC
Run this yourself

The widest row is MSFT Russell recon Jun-2026, at 48.1x its own twenty-session median: 16.09 million shares in one minute against a typical 0.33 million. The twelve readings do not all point the same way. At the soft end of the panel, KO Russell recon Jun-2026 measured 0x, a closing minute that carried a fraction of that name's usual closing-minute size rather than a multiple of it, which is what a thin or absent 16:00 bar looks like in a minute-bar feed. Read the panel row by row rather than as one number.

Which sessions in a month carry the biggest close?

Zoom out to a full month and the concentration is easy to place. The next panel tracks, session by session through June 2026, the share of each name's regular-session volume that printed in the closing minute.

QueryShare of session volume printed in the 4:00 p.m. minute, June 2026
21 rows (showing 20)
sessionsession_labelspy_close_share_pctaapl_close_share_pct
2026-06-01Jun 10.442.01
2026-06-02Jun 20.430.84
2026-06-03Jun 31.041.15
2026-06-04Jun 40.341.19
2026-06-05Jun 50.560.64
2026-06-08Jun 80.420.54
2026-06-09Jun 90.630.44
2026-06-10Jun 101.011.09
2026-06-11Jun 110.750.83
2026-06-12Jun 120.60.46
2026-06-15Jun 151.10.92
2026-06-16Jun 160.621.67
2026-06-17Jun 170.351.18
2026-06-18Jun 180.642.53
2026-06-22Jun 220.420.84
2026-06-23Jun 230.510.87
2026-06-24Jun 240.810.71
2026-06-25Jun 251.030.58
2026-06-26Jun 261.479.4
2026-06-29Jun 290.935.51
The exact SQL behind every number
WITH bars AS
(
    SELECT
        ticker,
        toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
        toHour(toTimeZone(window_start, 'America/New_York')) * 60
            + toMinute(toTimeZone(window_start, 'America/New_York')) AS et_minute,
        toFloat64(volume)                                            AS bar_volume
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'AAPL')
      AND window_start >= '2026-06-01'
      AND window_start <  '2026-07-01'
)
SELECT
    toString(session_date)                AS session,
    formatDateTime(session_date, '%b %e') AS session_label,
    round(100 * sumIf(bar_volume, ticker = 'SPY' AND et_minute = 960)
              / sumIf(bar_volume, ticker = 'SPY'), 2)  AS spy_close_share_pct,
    round(100 * sumIf(bar_volume, ticker = 'AAPL' AND et_minute = 960)
              / sumIf(bar_volume, ticker = 'AAPL'), 2) AS aapl_close_share_pct
FROM bars
WHERE et_minute >= 570
  AND et_minute <= 960
GROUP BY session_date
HAVING sumIf(bar_volume, ticker = 'SPY') > 0
   AND sumIf(bar_volume, ticker = 'AAPL') > 0
ORDER BY session_date
Run this yourself

On Jun 26, the last Friday of that month, SPY's closing minute carried 1.47% of its session volume and AAPL's carried 9.4%. On Jun 1, an ordinary session at the start of the month, the same two readings measured 0.44% and 2.01%. Read across the series and a handful of sessions sit well apart from the rest of the month.

What the volume curve looks like on a rebalance session

Inside one rebalance session the curve is lopsided. This panel splits that June recon Friday into half-hour buckets for a single name and puts each bucket's share of the session next to the average share of the same bucket over the twenty sessions before it.

QueryHalf-hour volume shares on the June 2026 recon session vs the prior 20 sessions
et_timerecon_day_pcttypical_day_pct
09:309.715.49
10:005.558.69
10:305.47.29
11:004.516.19
11:306.596.01
12:006.045.42
12:304.295.57
13:003.325.61
13:302.925.66
14:004.975.22
14:306.215.35
15:008.656.36
15:3022.4615.4
16:009.41.74
The exact SQL behind every number
WITH bars AS
(
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
        toHour(toTimeZone(window_start, 'America/New_York')) * 60
            + toMinute(toTimeZone(window_start, 'America/New_York')) AS et_minute,
        toFloat64(volume)                                            AS bar_volume
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'AAPL'
      AND window_start >= '2026-05-28'
      AND window_start <  '2026-06-27'
),
buckets AS
(
    SELECT
        session_date,
        if(et_minute = 960, 960, intDiv(et_minute, 30) * 30) AS bucket_min,
        sum(bar_volume)                                      AS bucket_volume
    FROM bars
    WHERE et_minute >= 570
      AND et_minute <= 960
    GROUP BY session_date, bucket_min
),
day_totals AS
(
    SELECT
        session_date,
        sum(bucket_volume) AS day_volume
    FROM buckets
    GROUP BY session_date
),
shares AS
(
    SELECT
        b.session_date                       AS session_date,
        b.bucket_min                         AS bucket_min,
        100 * b.bucket_volume / d.day_volume AS share_pct
    FROM buckets AS b
    INNER JOIN day_totals AS d ON d.session_date = b.session_date
)
SELECT
    formatDateTime(toDateTime(bucket_min * 60, 'UTC'), '%H:%i') AS et_time,
    round(avgIf(share_pct, session_date =  '2026-06-26'), 2)    AS recon_day_pct,
    round(avgIf(share_pct, session_date <  '2026-06-26'), 2)    AS typical_day_pct
FROM shares
GROUP BY bucket_min
HAVING countIf(session_date =  '2026-06-26') > 0
   AND countIf(session_date <  '2026-06-26') > 0
ORDER BY bucket_min
Run this yourself

The 16:00 bucket is the closing minute on its own, and it took 9.4% of that session against 1.74% on an ordinary day. The 09:30 bucket, the opening half hour, took 9.7%. The dip through the middle of both curves is the ordinary midday volume lull, unchanged by the rebalance. What changes is the last bucket.

Placing a market-on-close order into a rebalance

A market-on-close order is an instruction to trade at the official close with no price limit. A limit-on-close order adds a cap and participates only if the auction clears at or inside the price named. Both run on a clock, and the clock is the part most readers have never seen.

On a normal session, market-on-close and limit-on-close interest for the primary exchange's auction has to be entered by 3:50 p.m. ET. After that cutoff an existing order can no longer be cancelled, and fresh on-close interest is accepted only inside narrow exchange rules, generally on the side that offsets a published imbalance.

From that same minute the exchange starts publishing the auction book: paired shares, the size left unpaired on one side, and an indicative clearing price. The NYSE closing auction and the Nasdaq Closing Cross differ in their order types and in the role the exchange's assigned market maker plays, and those two pages walk each venue in detail.

The indication is a snapshot of the book at the moment it was published, not a quote for the close. Between 3:50 and 4:00 the offsetting side arrives, and on a rebalance session it arrives in size.

How far can the close print from the 3:50 p.m. indication?

Price tells the same story as volume. This panel measures, for the same names and sessions, the distance between the 3:50 p.m. price and the last print of the closing minute in basis points, one basis point being one hundredth of one percent, alongside each name's median distance over its prior twenty sessions.

QueryDistance from the 3:50 p.m. price to the closing minute, in basis points
labelevent_drift_bpstypical_drift_bps
AAPL S&P quarterly Dec-2025110.615.2
KO S&P quarterly Dec-202537.76.2
MSFT Russell recon Jun-202537.48.1
KO Russell recon Jun-202633.48.1
MSFT Russell recon Jun-202633.318.8
MSFT S&P quarterly Mar-2026248.4
AAPL Russell recon Jun-202521.49.5
AAPL S&P quarterly Mar-202616.217.9
KO S&P quarterly Mar-202614.76.8
AAPL Russell recon Jun-2026617.2
KO Russell recon Jun-20255.710.9
MSFT S&P quarterly Dec-20253.915
The exact SQL behind every number
WITH marks AS
(
    SELECT
        ticker,
        toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
        anyIf(toFloat64(close),
              toHour(toTimeZone(window_start, 'America/New_York')) = 15
              AND toMinute(toTimeZone(window_start, 'America/New_York')) = 50) AS px_350,
        anyIf(toFloat64(close),
              toHour(toTimeZone(window_start, 'America/New_York')) = 16
              AND toMinute(toTimeZone(window_start, 'America/New_York')) = 0)  AS px_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL', 'MSFT', 'KO')
      AND window_start >= '2025-05-01'
      AND window_start <  '2026-06-29'
      AND toHour(toTimeZone(window_start, 'America/New_York')) IN (15, 16)
    GROUP BY ticker, session_date
    HAVING px_350 > 0
       AND px_close > 0
),
drift AS
(
    SELECT
        ticker,
        session_date,
        round(10000 * abs(px_close / px_350 - 1), 1)                  AS drift_bps,
        row_number() OVER (PARTITION BY ticker ORDER BY session_date) AS n
    FROM marks
),
events AS
(
    SELECT
        ticker,
        drift_bps,
        n,
        multiIf(session_date = '2025-06-27', 'Russell recon Jun-2025',
                session_date = '2025-12-19', 'S&P quarterly Dec-2025',
                session_date = '2026-03-20', 'S&P quarterly Mar-2026',
                                             'Russell recon Jun-2026') AS event
    FROM drift
    WHERE session_date IN ('2025-06-27', '2025-12-19', '2026-03-20', '2026-06-26')
)
SELECT
    concat(e.ticker, ' ', e.event)                         AS label,
    e.drift_bps                                            AS event_drift_bps,
    round(quantileDeterministic(0.5)(b.drift_bps, b.n), 1) AS typical_drift_bps
FROM events AS e
INNER JOIN drift AS b ON b.ticker = e.ticker
WHERE b.n >= e.n - 20
  AND b.n <= e.n - 1
GROUP BY e.ticker, e.event, e.drift_bps
ORDER BY event_drift_bps DESC
Run this yourself

AAPL S&P quarterly Dec-2025 shows the widest travel in the panel: 110.6 basis points between the 3:50 p.m. price and the closing minute, against a median of 15.2 basis points across that name's previous twenty sessions. A market-on-close order resting in that auction accepted the full distance, whatever it turned out to be.

The two order types price different risks. A market-on-close order accepts price uncertainty and guarantees the fill. A limit-on-close order controls the price and accepts that it may go unfilled, leaving the position open into the next session. Leveraged and inverse funds add their own mechanical flow to the same minute, which the leveraged ETF rebalancing page covers.

How these panels measure the close

The official closing print is stamped 4:00:00 p.m. ET, so the minute bar stamped 16:00 is the cleanest proxy a minute-bar table offers. That bar can also hold other trades reported inside the same minute, which makes these counts a small overstatement of pure auction size. A pinned session can also carry a thin or absent 16:00 bar, which shows up as a multiple at or near zero instead of an elevated one, and the panels publish every row as measured rather than dropping the ones that sit against the headline. Baselines are medians over each name's previous twenty sessions, computed deterministically so a rerun of the same query returns the same figure. Every panel's exact SQL sits underneath it.

FAQ

What is index rebalance day?

It is the session a published index change takes effect. The index provider updates share counts, float factors or membership on a set date, and the funds tracking that index trade their side in that session's closing auction.

Why do index funds trade at the closing auction?

An index is valued at its members' official closing prices, so a fund that trades at the close owns the same prices the index used. Trading at any other time of day opens a gap between the fund's return and the benchmark's, which is tracking error.

Which index rebalance carries the most volume?

The June Russell reconstitution is the session market-structure desks watch for the year's largest auction prints. The S&P quarterly Fridays come next, and they coincide with index futures and options expiration, which stacks two flows into one close.

Can a market-on-close order print far from the 3:50 p.m. indication?

Yes. On-close orders are due by 3:50 p.m. ET and the exchange publishes its first imbalance picture from that minute, but the picture describes the book at publication time. Offsetting interest arriving in the final ten minutes moves the clearing price, and a market-on-close order carries no price limit, so it settles at whatever the auction prints.


Every panel here ships with the SQL that produced it, so you can open one and follow how each multiple was counted. To measure a rebalance close on a name you follow, ask the question in plain English on the Strasmore terminal.

#closing auction#index rebalance#moc#russell reconstitution#volume