Strasmore Research
Learn Matt ConnorBy Matt Connor · Updated 2026-07-26

Why Do Stocks Gap Up or Down Overnight?

A gap up or gap down is the distance from the prior close to the 9:30 open, after 17.5 closed hours. SPY overnight gap size, Mondays widest, plus stop risk.

A gap is the distance between where a stock closed one session and where it opened the next, a jump in the price chart with no regular-hours trades in between. Stocks gap up or down overnight for a structural reason: exchanges run a 6.5-hour session, and the other 17.5 hours still produce earnings, news, overseas trading and thin extended-hours prints. All of it lands on the next morning's open at once. This page measures gaps rather than asserting them: every SPY session of H1 2026, five household stocks beside the index, and one 8%-plus overnight move caught forming before the bell.

What is a gap up or gap down?

Gap up: today's opening price above yesterday's regular-session close. Gap down: below it. The open in question is the 9:30 a.m. ET open, set by the opening auction, which collects the overnight backlog of orders and clears it at a single price. Between the prior close and that auction, after-hours and premarket trading does print real trades, but at a fraction of regular-session volume, so the official open is where the market's full weight first speaks, and where the gap is measured.

Price discovery never fully stops: index futures trade nearly around the clock, overseas markets set levels while New York sleeps, premarket runs from 4:00 a.m. ET. By 9:30 the auction is not guessing, it ratifies a level the overnight venues already sketched.

How big is a normal overnight gap?

Every session of H1 2026 for SPY, the S&P 500 ETF, split into overnight (prior close to open) and intraday (open to close) components:

QuerySPY, H1 2026: average absolute overnight gap vs average absolute intraday move
sessionsavg_abs_overnight_gap_pctavg_abs_intraday_move_pctgaps_of_half_pct_or_more
1230.450.5341
The exact SQL behind every number
SELECT count() AS sessions,
       round(avg(abs(100 * (rth_open - prior_close) / prior_close)), 2) AS avg_abs_overnight_gap_pct,
       round(avg(abs(100 * (rth_close - rth_open) / rth_open)), 2) AS avg_abs_intraday_move_pct,
       countIf(abs(100 * (rth_open - prior_close) / prior_close) >= 0.5) AS gaps_of_half_pct_or_more
FROM (SELECT day, rth_open, rth_close, lagInFrame(rth_close) OVER (ORDER BY day) AS prior_close
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
               argMinIf(toFloat64(open), window_start, rth) AS rth_open,
               argMaxIf(toFloat64(close), window_start, rth) AS rth_close
        FROM (
            SELECT window_start, open, close,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker = 'SPY'
              AND window_start >= '2025-12-29 04:00:00'
              AND window_start < '2026-07-01 08:00:00'
        )
        GROUP BY day
    ))
WHERE day >= '2026-01-01' AND prior_close > 0 AND isFinite(prior_close)
Run this yourself

Across 123 sessions, SPY's average absolute overnight gap was 0.45%, against an average absolute open-to-close move of 0.53%: the untradeable overnight jump is nearly the size of the entire tradeable day that follows. Gaps of half a percent or more happened 41 times, roughly one session in three.

Do stocks gap more on Mondays?

