DEV Community

Daniel Oliveira
Daniel Oliveira

Posted on Originally published at equibles.com

How much do stocks move after earnings? I measured 12,353 S&P 500 reports

I measured the stock move on the first trading session after every quarterly earnings release by current S&P 500 companies since April 2020: 12,353 reports from 493 companies. The average move was 4.6% and the median 3.3%, about three times a normal day for the same stock. The part I didn't expect is how much bigger the moves have become.

Reports from Reports Average move Median move Moved 10% or more
Apr to Dec 2020 1,361 4.0% 3.0% 6.3%
2021 1,852 3.4% 2.6% 4.4%
2022 1,870 4.6% 3.3% 8.8%
2023 1,883 4.4% 3.3% 8.7%
2024 1,920 5.1% 3.9% 12.6%
2025 1,916 5.0% 3.6% 12.3%
Jan 1 to Oct 23, 2026 1,551 5.3% 3.9% 13.3%

In 2021 about one report in 23 moved the stock 10% or more. This year it's more than one in eight.

Five findings

1. It isn't index turnover. Newer, more volatile companies joining the S&P 500 could explain the trend, so I reran it on the 358 companies that reported in every year. Their average move went from 3.3% in 2021 to 5.2% in 2026, and the 10% share from 4.1% to 13.2%. Same picture.

2. After the close moves more than before the open. Releases after the close were followed by a 5.1% average move, against 4.1% before the open. Part of that is who reports when: technology companies put out 68.5% of their results after the close, industrial companies 22.7%. The after-close share itself has stayed between 43% and 45% a year.

3. Sector matters more than anything else. Over the last four quarters, technology stocks moved 8.0% on average and 28.2% of their reports moved the stock 10% or more. Utilities moved 1.9%. Eight of the ten calmest stocks on earnings are utilities.

4. The big moves don't keep going. Of the 4,119 reports followed by a move of 5% or more, the stock moved further in the same direction the next day 51.4% of the time, and the average next-day follow-through was 0.06%. A coin toss.

5. This October has been calm, so far. The 108 reports from October 1 to 23 moved stocks 3.6% on average, against 4.0% in the same weeks of 2025. The early weeks are mostly banks and industrial companies, though, and next week 133 S&P 500 companies report. Microsoft has averaged 7.0% over its last eight reports, Intel 9.3%, Eli Lilly 8.4% and Alphabet 4.1%; Twilio (15.8%) and Reddit (14.7%) are among the biggest movers on the list.

How I measured it, and the traps

  • The release time comes from the SEC. Each release is the company's item 2.02 8-K, timed by its EDGAR acceptance timestamp. Before 4 p.m. New York time, I use that day's close-to-close return; after the close, the next session's.
  • Don't trust one timestamp field. The acceptanceDateTime in EDGAR's submissions JSON didn't always agree with the acceptance time in the filing's own header file (.hdr.sgml), sometimes by several hours, which is enough to move a release across the close. Where the two disagreed about the trading day, I used the header.
  • Pick the right 8-K. Some companies file a preliminary 2.02 8-K days before the real results. My first rule grouped 2.02 filings within ten days of each other, which merged those pre-announcements with the real release. Keeping the latest one on or before the call date fixed it.
  • Check against something you know. For calls with a known start time, the inferred reaction day agreed with the call time 98.4% of the time.
  • Watch for rules that create trends. An early version treated a morning call as proof of a before-open release. It produced a neat finding that after-close releases were rising. They weren't; the rule was. Without it the share is flat.
  • Splits and the market. I excluded windows around stock splits, compared each move with the stock's median daily move over the previous 55 sessions, and checked a market-adjusted version: subtracting the median S&P 500 move that day only lowers the average from 4.6% to 4.5%.

Check a stock before it reports

With the Equibles MCP server connected to Claude or ChatGPT, a prompt like "Using Equibles, how much did Microsoft's stock move the day after each of its last eight earnings reports?" pulls the call dates and the daily prices and does the arithmetic.

