What Is the Gamma Flip Level?
The gamma flip level is the price where estimated dealer gamma crosses zero. How it is built from strike gamma and open interest, and how to check one.
The gamma flip level is the underlying price at which estimated aggregate dealer gamma crosses zero. Above that price, the standing options book implies hedging flows that lean against a move. Below it, flows that lean with one. The level is a model output assembled from public option data plus one large assumption about who is holding what, so the useful thing to know is how it gets built.
What a gamma flip level is made of
Gamma is the rate at which an option's delta changes as the underlying moves, the subject of what option gamma is. A desk running a hedged book buys and sells the underlying as its delta drifts, the mechanic covered in how delta hedging works, and gamma sets how much that hedge has to change per point of movement. Add the gamma of every contract in a chain together, with a sign and a weight on each, and you have gamma exposure, usually written GEX. The flip is one specific reading of that total: the underlying price where it passes through zero.
Four inputs go into it:
- Gamma per contract at each strike and expiration, from a Black-Scholes calculation.
- A sign convention. The usual build assumes dealers are short calls and long puts, so call gamma enters the sum negative and put gamma enters positive.
- A weight per contract. Published levels use open interest.
- A scaling step: the 100 share contract multiplier, then spot squared times 0.01, which states the total in dollars of delta per 1% move.
The sign convention deserves a second look. Assume the mirror instead, dealers long calls and short puts, and every number in the aggregate changes sign. The zero crossing does not move. What changes is which side of the level gets called positive.
Step one: gamma per contract across the strike ladder
Gamma per contract is not flat across a chain. It peaks near the money and falls away in both directions. The panel below is pinned to one fixed past session, the last June 2026 session carried in this data, and averages gamma per contract across the 20 to 45 day expirations at each strike within 6% of the close.
| strike | call_gamma | put_gamma |
|---|---|---|
| 705 | 0.00523 | 0.00512 |
| 710 | 0.00575 | 0.00589 |
| 715 | 0.00653 | 0.00678 |
| 720 | 0.00766 | 0.00776 |
| 725 | 0.00844 | 0.00888 |
| 730 | 0.00946 | 0.01002 |
| 735 | 0.0107 | 0.01137 |
| 740 | 0.01198 | 0.01239 |
| 745 | 0.01268 | 0.01344 |
| 750 | 0.01377 | 0.0142 |
| 755 | 0.01379 | 0.01446 |
| 760 | 0.01364 | 0.01404 |
| 765 | 0.01253 | 0.01204 |
| 770 | 0.01118 | 0.0112 |
| 775 | 0.00929 | 0.00957 |
| 780 | 0.00745 | 0.00814 |
The exact SQL behind every number
SELECT
toString(toInt32(strike_price)) AS strike,
round(avgIf(toFloat64(gamma), lower(substring(option_type, 1, 1)) = 'c'), 5) AS call_gamma,
round(avgIf(toFloat64(gamma), lower(substring(option_type, 1, 1)) = 'p'), 5) AS put_gamma
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date = (
SELECT max(date)
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date <= '2026-06-30'
)
AND iv_converged = 1
AND volume > 0
AND days_to_expiry BETWEEN 20 AND 45
AND modulo(toInt32(strike_price), 5) = 0
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.06
GROUP BY strike_price
HAVING countIf(lower(substring(option_type, 1, 1)) = 'c') > 0
AND countIf(lower(substring(option_type, 1, 1)) = 'p') > 0
ORDER BY strike_priceAt the bottom strike of that window, average call gamma prints 0.00523, and at the top strike 0.00745, with the hump sitting between them across 16 strikes. Call and put gamma at the same strike and expiration are the same quantity in the model, which is why the two series in the panel sit on top of each other. The sign convention, not the gamma, is what separates the two sides.
Step two: signs, weights, and where the curve turns
One contract's exposure is small. Take a strike carrying 100 contracts with a gamma of 0.02 while the underlying sits at $600. Multiply 0.02 by 100 contracts, by the 100 share multiplier, by 600 squared, by 0.01, and you get roughly $720,000 of delta per 1% move. That is the unit of the next panel, stated in millions.
The panel walks the same pinned session's strike ladder across every expiration out to 45 days. Each strike's contribution is signed by the convention above, weighted by that session's traded contract volume, and the running column accumulates from the lowest strike upward.
| strike | strike_gamma_musd | running_gamma_musd |
|---|---|---|
| 705 | 42.4 | 42.4 |
| 710 | 130.8 | 173.2 |
| 715 | 41 | 214.2 |
| 720 | 99.8 | 314 |
| 725 | 200.1 | 514.1 |
| 730 | 253.4 | 767.5 |
| 735 | 442.2 | 1209.7 |
| 740 | 1162.1 | 2371.8 |
| 745 | 1536.8 | 3908.6 |
| 750 | -4878.8 | -970.2 |
| 755 | -881.6 | -1851.8 |
| 760 | -395.7 | -2247.5 |
| 765 | -115.3 | -2362.8 |
| 770 | -43.8 | -2406.6 |
| 775 | -26.8 | -2433.4 |
| 780 | -14 | -2447.4 |
| 785 | -5.6 | -2453 |
| 790 | -2.5 | -2455.5 |
The exact SQL behind every number
SELECT
strike,
strike_gamma_musd,
round(sum(strike_gamma_musd) OVER (ORDER BY strike_num), 1) AS running_gamma_musd
FROM
(
SELECT
toInt32(strike_price) AS strike_num,
toString(toInt32(strike_price)) AS strike,
round(sum(multiIf(lower(substring(option_type, 1, 1)) = 'c', -1.0, 1.0)
* toFloat64(gamma) * volume * 100
* pow(toFloat64(underlying_close), 2) * 0.01) / 1e6, 1) AS strike_gamma_musd
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date = (
SELECT max(date)
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date <= '2026-06-30'
)
AND iv_converged = 1
AND volume > 0
AND days_to_expiry <= 45
AND modulo(toInt32(strike_price), 5) = 0
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.06
GROUP BY strike_price
)
ORDER BY strike_numThe bottom strike of the window contributes 42.4 million dollars of delta per 1% move and the top strike -2.5 million. Across the full 12% band the ladder nets to -2455.5 million. Read the running line left to right: it climbs while put-weighted strikes dominate and turns over once call-weighted strikes take the balance. The price where it turns is the flip estimate. Every step of that is bookkeeping a reader can redo by hand, which is the point.
What the level is not
Nothing in that construction observes a dealer. Open interest says a contract exists. It does not say which side of it a market maker holds. The project behind the open source GEX dashboard states the limit in its own README, describing the output as a Black-Scholes approximation computed from open interest and
not a measure of actual market-maker positions
(project README, as of September 2026)
Coverage is the second gap. The free data source behind that dashboard exposes no option chain endpoint for the cash index symbols, SPX, XSP, NDX, RUT, DJX and VIX, which are exactly the symbols practitioners quote flip levels on loudest. A level published for one of those was computed somewhere else, on a paid chain or on an ETF proxy. SPX and SPY options track the same index at roughly a ten to one notional ratio, and a level built on one has to be rescaled before it describes the other.
The curve itself is the third. A proper flip repvalues every contract's gamma at each candidate underlying price and finds the zero of the resulting function. The ladder proxy above reprices nothing: it reads the balance of the book as it stood at one close. The panels here also weight by traded volume rather than open interest, since volume is the per-contract weight this daily greeks data carries. Same shape, different weight.
Why two vendors publish different levels for the same index
Every input above is a choice, and vendors set them differently. The expiration window is the loudest one. The panel below recomputes the same estimate on the same session from four slices of the expiration calendar.
| dte_bucket | spot_close | flip_estimate |
|---|---|---|
| 0 to 1 days | 746.3 | 745 |
| 2 to 7 days | 746.3 | 744 |
| 8 to 30 days | 746.3 | 746 |
| 31 to 90 days | 746.3 | 745 |
The exact SQL behind every number
SELECT
dte_bucket,
round(any(spot), 2) AS spot_close,
round(argMax(strike, running), 2) AS flip_estimate
FROM
(
SELECT
dte_bucket,
bucket_order,
spot,
strike,
sum(net_gamma) OVER (PARTITION BY dte_bucket ORDER BY strike) AS running
FROM
(
SELECT
multiIf(days_to_expiry <= 1, '0 to 1 days',
days_to_expiry <= 7, '2 to 7 days',
days_to_expiry <= 30, '8 to 30 days',
'31 to 90 days') AS dte_bucket,
multiIf(days_to_expiry <= 1, 1,
days_to_expiry <= 7, 2,
days_to_expiry <= 30, 3, 4) AS bucket_order,
toFloat64(strike_price) AS strike,
any(toFloat64(underlying_close)) AS spot,
sum(multiIf(lower(substring(option_type, 1, 1)) = 'c', -1.0, 1.0)
* toFloat64(gamma) * volume * 100) AS net_gamma
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date = (
SELECT max(date)
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date <= '2026-06-30'
)
AND iv_converged = 1
AND volume > 0
AND days_to_expiry <= 90
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.15
GROUP BY dte_bucket, bucket_order, strike
)
)
GROUP BY dte_bucket, bucket_order
ORDER BY bucket_orderThe 0 to 1 day slice puts the estimate at 745 against a close of 746.3. The 31 to 90 day slice puts it at 745. One book, one session, one formula, four answers. A dashboard that sums every listed expiration and one that stops at the front month are not describing the same quantity, and neither is wrong.
The other knobs behave the same way:
- The weight: open interest at the prior settle, open interest refreshed intraday, or traded volume.
- The strike band: how far out of the money the sum runs before it is truncated.
- The sign convention, which relabels the sides without moving the crossing.
- The snapshot time.
- Whether the level comes from index options directly or from a rescaled ETF proxy.
Why the level moves during the session
Open interest in contracts expiring the same day is created and retired inside that session. The 0 to 1 day slice is the fastest moving part of the book, and it now carries a large share of index option volume, a topic covered in 0DTE options and their risks. A level computed at 9:45 a.m. ET and the same level computed at 2:00 p.m. ET rest on different open interest at the strikes nearest spot, where gamma per contract is largest. Vendors refreshing intraday publish a level that walks through the day. Vendors snapping once at the prior close publish one that sits still.
Does the estimate move day to day
Across the 21 sessions of June 2026, the same ladder estimate tracks the close at a distance that changes daily.
| date | session_label | spot_close | flip_estimate |
|---|---|---|---|
| 2026-06-01 | Jun 1 | 756.58 | 757 |
| 2026-06-02 | Jun 2 | 759.63 | 759 |
| 2026-06-03 | Jun 3 | 750.55 | 753 |
| 2026-06-04 | Jun 4 | 754.56 | 756 |
| 2026-06-05 | Jun 5 | 735.36 | 742.5 |
| 2026-06-08 | Jun 8 | 738.72 | 742.5 |
| 2026-06-09 | Jun 9 | 735.7 | 735 |
| 2026-06-10 | Jun 10 | 722.88 | 729 |
| 2026-06-11 | Jun 11 | 739.48 | 730 |
| 2026-06-12 | Jun 12 | 742.45 | 740 |
| 2026-06-15 | Jun 15 | 753.91 | 754 |
| 2026-06-16 | Jun 16 | 750.75 | 751 |
| 2026-06-17 | Jun 17 | 745.6 | 744 |
| 2026-06-18 | Jun 18 | 746.94 | 746 |
| 2026-06-22 | Jun 22 | 743.67 | 745 |
| 2026-06-23 | Jun 23 | 735.02 | 734 |
| 2026-06-24 | Jun 24 | 737.2 | 732 |
| 2026-06-25 | Jun 25 | 732.7 | 735 |
| 2026-06-26 | Jun 26 | 731.2 | 733 |
| 2026-06-29 | Jun 29 | 740.76 | 739 |
The exact SQL behind every number
SELECT
toString(d) AS date,
formatDateTime(d, '%b %e') AS session_label,
round(any(spot), 2) AS spot_close,
round(argMax(strike, running), 2) AS flip_estimate
FROM
(
SELECT
d,
spot,
strike,
sum(net_gamma) OVER (PARTITION BY d ORDER BY strike) AS running
FROM
(
SELECT
date AS d,
toFloat64(strike_price) AS strike,
any(toFloat64(underlying_close)) AS spot,
sum(multiIf(lower(substring(option_type, 1, 1)) = 'c', -1.0, 1.0)
* toFloat64(gamma) * volume * 100) AS net_gamma
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date BETWEEN '2026-06-01' AND '2026-06-30'
AND iv_converged = 1
AND volume > 0
AND days_to_expiry <= 45
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.15
GROUP BY d, strike
)
)
GROUP BY d
ORDER BY dOn Jun 1 the estimate landed at 757 against a close of 756.58. On Jun 30 it landed at 746 against 746.3. The two series travel together, which is what a statistic anchored to where volume concentrates will do. The gap between them is the part anyone is actually reading.
How to sanity-check a published flip level
- Ask which expirations it includes and how far out of the money the sum runs before truncation.
- Ask what weight it uses and what time that weight was snapped.
- Ask whether it was computed on the index itself or on an ETF proxy and rescaled.
- Rebuild the ladder on the same session and see whether your turn lands in the same neighbourhood. Two honest builds that land 30 points apart are telling you about the method rather than the market.
- Read the precision. Index strike ladders are spaced 5 points or wider and the greeks are daily, so a level quoted to the cent is finer than anything underneath it.
FAQ
What is the gamma flip level in options?
It is the underlying price at which an estimate of total dealer gamma crosses zero. The estimate is built by signing each contract's gamma, weighting it by open interest, scaling by the contract multiplier, and summing the chain. It comes from public option data, not from any view of dealer inventory.
Is the gamma flip the same thing as GEX?
No. GEX is the aggregate gamma number itself, usually stated in dollars of delta per 1% move. The flip is the single underlying price at which that aggregate passes through zero. GEX is the curve, the flip is one point on it.
Why do two dashboards show different gamma flip levels for the same index?
They set different inputs: the expiration window, the strike band, the weight and its snapshot time, the sign convention, and whether the level comes from index options or a rescaled ETF proxy. The expiration panel above produces four different estimates from one session by varying a single input.
Does the gamma flip level change during the trading day?
For any build that refreshes intraday, yes. Open interest in same-day expirations is created and retired inside the session, and the strikes nearest spot carry the heaviest gamma weight. A level snapped once at the prior close holds until the next snapshot.
Every panel on this page carries the exact SQL beneath it. Rebuild the ladder on another symbol or another session on the Strasmore terminal and watch where the turn lands.