Monday opens carry a reputation: a weekend stretches the same mechanics across 65 closed hours instead of 17.5. Folklore is testable. Every SPY session from January 2024 through June 2026, sorted into weekdays, with the average absolute gap and the 90th percentile, the size only one open in ten exceeds. (A Monday holiday pushes its weekend gap onto Tuesday's open, counted under Tuesday.)

QuerySPY overnight gaps by weekday: every session, January 2024 through June 2026
weekdaysessionsavg_abs_gap_pctp90_abs_gap_pct
Monday1190.521.11
Tuesday1310.360.73
Wednesday1270.390.92
Thursday1230.450.91
Friday1250.390.88
The exact SQL behind every number
SELECT ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'][dow] AS weekday,
       count() AS sessions,
       round(avg(abs(gap_pct)), 2) AS avg_abs_gap_pct,
       round(quantileDeterministic(0.9)(abs(gap_pct), toUInt64(toYYYYMMDD(day))), 2) AS p90_abs_gap_pct
FROM (
    SELECT day, toDayOfWeek(day) AS dow,
           100 * (rth_open - prior_close) / prior_close AS gap_pct
    FROM (
        SELECT day, rth_open, lagInFrame(rth_close) OVER (ORDER BY day) AS prior_close
        FROM (
            SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
                   argMinIf(toFloat64(open), window_start, rth) AS rth_open,
                   argMaxIf(toFloat64(close), window_start, rth) AS rth_close
            FROM (
            SELECT window_start, open, close,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
                FROM global_markets.delayed_stocks_minute_aggs
                WHERE ticker = 'SPY'
                  AND window_start >= '2023-12-28 04:00:00'
                  AND window_start < '2026-07-01 08:00:00'
            )
            GROUP BY day
        )
    )
    WHERE day >= '2024-01-01' AND prior_close > 0 AND isFinite(prior_close)
)
WHERE dow <= 5
GROUP BY dow
ORDER BY dow
Run this yourself

The folklore survives contact with the data. Monday's average absolute gap across 119 Mondays was 0.52%, the widest of the five weekdays, against 0.36% on Tuesday, 0.39% Wednesday, 0.45% Thursday and 0.39% Friday. The tail is where the weekend shows up hardest: Monday's 90th-percentile gap was 1.11% against Tuesday's 0.73%. The effect is real and small, a Monday open is a wider distribution, not a different animal, and nothing here says which direction.

The biggest gaps of H1 2026

The six largest SPY overnight gaps of the half, with what the rest of each day did:

QuerySPY's six biggest overnight gaps of H1 2026: and the same day's open-to-close move
sessionovernight_gap_pctrest_of_day_pct
April 8, 20262.6-0.08
March 3, 2026-1.650.77
March 23, 20261.47-0.41
January 20, 2026-1.46-0.57
June 23, 2026-1.42-0.02
June 15, 20261.380.37
The exact SQL behind every number
SELECT concat(monthName(day), ' ', toString(toDayOfMonth(day)), ', ', toString(toYear(day))) AS session,
       round(100 * (rth_open - prior_close) / prior_close, 2) AS overnight_gap_pct,
       round(100 * (rth_close - rth_open) / rth_open, 2) AS rest_of_day_pct
FROM (SELECT day, rth_open, rth_close, lagInFrame(rth_close) OVER (ORDER BY day) AS prior_close
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
               argMinIf(toFloat64(open), window_start, rth) AS rth_open,
               argMaxIf(toFloat64(close), window_start, rth) AS rth_close
        FROM (
            SELECT window_start, open, close,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker = 'SPY'
              AND window_start >= '2025-12-29 04:00:00'
              AND window_start < '2026-07-01 08:00:00'
        )
        GROUP BY day
    ))
WHERE day >= '2026-01-01' AND prior_close > 0 AND isFinite(prior_close)
ORDER BY abs(overnight_gap_pct) DESC, day
LIMIT 6
Run this yourself

The largest came on April 8, 2026: SPY opened 2.6% away from the prior close, then moved -0.08% from open to close. The entire day's repricing happened before the first regular-hours trade, the practical lesson of gaps is that the market can reprice without you.

A number with no story is half a number. Every SPY-tagged headline published between the April 7 close and the April 8 open:

QueryWhat crossed the wire during SPY's biggest overnight gap of H1 2026
et_publishedsourceheadline
Apr 08 03:28BenzingaDow Jones Surges Over 2% On US-Iran Ceasefire As Bullish April Seasonality Kicks
Apr 08 08:58BenzingaStock Market Today: S&P 500, Nasdaq Futures Surge As Trump Declares Ceasefire On
The exact SQL behind every number
SELECT formatDateTime(toTimeZone(published_utc, 'America/New_York'), '%b %d %H:%i') AS et_published,
       JSONExtractString(toString(publisher), 'name') AS source,
       substring(title, 1, 80) AS headline
FROM global_markets.stocks_news
WHERE published_utc >= toDateTime('2026-04-07 16:00:00', 'America/New_York')
  AND published_utc < toDateTime('2026-04-08 09:30:00', 'America/New_York')
  AND has(tickers, 'SPY')
ORDER BY published_utc
LIMIT 10
Run this yourself

Two headlines carried across those closed hours, both on a US-Iran ceasefire, timestamped Apr 08 03:28 ET and Apr 08 08:58 ET, before the bell, on a shut market. The gap is the accounting entry for news that arrives when you cannot trade.