The full study has the quarterly series, the sector table, the stocks that move most and least, the twelve biggest single moves since 2020 (AppLovin's +46.3% on November 7, 2024 leads) and next week's reporters with the biggest past moves: How Much Do Stocks Move After Earnings? Evidence From 12,353 S&P 500 Reports.

Top comments (9)

Collapse
 
signumhq profile image
SIGNUM HQ •

The 98.4% agreement with call times and the EDGAR header check are the parts I would copy. One cross-check against the options market, since you list this week's trailing averages: from the Oct 23 closing mids, the at-the-money straddle for the Oct 30 weekly expiry (a few ordinary days included) is about 5.3% for MSFT, 6.1% for GOOGL and 9.9% for INTC. Your trailing averages are 7.0%, 4.1% and 9.3%. So the options price sits below that history for MSFT and above it for GOOGL. It is a size, not a direction. If you can get the chain close from the last session before each past report, realized divided by implied per name would show whether options consistently under- or over-price specific stocks, which a stock's own history cannot. Did you look at that, or is a historical chain out of scope for this dataset?

Collapse
 
daniel_oliveira_4bd55d35d profile image
Daniel Oliveira •

I didn't, and with this dataset I can't do it properly. I only see the option chain as it is now, not the closing chain from the session before each past report, so realized over implied per name would need an archive I don't have.

The workable version is forward-looking: record the at-the-money straddle at the last close before each report from here on, then divide the next session's move by it. A few quarters of that would answer your question for the names that report every quarter.

Your three numbers show why one quarter isn't enough, though. An eight-report average is noisy: one outsized reaction can shift it by a point or more, so "options below history" for Microsoft could just as easily mean its history is running high. I'd want the per-name ratio over several quarters before reading a bias into it.

Collapse
 
signumhq profile image
SIGNUM HQ •

That forward-looking version is what I started logging, so a small update. For each report I store the straddle-implied move from the last session before the announcement and compare it with the next session's close-to-close move. It is only 16 reports from the last two weeks: 12 closed inside the implied range, 4 outside, and the median of absolute actual over implied is about 0.56. Only 4 of the 16 were captured live before the announcement; the rest were reconstructed afterward, so I would not read a bias into it yet. Your noise point holds: one name at 1.66x moves the mean a lot, so I report the median and want several quarters per name before saying anything about over- or under-pricing.

Thread Thread
 
daniel_oliveira_4bd55d35d profile image
Daniel Oliveira •

Good to see it running. One benchmark for the 0.56: a straddle prices roughly the average absolute move, and earnings moves are skewed, so the median sits below the average even when options are priced fairly. In the 12,353 reports here the median move was 3.3% against an average of 4.6%, a ratio of about 0.72. If implied moves matched the average move, your median ratio would land near 0.7 rather than 1, so 0.56 is a smaller gap than it looks.

The same skew means more than half of moves should close inside the implied range, so 12 of 16 is less surprising too. Once the sample is big enough to absorb the 1.66x names, I'd track the mean ratio alongside the median.

Thread Thread
 
signumhq profile image
SIGNUM HQ •

That benchmark is the missing context: I had been reading 0.56 against 1, and against roughly 0.72 the gap is much smaller. One thing to check on my side is the horizon. A straddle to a weekly expiry also covers ordinary days after the report, so if the implied move I logged runs to expiry rather than to the next session, that alone pulls the ratio down regardless of pricing. I will confirm which horizon each of the 16 uses before comparing, and track the mean ratio next to the median once the sample is larger. Your skew point also fits 12 of 16 landing inside the range.

Thread Thread
 
daniel_oliveira_4bd55d35d profile image
Daniel Oliveira •

That's the right thing to check. If the straddle runs to a weekly expiry, you can strip the ordinary days out roughly through variance: event move ≈ √(total² − n × daily²), where total is the straddle's implied move to expiry, n is the number of ordinary sessions after the report, and daily is the typical one-day move outside earnings (or the next expiry's implied vol scaled to a day).

It matters more than it sounds. With three extra sessions on a name that moves 1.5% a day, a 6.0% straddle leaves about 5.4% for the report itself, so a 0.56 ratio becomes about 0.62. On low-vol names with a big event premium the correction is small; on high-vol names it can be most of the gap.

Thread Thread
 
signumhq profile image
SIGNUM HQ •

That formula is the adjustment I was missing, and your worked example makes the size of it clear. I will apply it per report, using the next expiry's implied vol scaled to one day as the ordinary-day estimate, and keep both the raw and the adjusted ratio in the log so the correction stays visible. If most of the gap disappears on the high-vol names, that is the answer to my original question.

Thread Thread
 
daniel_oliveira_4bd55d35d profile image
Daniel Oliveira •

Sounds like a good plan. One catch with the ordinary-day estimate: if the next expiry also spans the report, its implied vol already includes the event, so scaling it to a day overstates ordinary moves. The forward vol between the first two expiries after the report avoids that, because the event sits inside both and cancels out: fwd² = (σ₂²·T₂ − σ₁²·T₁) / (T₂ − T₁), then scale that forward vol to one day. Curious what the high-vol names show once you've adjusted them.

Thread Thread
 
signumhq profile image
SIGNUM HQ •

Good catch, the next expiry would still carry the event, so scaling it to a day would count the report twice. The forward vol between the first two post-report expiries is cleaner because the event cancels out of both, and the chains I already pull include those expiries, so it is a small change to the calculation. I will use that as the ordinary-day estimate and share the high-vol names once a few reports have gone through it.