max pain options calculation SPY
Max pain na di strike where option holders collect di least at expiry. See di real math on a SPY chain and how close settlement actually land.
Max pain na di strike price where di biggest dollar value of options wey still dey go expire worthless. E dey for one underlying and one expiry date, and e come out from searching open interest: test every listed strike as a hypothetical settlement price, add up wetin every outstanding call and put go pay di holder at dat price, and keep di price where di total dey smallest. Di name describe di option holders' side of di ledger. Dis page walk di arithmetic on a real SPY chain, then measure how close settlement actually land across di standard 2026 monthly expirations.
How dem calculate max pain?
Max pain na search, no be formula. Five steps:
- Collect open interest, di number of contracts wey still dey outstanding, at every strike on di expiry, with calls and puts separate.
- Pick a candidate settlement price. Di listed strikes demself na di usual candidate set.
- Value each call at di candidate price minus e strike, floor am at zero, and each put at e strike minus di candidate price, floor am at zero.
- Multiply every value by dat strike open interest and by di 100-share contract multiplier, then add di whole chain into one dollar figure.
- Repeat for each candidate and keep di smallest total. Dat candidate na di max pain strike.
A hypothetical fix di mechanics. Say 1,000 calls dey open at a $95 strike and settlement land at $100. Each contract pay e holder $5 per share, so di block pay $500,000 across 1,000 contracts of 100 shares. Slide settlement down to $95 and dat block pay nothing, while every put struck above $95 begin pay instead. Walking di candidate price up and down di ladder trace a curve with a bottom, and dat bottom na di number wey people quote.
Two properties come straight out of di definition. Di minimum dey where call value and put value roughly balance in dollar terms, wey place am near di strikes wey carry di heaviest open interest. And di figure describe a chain at a moment: recompute am after another session of trading and di answer move.
Where di contracts dey on di strike ladder
Open interest publish once per session from clearing data after di close. Di panels here use traded contract volume over di life of one expiry as a visible stand-in for dat file, and di object get di same shape: a pile of contracts stack within a few dollars of di underlying price. Every contract on di SPY chain wey go expire Friday, July 17, 2026, group 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_usdDi ladder tilt as e cross di money. At di $736 strike, puts outnumber calls 113.2 thousand to 8 thousand. At $757 di tilt run di other way, 131.7 thousand calls against 8.1 thousand puts. Puts stack below di underlying price and calls stack above am, and di two sides cross somewhere for di middle. Dat crossover region na where a max pain figure go land before any arithmetic run, wey be di first thing wey worth knowing about di statistic. Contracts wey dem trade and contracts wey dey outstanding na different counts, and options volume vs open interest separate di two.
Di payout curve and e bottom
Running steps 3 through 5 across candidate settlement prices from $730 to $765 draw di shape wey di calculation dey search:
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 go pay holders $11149.2 million on dis chain, nearly all of am to put holders. A $765 settlement go pay $11083.9 million, nearly all of am to call holders. Between di ends di curve drop into a shallow basin. Ranking di same totals from smallest upward name di 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 6Di minimum dey at $746, at $1898.2 million. Look at how flat di basin be rather than only at where e bottom. Di runner-up, $747, come in at $1940.2 million, and di 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 di chain move di printed strike while nothing about di market don change.
Wetin di theory claim
Di popular version say an underlying gravitate toward e max pain strike into expiry, with option sellers push am there. Two separate claims dey stack for dat sentence. Di first na statistical: settlement prices cluster near di max pain strike. Di second na mechanical: somebody dey do di pushing.
Di second claim na di weaker one. A max pain figure aggregate open interest with no information about which counterparty dey long and which dey short at any strike, so di sellers for di story na assumption, no be observation. A participant wey fit move a broad-market ETF into a chosen strike go need size beyond di hedging flows wey di whole chain generate. Where a real hedging mechanism don describe, e be di gamma one: a dealer book wey carry positive gamma re-size e hedge by selling into strength and buying into weakness, a rulebook wey practitioners call dampening or pinning near heavily traded strikes. Our gamma exposure explainer lay out dat estimate and di assumptions underneath am.
Di first claim hold up better, with a large qualification wey di next section cover. Academic work on expiration pinning document di effect most clearly for single stocks wey dia option open interest dey large relative to dia tradable shares, and measure am for cents, no be dollars.
How close di strike actually land?
Six standard monthly expirations run on SPY between February and July 2026. For each one di panel compute di minimising strike from dat expiry week contracts, print di actual closing price on di expiry session, and put a naive control beside am: SPY own close one week earlier, measure against di 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.expiryDi gap between di minimising strike and di close run from 0.07% on di Jun 18 expiry to 0.53% on Mar 20, stay under six tenths of a percent for every month. Quoted on e own, dat look like a strong hit rate. Two features of di measurement cut am down.
Di candidate ladder dey centred on di underlying price by construction. Strikes dey listed around di money, and di contracts wey feed di sum concentrate there as well, so di arithmetic start inside a narrow band around spot and no fit return an answer far outside am. Di second feature na timing: di contracts wey feed each row here trade up to and include di expiry session, alongside di close wey dem compare against. A figure wey dem compute from di same window wey dem measure am against dey describe dat window, no be call am in advance.
Di last column na di control wey worth reading. SPY close one week before Apr 17 miss di settlement price by 4.32%, against 0.42% for di minimising strike. For May 15 di two come within a fraction of each other, 0.21% against 0.12%. A statistic wey dem compute on expiry day suppose beat a week-old price by a wide margin. Di honest test, wey dis panel no attempt, freeze di chain a week out and ask whether dat strike call di close any better than di price wey dey on di screen di same day.
Reading a published max pain number
- Ask which contracts go into am. Publishers differ on weekly versus monthly series, and on index chains versus ETF chains wey track di same benchmark.
- Ask when dem pull di open interest. Di clearing file update once a session, so an intraday figure wey move dey recompute from something else.
- Ask wetin di whole curve look like, no be only where di bottom dey. A flat basin mean di printed strike na one of several near-equal answers.
- Compare against a naive alternative before reading closeness as skill.
Expiration mechanics decide which contracts still dey for di sum on any given day, and when options expire cover dat calendar. For a second positioning statistic wey dem build from di same chain, di put call ratio measure di call and put mix directly.
Max pain FAQ
Wetin max pain mean for options trading?
Max pain na di strike price where di total payout to holders of outstanding options on a single expiry go be smallest. Dem compute am from open interest by testing every listed strike as a hypothetical settlement price and keep di cheapest one. Di number describe di shape of an option chain and no contain any forecast.
Stocks always close at di max pain strike?
No. On di six SPY monthly expirations wey dem measure above, di minimising strike sit within 0.53% of di close at e widest, wey sound tight until dem compare di figure against a naive benchmark and against di fact wey di candidate strikes cluster around di price already. Closeness on a ladder wey centre at spot na weak test.
How often a max pain number change?
Open interest publish once per trading session from clearing data after di close, so most published max pain figures move at most once a day. A dashboard wey e number move through di session dey recompute from traded volume or from an intraday chain snapshot instead of settled open interest.
Max pain be di same as gamma exposure?
No. Both read di same option chain and answer different questions. Max pain name a price, using open interest alone with no pricing model. Gamma exposure size a hedging flow for dollars per one percent move, and e need an implied volatility surface plus an assumption about which side of each contract dealers hold.
Max pain work on individual stocks?
Di arithmetic run on any listed chain. E output get noisy on thin chains where a handful of strikes carry nearly all di open interest, and di pinning research wey support any part of di theory concentrate on names wey dia option open interest dey large relative to di shares wey dey available to trade.
Every panel above na a stored query with e SQL one click away. Run di same strike by strike walk on any chain on di Strasmore terminal.