Appearance
GEX
What it computes
Aggregate dealer gamma exposure at the underlying spot, decomposed by strike. The crate emits the per-strike contribution under the canonical SqueezeMetrics sign convention (dealers are net short calls / net long puts):
where Client::connect, 100.0 for US-listed equity options, defaulted server-side to match the standard equity-option contract size). Positive net GEX means dealers are net long gamma (price tends to be pinned); negative net GEX means dealers are net short gamma (moves are amplified). Consumers that want a "dollar gamma per 1 % spot move" scaling apply the per-1 % factor on their side; the engine emits the raw aggregate.
The analytic implements the signed per-contract contribution following the SqueezeMetrics convention.
Methodology
SqueezeMetrics, The GEX Effect (2017). See /methodology/squeeze-metrics for the dealer-positioning convention. Black–Scholes gamma derivation: Hull §19.
Inputs
- The option chain's NBBO quote stream per strike.
- The prior-session option open-interest snapshot hydrated at
Client::connect(see reference data for the boot-time hydration model). - The underlying-spot reference populated from stock NBBO quotes — the same source the Greeks analytic reads from.
Both reference-data surfaces are provisioned by the client at connect time. Callers configure the analytic only through its public knobs (the contract filter and the scalar debounce interval) — every required data dependency is plumbed under the hood.
Contracts without an OI entry, without a spot price, or with an unresolvable IV are skipped — strikes_used reflects only contributing contracts.
Output schema (GexTick)
The field / type / description table below is regenerated from the GexTick Rust source by docs-site/scripts/inject-doc-tables.ts on every npm run docs:build. Do not hand-edit between the sentinels.
| Field | Type | Description |
|---|---|---|
contract | Contract | Resolved underlying contract metadata. Subscribers identify the underlying by (symbol, …) on this field — the wire-level contract id is engine-internal and is not surfaced here. |
date | i32 | Trading-session date in YYYYMMDD form. |
ms_of_day | i32 | Milliseconds-of-day of the emission. |
spot | f64 | Spot price used to scale every contribution. |
net_gex | f64 | Net gamma exposure across every contributing contract. |
call_gex | f64 | Sum of call-side gamma exposures (positive under the SqueezeMetrics convention — dealers are net long calls). |
put_gex | f64 | Sum of put-side gamma exposures (negative — dealers are net short puts). |
strikes_used | u32 | Number of (expiration, strike, right) triples that contributed (i.e. had a resolved γ and an OI hit). |
per_strike | Vec<GexStrikeContribution> | Per-(expiration, strike, right) contributions, sorted lexicographically for deterministic replay. |
zero_gamma_strike | Option<i32> | Approximate zero-gamma strike: the smallest strike on the chain where cumulative GEX (sorted by strike, summed from below) changes sign — on a typical chain the put-dominated low strikes accumulate negative dealer gamma and the call-dominated high strikes flip the running sum positive. None when no crossing exists in the surveyed range (e.g. when every contribution shares a sign). |
Configuration (GexParams)
The caller names the contract universe in the analytic accessor (client.live().gex([...])) — bare symbols expand to the chain plus the underlying — and inherits the standard 100.0 contract multiplier for US-listed equity options as the server-side default. The reference-data dependencies (rate, calendar, the open-interest and spot caches) are wired at Client::connect time and shared with a matched Greeks subscription. The full field set is regenerated from the GexParams Rust source:
| Field | Type | Description |
|---|---|---|
contracts | SecurityFilter | Contracts the subscription tracks. Typically a [SecurityFilter::Symbols] entry naming the underlying roots. |
rate | Arc<dyn RateService> | Risk-free rate provider, shared with the Greeks analytic. |
calendar | Arc<dyn MarketCalendar> | Market calendar provider, shared with the Greeks analytic. |
annual_dividend | Option<f64> | Annual continuously compounded dividend yield. None (default) treats the underlying as non-dividend-paying. |
dividend_cache | `std::sync::Arc<crate::reference_data::dividend_yield:: | |
| DividendYieldCache>` | Engine-wired per-symbol dividend-yield cache. Seated at subscribe time by DefaultSpec via wire_dividend_yield. Consulted on the dispatch path only when annual_dividend is None — the per-tick lookup resolves the continuous-dividend carry yield q = D / S from the live underlying spot the analytic already holds (O(1), lock-light, non-blocking). An explicit annual_dividend override always wins. | |
oi_cache | Arc<OpenInterestCache> | Engine-wide market-wide Option open-interest cache. Build at Client::connect via Client::builder() and clone the resulting Arc into the spec. |
spot_cache | SpotPriceCache | Shared underlying-spot cache, populated by the engine from stock NBBO quotes. The same handle the Greeks analytic reads from. |
contract_multiplier | f64 | Contract multiplier. Default 100.0 for US-listed equity options. |
min_emit_interval_ms | i64 | Minimum interval between emissions, in milliseconds. Defaults to 1_000 (one snapshot per second). |
conditions | ConditionPolicy | Trade-condition admission policy (gates which quote ticks can feed the IV solve). |
venues | ExchangeFilter | Exchange / venue admission policy applied to option quotes. |
iv_cache | IvCacheConfig | IV reuse thresholds for the per-contract γ recompute — the same drift policy the Greeks analytic applies. When the (option_mid, spot) pair drifts below both thresholds the bisection IV solve is skipped and γ is recomputed in closed form from the cached IV; the solver dominates per-quote cost, so the reuse path carries the steady-state throughput. [IvCacheConfig::off] re-solves on every quote. |
Operational characteristics
- Per-tick latency. Incremental per-strike update; emissions debounced by
min_emit_interval_ms. - Open-interest snapshot. Sealed at
Client::connectfrom the prior session's settlement snapshot. Staleness is the caller's responsibility — the snapshot is captured once at boot and pinned for the session. - Allocation discipline. Strike-contribution
Vecis reused across emissions; theGexTickpayload is the only heap allocation per emit. - Replay parity. Deterministic — the open-interest snapshot is immutable post-boot.
Example
rust
// Cargo.toml:
// kairos = "0.1"
use kairos::{Client, GexRow};
let client = Client::connect(("me@example.com", "secret"))?;
let sub = client
.live()
.gex(["QQQ"])
.on_event(|row: &GexRow| {
// The callback fires once per emission with a typed `GexRow`.
println!("net_gex={} spot={}", row.net_gex, row.spot);
})?;
// ... later ...
sub.unsubscribe();