Implied move
How it's calculatedA straddle-based estimate of how far the stock could swing by the nearest options expiry. We pull the next available expiry from yfinance (expiries[0] — the nearest weekly or monthly), find the strike closest to the current price (the at-the-money, or ATM, strike), and look at the ATM call and ATM put. The correct calculation ADDS the two premiums (the cost of buying both = a straddle) and divides by the spot price: (call + put) / spot, shown as ±N%. Two code paths compute this differently. The live path (data_provider.py:742-743) does it right: it sums the call and put mid-prices (bid/ask midpoint, falling back to last trade) and divides by spot. The daily-batch path (options_snapshot_service.py:83-85) does NOT sum — it AVERAGES the two legs ((call.lastPrice + put.lastPrice) / 2) and divides that by spot, producing roughly half the true straddle move, and it uses last-trade prices rather than the midpoint.
How it affects judgementA high implied move tells you the options market is paying up for protection or leverage into the nearest expiry — common ahead of earnings, a regulatory date, or a macro print, or when a name is in play. Set it against the stock's recent realized moves: if implied is running well above the stock's historical swings, the market is pricing in something specific; if it's below, the market sees calm. You can use it to gauge whether a thesis price target is within reach inside the expiry window, or whether the options market is at odds with a quiet consensus. One caution before drawing any of those conclusions: the number you see on screen comes from the batch path, which currently halves the straddle (see The catch), so compare it against the bands below rather than against textbook implied-move figures.
Current valueThis metric’s live data pipeline is under review — the method above describes how it is intended to be calculated, but the current displayed value may not yet reflect that formula. Treat it as in progress, not a finished number.
RangeFor a correctly-computed straddle move: theoretical floor is 0% (options worth nothing — never seen in practice). Typical large-cap non-event range: ±2-6%. Pre-earnings: ±5-15%. Small/micro-cap or high-fear names: ±15-40%. Distress or near-expiry thin chains can exceed ±50% but lose precision there. Caveat on the shipped number: because the preferred batch source averages the two legs instead of summing them, the displayed ±N% lands at roughly half these bands. The two code paths can also disagree for the same ticker — the live path (sum) reports about 2x the batch path (average) — so which number you see depends on which snapshot is fresher.
The catchThe number displayed today is mathematically wrong by a factor of about 2. The on-screen value prefers the daily-batch snapshot (options_snapshot_service.py), and that path AVERAGES the ATM call and put ((call + put)/2) instead of summing them — a straddle is the sum, not the average. So the displayed implied move is roughly HALF the true straddle move. The batch path also uses last-trade prices, which on thinly traded strikes can be stale on top of the halving. The live-fetch path (data_provider.py) computes it correctly — it sums the two legs and prefers the bid/ask midpoint — but the display layer (ticker_service.py:529-535) prefers the batch value when it exists. Net: for a given ticker the batch and live numbers can be about 2x apart, and the one you usually see is the halved, less accurate one.
Max pain
How it's calculatedFor each listed strike, we sum the total dollar payout that would flow to call holders (all calls below that strike, weighted by their open interest) plus the payout to put holders (all puts above it). The strike where that combined payout is smallest is max pain. Strikes within 0.5x-2x of spot are preferred; if none fall in that band, the full strike list is used as a fallback. If the chain carries zero open interest, the field is suppressed entirely.
How it affects judgementMax pain tells you where the largest share of open-interest value evaporates at expiry. If spot is far above max pain heading into expiry week, there is structural pressure for price to drift back; if far below, the reverse. Weigh it alongside put/call ratio and gamma walls — convergence across all three sharpens the read; divergence weakens it.
What the current value signifiesThe displayed dollar figure is the strike where option writers collectively owe the least. A max pain close to the current price (within ~2-3%) signals the chain is balanced around today's level. A gap of 5-10%+ means spot has drifted meaningfully from where writers would prefer it to settle — watch for reversion pressure as expiry nears.
RangeExpressed as a price in the same dollar terms as the stock. The companion field max_pain_dist shows the percentage gap from spot: typical readings cluster within +/-5-10% of spot; anything beyond +/-15% is unusual. The display layer suppresses the field via _near_spot (0.3x-3.0x of spot) as a feed-glitch guard, and it is also suppressed when the chain is too thin.
The catchThe pinning effect is real but inconsistent — it depends on dealers actively hedging and on expiry proximity. On low-volume names or fresh weekly chains with sparse open interest, the pain curve flattens and the reading becomes unreliable (the code returns null in the zero-OI case, but a lightly populated chain can still produce a noisy result).
Gamma walls
How it's calculatedWe look at the strikes saved in the nightly options snapshot and pick the strike holding the most call open interest (the call wall) and the most put open interest (the put wall). Important: the snapshot is not the full chain. It is built from the front-month expiry only — the nearest expiration — and trimmed to roughly the 10 strikes above and 10 below the at-the-money strike at the time it was captured (`backend/app/services/options_snapshot_service.py:39` takes `expiries[0]`; lines 52-58 keep only ATM±10). So the recompute loop scans that windowed snapshot, not every strike on the board. The winner on each side is stored as `call_wall` / `put_wall` by `backend/scripts/recompute_options_analytics.py:107-118`. A `_near_spot` sanity guard (0.3x-3x of spot) drops feed glitches before the values reach the page.
How it affects judgementThe call wall is the strike carrying the heaviest call open interest, and the put wall the strike carrying the heaviest put open interest. Traders commonly watch the call wall as a possible resistance zone and the put wall as a possible support zone, on the idea that heavy OI can act as a magnet near expiration. But read it as a descriptor, not a forecast: this computation only counts contracts by strike — it has no knowledge of who holds them. The same OI can be dealer short-gamma (which would push hedging toward pinning price) or customer long-gamma (which pushes the opposite way), and those flip the implied hedging direction entirely. So the wall tells you where the open interest is clustered, not which way price will move. A narrow spread between the two walls is often associated with price staying range-bound; a wide spread leaves more room before either cluster matters. Walls also dissolve when large OI rolls or expires, so treat one as a live cluster that can move, not a fixed barrier.
What the current value signifiesThe call wall is the heaviest call-OI strike above spot in the stored window; the put wall is the heaviest put-OI strike below it. A call wall within 1-2% of spot means the largest call cluster sits close overhead; a put wall 5%+ below spot means the largest put cluster is far away — option-market support is thin nearby from an OI standpoint. Because the snapshot only keeps ATM±10 strikes of the front month, a wall is always reported within that window: it is the busiest strike near spot at last capture, not necessarily the busiest strike across the whole chain.
RangeBoth walls are stated in dollars (the stock price), so the number itself is not bounded. What matters is distance from spot: 0-2% = tight, 2-5% = moderate, 5-10%+ = loose. Two limits cap what can appear: the value is suppressed entirely when it falls outside 0.3x-3x of current spot (feed-glitch filter), and — more restrictively — the stored snapshot only contains the front-month strikes within about ±10 of ATM, so a genuine OI peak farther out than that window can never surface as a wall. A wall reported "5-10%+ away" only shows up if such a strike happens to fall inside that stored window.
The catchOpen interest is reported on a one-day lag, and the snapshot covers only the nearest expiry within ±10 strikes of ATM — so a large OI peak in a later expiry or far from spot is invisible to this metric. Combined with the dealer-vs-customer ambiguity noted above, the wall is best read as "where near-the-money front-month OI is clustered right now," not as a guaranteed price level.
Dealer gamma regime
How it's calculatedNightly (`bi-optanalytics.timer`, 03:00 UTC), pure recompute over stored chain data — no live fetch. For each strike in `chain_json`, Black-Scholes gamma is computed from the stored implied vol, spot price, the live 10Y risk-free rate (fetched once per run from the FRED macro store, falling back to 0.045 if unreachable), and time to the nearest expiry. Dealer net GEX = Σ(BS_gamma × call_OI) − Σ(BS_gamma × put_OI), then scaled to dollar-gamma per 1% spot move (× 100 contract multiplier × S² × 0.01). Sign convention follows SqueezeMetrics: dealers assumed long calls / short puts. Positive sum → `long` regime; negative → `short`; zero → `flat`. Stored as `gex_regime` + `gex_total` on `IntelOptionsChainSnapshot`; surfaced via `/positioning` chain block. Code: `backend/scripts/recompute_options_analytics.py:88-135` (computation), `:167` (risk-free rate); model field: `backend/app/models/intel.py:293-294`; display: `backend/app/qtick/services/ticker_service.py:3143-3157`; frontend: `qtick/frontend/src/lib/data/map/gamma.ts:19-20`.
How it affects judgementTells you what the options market structure is doing to vol, NOT where price is going. In short-gamma (negative GEX), dealer hedging flows WITH price — up moves get bought into by dealers, down moves get sold into, so intraday swings tend to run farther and mean-reversion is weaker. That tightens stop placement and widens expected-move bands in your thesis. In long-gamma, dealer flows lean against the move, compressing realized vol and favouring range-bound scenarios. A regime flip from long to short mid-thesis is a signal to re-examine any assumption that relied on a quiet, pinned tape.
What the current value signifiesThe display shows one of three states: "Dampens moves" (long-gamma, positive GEX — dealers act as a vol shock-absorber, price tends to pin near high-OI strikes), "Amplifies moves" (short-gamma, negative GEX — dealer hedging accelerates swings, the UI flags this with a caution tone), or "Neutral" (flat). The sub-label renders the magnitude as a dollar amount per 1% spot move (e.g. "net $4.2M/1% move"), which lets you gauge how meaningful the regime is — a $200k GEX on a mega-cap is structurally flat regardless of sign, while the same sign on a mid-cap with thin OI is more binding.
RangeThree discrete states: long / flat / short (displayed as "Dampens moves" / "Neutral" / "Amplifies moves"). The underlying `gex_total` is a continuous dollar figure ($/1% move) with no fixed ceiling — large-cap, high-OI names can reach hundreds of millions; small-caps often sit in the low millions or flip sign intraday on thin chain data. There is no normalized 0-100 scale; the regime label is the primary read and `gex_total` is the intensity gauge. Across the 1,803-symbol universe the nightly run prints long/short counts to its log (flat is not tallied), so coarse base-rate context exists in logs but is not persisted or displayed on the card.
The catchThe computation uses the nearest-expiry chain only and assumes dealers are uniformly long calls / short puts — a standard SqueezeMetrics-style approximation that breaks down when a significant dealer position is short calls or long puts (e.g. after a large structured-product unwind). It also refreshes once nightly, so an intraday OI shift (pre-earnings hedging, a block print) won't be reflected until the next 03:00 UTC run.
IV skew
How it's calculatedWe take the implied volatility of the nearest-strike put at ~5% below spot and subtract the IV of the nearest-strike call at ~5% above spot, then express the gap in percentage points. The label says "25-delta," but the value shown on this card (options_snapshot_service.py:89-103) uses ±5% strike distance as a proxy for delta, picking the closest available strike on each side. A true Black-Scholes 25-delta engine exists separately in greeks.py (iv_skew_25delta) but feeds stock-analysis runs, not this Ownership card.
How it affects judgementA persistent put-skew makes downside protection more expensive than upside bets, which can corroborate a bearish thesis or show that someone is paying up to hedge. A call-skew (negative reading) means options demand leans toward the upside, which can soften a bearish case or add weight to a bullish one — though neither direction is decisive on its own. Cross-check it against the put/call OI ratio and the GEX regime before treating it as confirmatory.
What the current value signifiesPositive means the market pays a premium for crash protection relative to upside bets (a defensive lean). Negative means call IV exceeds put IV (an upside-demand lean). Values near zero mean roughly symmetric pricing of fear and greed. Readings beyond ±5 pp are elevated; beyond ±10 pp are rare and point to either a strong fear bid or an unusual upside chase.
RangeExpressed in percentage points (pp). Typical calm-market range runs about -3 to +8 pp. Equity index skew tends to sit positive (puts pricier than calls); individual stocks can flip negative briefly. Extreme fear events can push single-name skew past +15 pp; a sustained call-skew below -5 pp is uncommon outside takeover targets or speculative single-name episodes.
The catchThe displayed value uses ±5% strikes as a delta proxy, not actual 25-delta options — so on stocks with sparse chains or wide strike spacing, the picked strikes can land far from 0.25 delta, making the number unreliable as a true skew measure. Separately, the live Positioning card renders this same underlying field with the opposite sign convention (positive labeled "upside demand"/bullish at ticker_service.py:3129-3137), which contradicts this card's positive=defensive reading — that is a code bug, not a measurement caveat, so don't compare the two cards' tones for the same number until it's fixed.