TL;DR
Three numbers, one identity
GEX measures the dollars dealers must trade to rehedge gamma when spot moves 1%. It is the SqueezeMetrics 2017 quantity, gamma channel only.
VEX measures the same thing for the vanna channel — dealer rehedging when IV moves — under the SqueezeMetrics simplifying assumption that 1% spot ⇒ −10% IV.
GEX+ = GEX + VEX. A single combined dealer-rehedging-sensitivity figure that captures both spot-driven and IV-driven flow. Both inputs share the same $/1%-spot-move unit, so the addition is exact.
| Endpoint | What it returns |
|---|---|
/api/levels/{symbol} | Pure-gamma walls + HVL + flip (unchanged) |
/api/gex-plus/{symbol} | net_gex, net_vex, net_gex_plus, vex_share, GEX+ walls |
/api/profile/{symbol} | Per-strike vex + gex_plus alongside net_gex, net_dex |
GEX basics
The SqueezeMetrics 2017 formula
Gamma Exposure (GEX) was introduced in the SqueezeMetrics white paper Gamma Exposure: Quantifying Hedging Pressure (December 2017). For a single contract:
GEXcontract = sign × γ × OI × multiplier × spot² × 0.01Sum across both legs and all expiries (filtered by min_oi) → the per-strike net_gex column you see in /api/profile.
Source: SqueezeMetrics, Gamma Exposure, Dec 2017. PDF
Why GEX alone is incomplete
Spot and IV move together — vanna picks up the difference
Gamma captures dealer rehedging when spot moves. But spot and IV typically move together (anti-correlated for most regimes). When IV moves, dealer delta also shifts — via vanna — and dealers must trade more to neutralize.
In a stress regime the sequence is canonical:
- 01Spot drops.
- 02IV spikes (anti-correlation).
- 03Vanna-driven Δ changes pile on top of gamma-driven Δ changes.
- 04Dealer's combined rehedge is materially bigger than gamma alone would predict.
GEX alone misses step 3. GEX+ doesn't. This is the entire motivation for the VEX add-on.
10× IV-response calibration
Why VEX scales the way it does
From the SqueezeMetrics Master Spreadsheet Reference Guide, verbatim:
VEX … measured in thousands of dollars per SPX point, where each 0.10% move in SPX is assumed, for simplicity, to result in an anti-correlated 1.00% move (10×) in option implied volatility.
Translated into fractional units:
dIV_fractional / dS_fractional = −10That is: a 1% SPX drop ⇒ +10% IV bump (in absolute IV percentage points — e.g. IV moves 15.00% → 25.00%, not 0.15 → 0.165).
For SPX 7400, a 1-pt move (= 0.0135% fractional) gives a fractional IV change of −10 × 0.0135% = −0.135 pp. Plug into the vanna math below to recover the per-pt VEX.
The constant is exposed as IV_RESPONSE_FACTOR = 10.0 in backend/app/analytics/vanna_charm.py. Override via the keyword arg on per_strike_vanna_charm(...) if you want to back-test under a different calibration. Setting iv_response_factor = 0.0 nulls VEX entirely (pure-gamma mode).
VEX derivation
Same unit as GEX, exact identity from vanna_dollars
We want VEX in the same $/1%-spot-move unit as GEX so the two are directly additive at the strike level.
For a 1% spot move (= ΔS = 0.01 × spot in dollars):
ΔIV_fractional = −0.01 × IV_RESPONSE_FACTOR # default = −0.10
ΔΔ_per_share = vanna × ΔIV_fractional
$-rehedge_per_contract = ΔΔ_per_share × multiplier × spot
= vanna × (−0.01 × factor) × 100 × spotMultiplying by OI and applying the dealer sign:
VEX_strike = sign × OI × vanna × multiplier × spot × (−0.01 × factor)
= sign × OI × vanna × 100 × spot × (−0.10) # for factor = 10The existing vanna_dollars field already stores sign × vanna × OI × 100 × spot (dollar exposure per 1.0 fractional vol move = per 100% IV move), so VEX simplifies to an exact identity:
vex_scale = -0.01 * iv_response_factor # = -0.10 by default
vex_dollars = vex_scale * vanna_dollars # exact identitytests/test_vex.py::test_vex_default_factor_is_neg_10pct_of_vanna.GEX+ aggregation
Outer-join on strike so neither channel is silently truncated
At each strike:
gex_plus = net_gex + vexWhole chain:
net_gex_plus = net_gex + net_vexBoth gex and vex are signed under the same dealer convention. We align them via outer join on strike so a strike present in one DataFrame but missing in the other (e.g. dropped by the OI filter) fills with 0 rather than getting silently truncated:
# backend/app/analytics/gex_plus.py
merged = gex_agg.merge(vex_agg, on="strike", how="outer").fillna(0.0)
merged["gex_plus"] = merged["gex"] + merged["vex"]test_gex_plus_equals_net_gex_plus_vex_at_each_strike + test_net_gex_plus_equals_net_gex_plus_net_vex.Interpreting the numbers
Magnitudes, signs, walls, flip
Magnitudes
In $/1%-spot-move units (the Gamma Flow convention), GEX and VEX have very different typical scale:
- GEX is heavily sign-cancelled across calls and puts → net values often in the single-digit billions for SPX.
- VEX is more one-sided (dealers' vanna positions are structurally destabilizing in falling markets) → net values often dominated by the OTM-wing strikes, can reach hundreds of billions on the full chain.
A typical SPX payload from /api/gex-plus/SPX:
{
"net_gex": 1.7e9,
"net_vex": -473.5e9,
"net_gex_plus": -471.8e9,
"vex_share": -0.996,
"call_wall_plus": 7450,
"put_wall_plus": 8100,
"gex_plus_flip": null
}The vex_share = −0.996 tells you the chain is currently dominated by the IV-channel — the GEX+ card flags this as VEX DOMINATED.
$/SPX-pt unit (divide by spot × 0.01 ≈ 74), our VEX of −473B becomes −6.4B per SPX-pt — comfortably in their published GEX-magnitude neighborhood.Sign convention
Both channels follow the heuristic dealer sign. Positive gex_plus = combined dealer-rehedge flow is stabilizing (dealers will buy as spot falls, sell as spot rises). Negative = destabilizing.
In stress regimes the vanna channel typically pulls GEX+ negative (crash-dynamics intuition). In stable regimes gamma dominates and the sign tracks the pure-GEX sign.
Walls
call_wall_plus=argmax(gex_plus)across strikes.put_wall_plus=argmin(gex_plus)across strikes.
These often differ from the pure-GEX walls because vanna adds weight at OTM strikes (where gamma is small but vanna is large). Compare against /api/levels/{symbol}.call_resistance_1 / put_support_1 to see how the combined model shifts the "magnet" strikes.
GEX+ flip
The strike where cumulative gex_plus crosses zero, nearest to spot. Analog of the gamma-flip in the gamma-only model — divides the chain into the "long combined dealer exposure" zone and "short combined dealer exposure" zone. Returns null if the chain has no sign change (pure long-GEX+ or pure short-GEX+ regime).
HVL vs Gamma Wall
Semantic correction shipped 2026-05-19 — read this before you cite either field
Before 2026-05-19, our /api/levels/{symbol}.hvl field accidentally stored the Gamma Wall. Every consumer labelling it "HVL" was actually seeing the wall. That bug is fixed — and the API field names did not change, so existing downstream consumers automatically pick up the correct value.
What each one means
- HVL (High Volume Level) =
argmin |cumulative GEX − 0|nearest to spot. It's the regime divider — above HVL the chain is net long-gamma (vol-suppressing), below it's net short-gamma (vol-amplifying). This is the same semantic MenthorQ uses. - Gamma Wall =
argmax |Σ GEX|across all strikes. The single biggest dealer-rehedge-density strike — your spot-attractor / magnet candidate. - Gamma Flip = the lowest-strike first-crossing of cumulative GEX. Legacy field, kept for back-compat. Most surfaces should use
hvlinstead.
Why both ship
They answer different questions. HVL tells you which regime you're in. Gamma Wall tells you which strike is pulling spot. Mistaking one for the other is the most common interpretation error on this kind of data, which is exactly why we now expose both fields side-by-side on every levels payload.
Vendor mapping (GEXBot · MenthorQ · SpotGamma)
Different vendors use different vocabulary for the same regime-divider concept. Use this lookup when cross-checking our numbers against another platform's:
- GEXBot "zero gamma" ⇒ our
hvl(NOTgamma_flip). Their "zero gamma" is the strike where cumulative GEX is at its minimum within the active strike window — same math as MenthorQ HVL. Compare these two if you want a direct number-vs-number check. - MenthorQ "HVL" ⇒ our
hvl(exact match — empirically within 0.15% on SPX 2026-05-19). - SpotGamma "Volatility Trigger" ⇒ our
hvlis the closest analog (their formula is proprietary but the sign-of-cumulative-GEX semantics line up). - Gamma Wall has no direct vendor analog — GEXBot's "Major Positive" wall is the call-side resistance, which maps to our
call_resistance_1, notgamma_wall.
/api/levels/{symbol} and on /api/menthorq/{symbol}. The MenthorQ-shape payload exposes hvl + gamma_wall verbatim.DEX (Delta Exposure)
The orange cumulative line on the profile chart
Per-contract:
DEX_contract = sign × δ × OI × multiplier × spotDEX answers how much underlying dealers are notionally long/short right now, in dollars. Cumulative DEX is what MenthorQ renders as the orange line overlay on top of the GEX histogram in the per-strike profile.
Exposed per-strike on /api/profile/{symbol}.strikes[].net_dex alongside net_gex, vex, and gex_plus. Aggregate total_dex + net_dex on /api/levels.
Futures conversion
Ratio-derived levels for NQ, ES, GC, RTY, ZB — and where this differs from native pipelines
Free-tier options-on-futures data don't exist with the depth we need. Instead we compute levels on the corresponding ETF (or index) and convert by an empirical ratio:
F_levels ≈ underlying_levels × ratio| Futures | Source | Method | Ratio (current) |
|---|---|---|---|
| NQ | QQQ (default) or NDX | ratio | ≈ 42 |
| ES | SPY (default) or SPX | ratio | ≈ 10 |
| GC | GLD | ratio | ≈ 10 |
| RTY | IWM | ratio | ≈ 1 |
| ZB | TLT | ratio | — |
Each ratio is computed live from the actual spot prices — ratio = futures_spot / source_spot — so as the basis drifts the conversion drifts with it. The futures spot itself comes from yfinance (NQ=F, ES=F, etc.).
framework/playbooks/validate-conversion-formula.md. If intra-day dispersion blows out (e.g. an overnight gap on futures that the cash session hasn't caught up to), the conversion will drift.How this differs from MenthorQ's native NQ pipeline. MenthorQ computes NQ levels directly from the NQ futures options chain — the institutional dealer hedging book lives there, separate from the retail/ETF flow in QQQ options. On 2026-05-21 (validated via MQ Quin AI direct query, see backend/data/backtest/hvl_validation/quin_ai_session_findings.md), MQ's native NQ HVL was 29,100 while our NDX-derived projection produced 28,171 — a ~3% structural difference because the OI clustering on futures options doesn't map perfectly through a price ratio. We choose derivation because it's free; the trade-off is a small structural drift on futures whose flow profile diverges most from its cash underlying.
What we don't do (and why)
The methodologies we explicitly chose not to ship
Negative space matters. Here's what we considered, and why it's not on the site:
- Flow-adjusted GEX — chose DDOI instead. Flow-adjustment (e.g. layering volume-weighted call/put sign signals onto the heuristic) was rejected as too fragile vs. just measuring dealer directional position from OPRA classified-trade data. Tracked as audit recommendation #2.
- Opaque vendor signals — no SpotGamma "HIRO" reseller, no SqueezeMetrics live API reseller, no MenthorQ data fetch. We do not redistribute anyone else's data product. Every number here is computed from primary CBOE delayed quotes.
- Volume gating on GEX — we use
min_oionly. A strike with massive OI but ~zero volume is treated as "live" exposure when it might be stale. Polygon HIRO (paid) would refine this; we're holding off until DDOI ships. - Regime-aware IV-response — the 10× SqueezeMetrics constant is a simplification. Real IV-response varies with regime, skew, term structure, time of day. We expose
iv_response_factoras a kwarg so future versions can fit IV vs SPX over a rolling 21-day window. Until then: 10× constant, documented. - Forecasting / trade signals — Q-Score is a deterministic function of today's data. It is not a forecast, not a trade recommendation. Past output tells you nothing about future returns. (We have a research backlog for evaluating signal vs. forward returns, but anything published would have to clear statistical significance bars first.)
- Custom Pine Seeds feed — Pine Seeds is closed for new repos as of 2026. We ship a paste-based Pine indicator instead (BackQuant / OutsiderEdge pattern), which is what
/api/copy/{symbol}and/api/menthorq/{symbol}/pineserve.
Known limitations
Honest about the edges
- 01Heuristic dealer sign. Until DDOI ships we use the static "calls long, puts short" assumption. This is wrong when, e.g., customers have been selling protective puts back to dealers (which makes dealers long puts at those strikes). DDOI fixes it.
- 02Fixed 10× calibration. Real IV-response varies with regime. The 10× number is SqueezeMetrics' simplification — we expose
iv_response_factorso future regime-aware calibrations are a drop-in change. - 03No volume gating. See "what we don't do" above. OI-only filtering can include stale strikes.
- 04Same-sign-flips suppressed. Two adjacent strikes both with
gex_plus = 0get only the first reported as a flip candidate. Rare corner case. - 05Risk-free rate is a constant. Vanna/Charm use a placeholder
r. FRED 3-mo T-bill wire-up is queued. Sensitivity is small for short-dated, non-zero for long-dated. - 06Futures levels are derived, not native. NQ/ES/GC/RTY/ZB are converted from QQQ/SPY/GLD/IWM/TLT by an empirical ratio. MenthorQ runs a native NQ futures-options pipeline; ours doesn't (CME futures options data isn't on the free CBOE feed). The 2026- 05-22 Quin AI cross-check showed a ~3 % structural delta on NQ HVL between our derived value and MQ native. Acceptable for directional signal; not acceptable if you trade off the exact dealer-hedging level. See Section 10 for full numbers.
- 0715-minute CBOE delay. Free tier. Real-time options data costs $$$. For levels (slow-moving), 15min delay is fine. For anything intraday-sensitive, it isn't — and we don't pretend otherwise.
- 08Not financial advice. Self-evident. The numbers here are for research and education.
Source attribution
Upstream credit is intentional
The methodology on this page is downstream of SqueezeMetrics' work. Gamma Flow's contribution is the open-source implementation and the free public API — not the math.
- Gamma Exposure (Dec 2017) — original GEX formula. white_paper.pdf
- Master Spreadsheet Reference Guide — VEX, GEX+, DDOI definitions used as the modern reference.
- @SqueezeMetrics 2020-07-07 (status 1280212140759097346) — first public introduction of VEX.
- Hull, Options, Futures and Other Derivatives (chs. 17 & 19) — closed-form vanna / charm.
- OCC option symbology — 21-char OPRA symbol decoding. theocc.com
docs/audit_2026_05_19/11_squeezemetrics_deep_research.md. This page is a distillation of that file + the shipped GEX+ doc at docs/methodology/gex_plus.md.