Do individual stocks gap harder than the index?

An index ETF holds hundreds of companies, and their overnight surprises partly cancel. A single stock has no such cushion. Five household names next to SPY, same sessions:

QueryOvernight gaps by ticker, H1 2026: average absolute gap and the single biggest gap
tickersessionsavg_abs_gap_pctbiggest_gap_pctbiggest_gap_day
SPY1230.452.6April 8, 2026
KO1230.425.41April 28, 2026
AAPL1230.532.82May 1, 2026
MSFT1230.89-8.66January 29, 2026
NVDA1230.993.6April 8, 2026
TSLA1231.054.97April 8, 2026
The exact SQL behind every number
SELECT ticker,
       count() AS sessions,
       round(avg(abs(gap_pct)), 2) AS avg_abs_gap_pct,
       round(argMax(gap_pct, (abs(gap_pct), day)), 2) AS biggest_gap_pct,
       concat(monthName(argMax(day, (abs(gap_pct), day))), ' ', toString(toDayOfMonth(argMax(day, (abs(gap_pct), day)))), ', ', toString(toYear(argMax(day, (abs(gap_pct), day))))) AS biggest_gap_day
FROM (
    SELECT ticker, day, 100 * (rth_open - prior_close) / prior_close AS gap_pct
    FROM (
        SELECT ticker, day, rth_open,
               lagInFrame(rth_close) OVER (PARTITION BY ticker ORDER BY day) AS prior_close
        FROM (
            SELECT ticker, toDate(toTimeZone(window_start, 'America/New_York')) AS day,
                   argMinIf(toFloat64(open), window_start, rth) AS rth_open,
                   argMaxIf(toFloat64(close), window_start, rth) AS rth_close
            FROM (
                SELECT ticker, window_start, open, close,
                       toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                       AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
                FROM global_markets.delayed_stocks_minute_aggs
                WHERE ticker IN ('SPY', 'KO', 'AAPL', 'MSFT', 'NVDA', 'TSLA')
                  AND window_start >= '2025-12-29 04:00:00'
                  AND window_start < '2026-07-01 08:00:00'
            )
            GROUP BY ticker, day
        )
    )
    WHERE day >= '2026-01-01' AND prior_close > 0 AND isFinite(prior_close)
)
GROUP BY ticker
ORDER BY indexOf(['SPY', 'KO', 'AAPL', 'MSFT', 'NVDA', 'TSLA'], ticker)
Run this yourself

Read the two columns separately. On the typical night the ranking is what you would guess: Tesla averaged 1.05% and Nvidia 0.99%, against SPY's 0.45%, but Coca-Cola averaged 0.42%, below the index, a steady consumer mega-cap is a quiet overnight instrument most nights.

The tail column is where the cushion disappears. SPY's single biggest gap of the half was 2.6% (April 8, 2026), and all five single stocks beat it: Coca-Cola 5.41%, Apple 2.82%, Nvidia 3.6%, Tesla 4.97%, and Microsoft, the biggest of the lot, -8.66% on January 29, 2026. Single stocks are not always noisier than the index on an average night, but their worst night is far worse.

Watching a gap form before the bell

Rewind Microsoft's January 29, 2026 gap. The prior session closed at $481.72; whatever landed after that close landed on a shut market, and by the 4:00 a.m. ET premarket open the repricing was already done:

