What Is Max Pain in Options? The Real Math
Max pain is the strike where option holders collect the least at expiry. See the calculation on a real SPY chain and how close settlement actually landed.
Max pain is the strike price at which the largest dollar value of outstanding options would expire worthless. It belongs to one underlying and one expiry date, and it comes out of a search over open interest: test every listed strike as a hypothetical settlement price, add up what every outstanding call and put would pay its holder at that price, and keep the price where the total is smallest. The name describes the option holders' side of the ledger. This page walks the arithmetic on a real SPY chain, then measures how close settlement actually landed across the standard 2026 monthly expirations.
How is max pain calculated?
Max pain is a search rather than a formula. Five steps:
- Collect open interest, the number of contracts still outstanding, at every strike on the expiry, with calls and puts kept separate.
- Pick a candidate settlement price. The listed strikes themselves are the usual candidate set.
- Value each call at the candidate price minus its strike, floored at zero, and each put at its strike minus the candidate price, floored at zero.
- Multiply every value by that strike's open interest and by the 100-share contract multiplier, then add the whole chain into one dollar figure.
- Repeat for each candidate and keep the smallest total. That candidate is the max pain strike.
A hypothetical fixes the mechanics. Say 1,000 calls sit open at a $95 strike and settlement lands at $100. Each contract pays its holder $5 a share, so the block pays $500,000 across 1,000 contracts of 100 shares. Slide settlement down to $95 and that block pays nothing, while every put struck above $95 begins paying instead. Walking the candidate price up and down the ladder traces a curve with a bottom, and that bottom is the number people quote.
Two properties come straight out of the definition. The minimum sits where call value and put value roughly balance in dollar terms, which places it near the strikes carrying the heaviest open interest. And the figure describes a chain at a moment: recompute it after another session of trading and the answer moves.
Where the contracts sit on the strike ladder
Open interest publishes once per session from clearing data after the close. The panels here use traded contract volume over the life of one expiry as a visible stand-in for that file, and the object has the same shape: a pile of contracts stacked within a few dollars of the underlying's price. Every contract on the SPY chain expiring Friday, July 17, 2026, grouped by strike:
The exact SQL behind every number
SELECT toString(strike_usd) AS strike,
round(sumIf(contracts, opt_type = 'C') / 1e3, 1) AS call_contracts_k,
round(sumIf(contracts, opt_type = 'P') / 1e3, 1) AS put_contracts_k
FROM (
SELECT intDiv(toUInt32OrZero(substring(ticker, length(ticker) - 7, 8)), 1000) AS strike_usd,
substring(ticker, length(ticker) - 8, 1) AS opt_type,
sum(toFloat64(volume)) AS contracts
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-06-18 08:00:00')
AND window_start < toDateTime('2026-07-18 04:00:00')
AND startsWith(ticker, 'O:SPY260717')
AND intDiv(toUInt32OrZero(substring(ticker, length(ticker) - 7, 8)), 1000) BETWEEN 736 AND 757
GROUP BY strike_usd, opt_type
)
GROUP BY strike_usd, strike
ORDER BY strike_usdThe ladder tilts as it crosses the money. At the $736 strike, puts outnumbered calls 113.2 thousand to 8 thousand. At $757 the tilt runs the other way, 131.7 thousand calls against 8.1 thousand puts. Puts stack below the underlying's price and calls stack above it, and the two sides cross somewhere in the middle. That crossover region is where a max pain figure will land before any arithmetic runs, which is the first thing worth knowing about the statistic. Contracts traded and contracts outstanding are different counts, and options volume vs open interest separates the two.
The payout curve and its bottom
Running steps 3 through 5 across candidate settlement prices from $730 to $765 draws the shape the calculation searches:
The exact SQL behind every number
WITH chain AS (
SELECT intDiv(toUInt32OrZero(substring(ticker, length(ticker) - 7, 8)), 1000) AS strike,
substring(ticker, length(ticker) - 8, 1) AS opt_type,
sum(toFloat64(volume)) AS contracts
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-06-18 08:00:00')
AND window_start < toDateTime('2026-07-18 04:00:00')
AND startsWith(ticker, 'O:SPY260717')
GROUP BY strike, opt_type
),
candidates AS (
SELECT DISTINCT strike AS settle FROM chain WHERE strike BETWEEN 730 AND 765
)
SELECT candidates.settle AS settle_price,
round(sum(multiIf(chain.opt_type = 'C' AND chain.strike < candidates.settle,
chain.contracts * (candidates.settle - chain.strike),
chain.opt_type = 'P' AND chain.strike > candidates.settle,
chain.contracts * (chain.strike - candidates.settle),
0)) * 100 / 1e6, 1) AS holder_payout_usd_mm
FROM candidates CROSS JOIN chain
GROUP BY settle_price
ORDER BY settle_priceA $730 settlement would pay holders $11149.2 million on this chain, nearly all of it to put holders. A $765 settlement would pay $11083.9 million, nearly all of it to call holders. Between the ends the curve drops into a shallow basin. Ranking the same totals from smallest upward names the strike:
The exact SQL behind every number
WITH chain AS (
SELECT intDiv(toUInt32OrZero(substring(ticker, length(ticker) - 7, 8)), 1000) AS strike,
substring(ticker, length(ticker) - 8, 1) AS opt_type,
sum(toFloat64(volume)) AS contracts
FROM global_markets.options_minute_aggs
WHERE window_start >= toDateTime('2026-06-18 08:00:00')
AND window_start < toDateTime('2026-07-18 04:00:00')
AND startsWith(ticker, 'O:SPY260717')
GROUP BY strike, opt_type
),
candidates AS (
SELECT DISTINCT strike AS settle FROM chain WHERE strike BETWEEN 730 AND 765
)
SELECT concat('$', toString(candidates.settle)) AS candidate_strike,
round(sum(multiIf(chain.opt_type = 'C' AND chain.strike < candidates.settle,
chain.contracts * (candidates.settle - chain.strike),
chain.opt_type = 'P' AND chain.strike > candidates.settle,
chain.contracts * (chain.strike - candidates.settle),
0)) * 100 / 1e6, 1) AS holder_payout_usd_mm
FROM candidates CROSS JOIN chain
GROUP BY candidate_strike
ORDER BY holder_payout_usd_mm ASC
LIMIT 6The minimum sits at $746, at $1898.2 million. Look at how flat the basin is rather than only at where it bottoms. The runner-up, $747, comes in at $1940.2 million, and the sixth-ranked candidate $749 at $2272.8 million. Six candidate prices spanning a handful of dollars on a $700-plus instrument sit close together, so a modest revision to the chain moves the printed strike while nothing about the market has changed.
What the theory claims
The popular version says an underlying gravitates toward its max pain strike into expiry, with option sellers pushing it there. Two separate claims are stacked in that sentence. The first is statistical: settlement prices cluster near the max pain strike. The second is mechanical: someone is doing the pushing.
The second claim is the weaker one. A max pain figure aggregates open interest with no information about which counterparty is long and which is short at any strike, so the sellers in the story are an assumption rather than an observation. A participant able to move a broad-market ETF into a chosen strike would need size beyond the hedging flows the whole chain generates. Where a real hedging mechanism has been described, it is the gamma one: a dealer book carrying positive gamma re-sizes its hedge by selling into strength and buying into weakness, a rulebook practitioners call dampening or pinning near heavily traded strikes. Our gamma exposure explainer lays out that estimate and the assumptions underneath it.
The first claim holds up better, with a large qualification covered in the next section. Academic work on expiration pinning documents the effect most clearly in single stocks whose option open interest is large relative to their tradable shares, and measures it in cents rather than dollars.
How close does the strike actually land?
Six standard monthly expirations ran on SPY between February and July 2026. For each one the panel computes the minimising strike from that expiry week's contracts, prints the actual closing price on the expiry session, and puts a naive control beside it: SPY's own close one week earlier, measured against the same settlement price.
The exact SQL behind every number
WITH expiries AS (
SELECT arrayJoin([toDate('2026-02-20'), toDate('2026-03-20'), toDate('2026-04-17'),
toDate('2026-05-15'), toDate('2026-06-18'), toDate('2026-07-17')]) AS expiry
),
chain AS (
SELECT toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) AS expiry,
intDiv(toUInt32OrZero(substring(ticker, length(ticker) - 7, 8)), 1000) AS strike,
substring(ticker, length(ticker) - 8, 1) AS opt_type,
sum(toFloat64(volume)) AS contracts
FROM global_markets.options_minute_aggs
WHERE ((window_start >= toDateTime('2026-02-16 08:00:00') AND window_start < toDateTime('2026-02-21 04:00:00'))
OR (window_start >= toDateTime('2026-03-16 08:00:00') AND window_start < toDateTime('2026-03-21 04:00:00'))
OR (window_start >= toDateTime('2026-04-13 08:00:00') AND window_start < toDateTime('2026-04-18 04:00:00'))
OR (window_start >= toDateTime('2026-05-11 08:00:00') AND window_start < toDateTime('2026-05-16 04:00:00'))
OR (window_start >= toDateTime('2026-06-15 08:00:00') AND window_start < toDateTime('2026-06-19 04:00:00'))
OR (window_start >= toDateTime('2026-07-13 08:00:00') AND window_start < toDateTime('2026-07-18 04:00:00')))
AND startsWith(ticker, 'O:SPY26')
AND toDateOrNull(concat('20', substring(ticker, length(ticker) - 14, 6))) IN (SELECT expiry FROM expiries)
GROUP BY expiry, strike, opt_type
),
curve AS (
SELECT c1.expiry AS expiry,
c1.strike AS settle,
sum(multiIf(c2.opt_type = 'C' AND c2.strike < c1.strike, c2.contracts * (c1.strike - c2.strike),
c2.opt_type = 'P' AND c2.strike > c1.strike, c2.contracts * (c2.strike - c1.strike),
0)) AS payout
FROM chain AS c1 INNER JOIN chain AS c2 ON c1.expiry = c2.expiry
GROUP BY c1.expiry, c1.strike
),
pain AS (
SELECT expiry, argMin(settle, payout) AS pain_strike FROM curve GROUP BY expiry
),
px AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMax(close, window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2026-02-05')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-17')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
),
prior AS (
SELECT expiries.expiry AS expiry, argMax(px.close_px, px.d) AS week_earlier_px
FROM expiries CROSS JOIN px
WHERE px.d <= expiries.expiry - 7
GROUP BY expiries.expiry
)
SELECT formatDateTime(pain.expiry, '%b %e') AS expiry_label,
pain.pain_strike AS min_payout_strike,
round(px.close_px, 2) AS settlement_close,
round(abs(px.close_px - pain.pain_strike) / px.close_px * 100, 2) AS max_pain_miss_pct,
round(abs(px.close_px - prior.week_earlier_px) / px.close_px * 100, 2) AS week_earlier_miss_pct
FROM pain
INNER JOIN px ON pain.expiry = px.d
INNER JOIN prior ON pain.expiry = prior.expiry
ORDER BY pain.expiryThe gap between the minimising strike and the close ran from 0.07% on the Jun 18 expiry to 0.53% on Mar 20, staying under six tenths of a percent in every month. Quoted on its own, that looks like a strong hit rate. Two features of the measurement cut it down.
The candidate ladder is centred on the underlying's price by construction. Strikes are listed around the money, and the contracts feeding the sum concentrate there as well, so the arithmetic starts inside a narrow band around spot and cannot return an answer far outside it. The second feature is timing: the contracts feeding each row here traded up to and including the expiry session, alongside the close being compared against. A figure computed from the same window it is measured against is describing that window, not calling it in advance.
The last column is the control worth reading. SPY's close one week before Apr 17 missed the settlement price by 4.32%, against 0.42% for the minimising strike. In May 15 the two came within a fraction of each other, 0.21% against 0.12%. A statistic computed on expiry day should beat a week-old price by a wide margin. The honest test, which this panel does not attempt, freezes the chain a week out and asks whether that strike calls the close any better than the price sitting on the screen the same day.
Reading a published max pain number
- Ask which contracts went into it. Publishers differ on weekly versus monthly series, and on index chains versus ETF chains tracking the same benchmark.
- Ask when the open interest was pulled. The clearing file updates once a session, so an intraday figure that moves is recomputing from something else.
- Ask what the whole curve looks like, not only where the bottom sits. A flat basin means the printed strike is one of several near-equal answers.
- Compare against a naive alternative before reading closeness as skill.
Expiration mechanics decide which contracts are still in the sum on any given day, and when options expire covers that calendar. For a second positioning statistic built from the same chain, the put call ratio measures the call and put mix directly.
Max pain FAQ
What does max pain mean in options trading?
Max pain is the strike price at which the total payout to holders of outstanding options on a single expiry would be smallest. It is computed from open interest by testing every listed strike as a hypothetical settlement price and keeping the cheapest one. The number describes the shape of an option chain and contains no forecast.
Do stocks always close at the max pain strike?
No. On the six SPY monthly expirations measured above, the minimising strike sat within 0.53% of the close at its widest, which sounds tight until the figure is compared against a naive benchmark and against the fact that the candidate strikes cluster around the price already. Closeness on a ladder centred at spot is a weak test.
How often does a max pain number change?
Open interest publishes once per trading session from clearing data after the close, so most published max pain figures move at most once a day. A dashboard whose number moves through the session is recomputing from traded volume or from an intraday chain snapshot instead of settled open interest.
Is max pain the same as gamma exposure?
No. Both read the same option chain and answer different questions. Max pain names a price, using open interest alone with no pricing model. Gamma exposure sizes a hedging flow in dollars per one percent move, and it needs an implied volatility surface plus an assumption about which side of each contract dealers hold.
Does max pain work on individual stocks?
The arithmetic runs on any listed chain. Its output gets noisy on thin chains where a handful of strikes carry nearly all the open interest, and the pinning research supporting any part of the theory concentrates on names whose option open interest is large relative to the shares available to trade.
Every panel above is a stored query with its SQL one click away. Run the same strike by strike walk on any chain on the Strasmore terminal.