QueryMSFT: how the January 29, 2026 gap formed, 30-minute premarket buckets
et_timepriceprior_closevs_prior_close_pctpct_below_prior_closeshares_thousandscum_shares_millionscum_pct_of_regular_volume
04:00454481.72-5.755.751280.130.11
04:30451.32481.72-6.316.311370.260.23
05:00450.2481.72-6.546.541910.460.4
05:30449.13481.72-6.776.771110.570.5
06:00448.85481.72-6.826.821180.680.61
06:30446.2481.72-7.377.372640.950.84
07:00447.77481.72-7.057.053421.291.14
07:30449.22481.72-6.756.753051.61.41
08:00448.86481.72-6.826.8210102.612.31
08:30448.59481.72-6.886.885973.22.84
09:00439.74481.72-8.718.7116604.864.31
The exact SQL behind every number
WITH day_vol AS (
    SELECT sum(toFloat64(volume)) AS rth_vol
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'MSFT'
      AND window_start >= toDateTime('2026-01-29 09:30:00', 'America/New_York')
      AND window_start < toDateTime('2026-01-29 16:00:00', 'America/New_York')
),
prior AS (
    SELECT round(argMax(toFloat64(close), window_start), 2) AS prior_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'MSFT'
      AND window_start >= toDateTime('2026-01-28 09:30:00', 'America/New_York')
      AND window_start < toDateTime('2026-01-28 16:00:00', 'America/New_York')
),
buckets AS (
    SELECT toStartOfInterval(toTimeZone(window_start, 'America/New_York'), INTERVAL 30 minute) AS bucket,
           round(argMax(toFloat64(close), window_start), 2) AS price,
           sum(toFloat64(volume)) AS shares
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'MSFT'
      AND window_start >= toDateTime('2026-01-29 04:00:00', 'America/New_York')
      AND window_start < toDateTime('2026-01-29 09:30:00', 'America/New_York')
    GROUP BY bucket
)
SELECT formatDateTime(bucket, '%H:%i') AS et_time,
       price,
       (SELECT prior_close FROM prior) AS prior_close,
       round(100 * (price - (SELECT prior_close FROM prior)) / (SELECT prior_close FROM prior), 2) AS vs_prior_close_pct,
       round(abs(100 * (price - (SELECT prior_close FROM prior)) / (SELECT prior_close FROM prior)), 2) AS pct_below_prior_close,
       round(shares / 1000) AS shares_thousands,
       round(sum(shares) OVER (ORDER BY bucket) / 1000000, 2) AS cum_shares_millions,
       round(100 * sum(shares) OVER (ORDER BY bucket) / (SELECT rth_vol FROM day_vol), 2) AS cum_pct_of_regular_volume
FROM buckets
ORDER BY bucket
Run this yourself

The first premarket bucket, 04:00 ET, already printed $454, 5.75% below the prior close, on 128 thousand shares. The next five hours shuffled; by the final premarket bucket (09:00 ET) the price stood 8.71% below the close, and the official open landed at -8.66%, within a rounding error of what 4.86 million overnight shares had already decided.

Note the last column: all of premarket carried 4.31% of what the regular session would trade. A gap this size gets priced by a sliver of volume in the dark and confirmed by the full market at 9:30. That thinness is why spreads are widest around the open.

What the options market charged for that night

Options show what the market expected the move to be, before it happened. A straddle, the call plus the put at one strike and expiry, costs roughly what the market thinks the stock will move in either direction by expiry. Microsoft's near-the-money straddles, quoted in the last 15 minutes before the January 28 close, expiring two days later:

QueryMSFT straddle prices at the close before the gap: Jan 28, 2026, Jan 30 expiry
strike_pricecall_midput_midstraddle_costimplied_move_pct
$477.515.210.6725.875.37
$48013.811.9525.755.35
$482.512.6213.0725.695.33
$48511.4714.4225.895.37
The exact SQL behind every number
WITH prior AS (
    SELECT round(argMax(toFloat64(close), window_start), 2) AS prior_close
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'MSFT'
      AND window_start >= toDateTime('2026-01-28 09:30:00', 'America/New_York')
      AND window_start < toDateTime('2026-01-28 16:00:00', 'America/New_York')
),
quotes AS (
    SELECT toFloat64(substring(ticker, 14, 8)) / 1000 AS strike,
           substring(ticker, 13, 1) AS cp,
           round(argMax((bid_price + ask_price) / 2, sip_timestamp), 2) AS mid
    FROM global_markets.cache_options_quotes
    WHERE ticker LIKE 'O:MSFT260130%'
      AND sip_timestamp >= toDateTime('2026-01-28 15:45:00', 'America/New_York')
      AND sip_timestamp < toDateTime('2026-01-28 16:00:00', 'America/New_York')
      AND bid_price > 0
      AND ask_price > 0
    GROUP BY ticker
)
SELECT concat('$', toString(strike)) AS strike_price,
       maxIf(mid, cp = 'C') AS call_mid,
       maxIf(mid, cp = 'P') AS put_mid,
       round(maxIf(mid, cp = 'C') + maxIf(mid, cp = 'P'), 2) AS straddle_cost,
       round(100 * (maxIf(mid, cp = 'C') + maxIf(mid, cp = 'P')) / (SELECT prior_close FROM prior), 2) AS implied_move_pct
FROM quotes
WHERE abs(strike - (SELECT prior_close FROM prior)) <= 5
GROUP BY strike
HAVING countIf(cp = 'C') > 0 AND countIf(cp = 'P') > 0
ORDER BY strike
Run this yourself

The strike nearest the $481.72 close, $482.5, went out at $25.69 for the pair, 5.33% of the share price, and that was the priced move for two full sessions, not one night. The overnight gap alone came in at -8.66%. The options market had a number and the night beat it, and the neighbouring strikes agreed (5.37% at $477.5, 5.37% at $485), so this was consensus, not one rogue quote.

Two mechanics follow for anyone holding options through a gap. An option cannot reprice while the market is shut, the clock keeps running against long premium, and the whole move arrives in the opening print. And once the event is out, the uncertainty leaves the price with it: implied volatility collapses the morning after a release, which is why a correctly-called direction can still lose money on a long option. Days to expiry decide how violently both bite.

Types of gaps: the chart-pattern vocabulary

Traders label gaps by where they sit in a longer move. The names are descriptive, applied after the fact, and none is a forecast:

  • Common (area) gap, a small gap inside an ordinary range, no special news. Most sub-half-percent SPY gaps are these.
  • Breakaway gap, price jumps out of a range or through a long-standing level, typically on heavy volume.
  • Runaway (continuation) gap, a gap mid-trend, in the direction the stock was already going.
  • Exhaustion gap, a gap in the trend's direction arriving at the end of the run, after which price turns. On the day it looks identical to a runaway gap; only later data separates them.

The last pair is the honest catch: the label depends on what happens next, so nobody names it in real time.

What gaps mean for your orders

Three consequences, all flowing from the fact that no regular-hours trading happens inside the gap:

  • Stop orders do not stop the loss at the stop price. A stop becomes a market order once the stock trades at or through the trigger. If a stock closes at $50 and opens at $44, a $48 stop triggers at the open and fills near $44, the gap jumped clean over it. The stop guarantees the attempt, not the level; a stop-limit order caps the price you accept, at the risk of no fill at all.
  • Halts, not gaps, are the market's brake. Limit up-limit down (LULD) bands stop a stock printing more than a set percentage from its recent average price, 5% or 10% for most names, wider for low-priced ones, doubled at the open and close, and a persistent move outside the band triggers a five-minute pause. Market-wide circuit breakers halt everything if the S&P 500 falls 7% (Level 1) or 13% (Level 2) from the prior close, and shut the day at 20% (Level 3). None of this prevents the gap; it governs what happens once trading resumes.
  • "Gap fill" is a description, not a schedule. Traders say a gap "fills" when price returns to the prior close. Nothing obligates it to, on any timeframe. SPY's biggest gap day of the half moved just -0.08% after the open: no fill, no fade, just a new level.

Overnight and intraday are, statistically, different markets, which is also why how monthly returns are measured changes the answer depending on whether the overnight jumps are counted.

FAQ

What makes a stock gap up or down overnight?

The market is closed for 17.5 of every 24 hours and information does not stop: earnings land after the close, news breaks before the open, overseas markets trade all night. The opening auction clears the accumulated orders at one price; the distance from the prior close is the gap.

How common are overnight gaps?

Ubiquitous. In H1 2026, SPY's average absolute overnight gap was 0.45%, and 41 of 123 sessions opened at least half a percent from the prior close. Single stocks run larger: Tesla averaged 1.05%.

Do stocks gap more on Mondays?

Modestly, yes. From January 2024 through June 2026, SPY's average absolute Monday gap was 0.52%, the widest weekday, against 0.36% on Tuesday. The weekend adds closed hours, not direction.

Do gaps always get filled?

No. "The gap always fills" is trading folklore: some fill within hours, others never revisit the prior close. Treat any fill statistic as a description of past sessions, not a rule about the next one.

What happens to my stop-loss if a stock gaps down?

The stop triggers at the open and fills at whatever the market offers, which can sit far below the stop price, the gap holds no trades to catch it.


Every number above is a stored query, expand the SQL under any panel, or split any ticker's month into overnight and intraday moves on the Strasmore terminal.

#gaps#market structure#opening auction#overnight moves