Docs
GET /v2/gex/{symbol}/history

Every GEX capture of one session

gex_getHistory

Every capture of one exchange session, oldest first, each shaped like a GET /v2/gex/{symbol}/grid response. Use it to replay how dealer gamma exposure moved through a day.

Path parameters

symbol string required

Underlying symbol, e.g. SPY

Query parameters

date string ISO date

Exchange session to read, ISO YYYY-MM-DD (required).

from string

Window start, HH:MM exchange time (ET) on date, inclusive. Default: the start of the day.

to string

Window end, HH:MM exchange time (ET) on date, exclusive. Default: the end of the day.

by_expiry boolean

true returns one row per (strike, expiry) instead of one net row per strike.

top integer · int32

Keep only the N strikes with the largest absolute gex in each capture. Requests with an API key that omit it get top=20.

Details

from and to narrow the result to a window of the day; meta.session_open and meta.session_close give that date's regular session (09:30 and 16:00, or 13:00 on a half day). net_gex always covers the full curve, before any top trim.

Units

  • gex, net_gex and delta_adj are dollars of dealer hedging per $1 move in the underlying (calls positive, puts negative).
  • Share-denominated GEX is dollar GEX ÷ the capture's spot, using prior_close_spot when spot is null. Delta-adjusted shares are delta_adj ÷ the same price.
  • strike is in integer thousandths of a dollar (600000 = $600.00); call_oi and put_oi are contracts.
  • spot, prior_close_spot and flip_point are dollars; captured_at is epoch milliseconds.

GEX on this route is in dollars. For shares or delta-adjusted figures and how to convert, see Units: dollars, shares and delta-adjusted.

Freshness

A new capture lands every 5 minutes during the session. A past session never changes, so its response carries a strong ETag and answers If-None-Match with 304 Not Modified; today's session is not cached.

Limits

A full session is large (SPY untrimmed is about 14 MB). Requests with an API key that send no top get top=20 (about 0.7 MB for SPY), echoed as meta.top with meta.top_defaulted: true; send an explicit top for more or fewer strikes, and from/to to narrow further. No other per-operation limit applies.

Empty results

A weekend, a holiday, a symbol without GEX coverage, or a window with no capture returns 200 with captures: [].

Example

http
GET /v2/gex/SPY/history?date=2026-09-24&top=1
json
{
  "data": {
    "symbol": "SPY",
    "session_date": "2026-09-24",
    "captures": [
      {
        "captured_at": 1790253412446,
        "spot": 763.36,
        "prior_close_spot": 767.18,
        "net_gex": -1241673953.06,
        "flip_point": null,
        "strikes": [
          {
            "strike": 760000,
            "gex": -230644255.65,
            "call_oi": 65552,
            "put_oi": 164210,
            "delta_adj": -60586711.02
          }
        ]
      }
    ]
  },
  "meta": {
    "capture_count": 12,
    "session_open": "09:30",
    "session_close": "16:00",
    "top": 1
  }
}

Response

Prices are dollars, timestamps epoch milliseconds, strikes integer thousandths of a dollar; null means unknown. Units →

200application/json

{symbol, session_date, captures[]} in data; each capture is {captured_at, spot, prior_close_spot, net_gex, flip_point, strikes[]} with the grid's units and row shape. from/to (ET HH:MM) narrow the bundle to the half-open [from, to) window on captured_at; both default to the whole calendar day. A session with no captures — a weekend, a holiday, a symbol the engine does not cover, or a window nothing was captured in — is captures: [], never synthesized. meta.session_open/meta.session_close carry the exchange calendar's regular session for that date (null on a non-trading date). Past sessions carry a strong ETag (over the window and the body) and honour If-None-Match with 304; today's session is uncached.

object

A successful response: the payload consumers parse plus response metadata. data shapes are the platform types — never reshaped by the envelope.

data object required

The session bundle: one symbol, one ET session, every capture.

captures array<GexHistoryCapture> required
captured_at integer · int64 required epoch ms

Epoch ms; ascending across captures.

flip_point number · double nullable

null unless the cumulative net actually crosses zero.

net_gex number · double required USD

Per-$1-move dollars, summed over the full curve (before any top trim).

prior_close_spot number · double nullable USD

Previous session's close, dollars.

spot number · double nullable USD

Underlying price the capture was valued at, dollars.

strikes array<GexGridStrike> required
call_oi integer · int32 nullable

Call open interest, contracts.

delta_adj number · double nullable $ per $1 move

Delta-adjusted exposure, dollars per $1 move. null on older historical rows captured before the field existed.

expiry string · date nullable ISO date

Present only with by_expiry=true.

gex number · double required $ per $1 move

Net dealer gamma exposure at this strike, dollars per $1 move (calls positive, puts negative).

gex_0dte number · double nullable

The part of gex from the nearest (0DTE) expiry, when known.

put_oi integer · int32 nullable

Put open interest, contracts.

strike integer · int64 required 1/1000 $

Strike in integer thousandths of a dollar (exact OSI unit)

session_date string · date required ISO date
symbol string required
meta object required

Response metadata.

caps object nullable

meta.caps — the entitlement caps that shaped this response. applied lists the caps that actually changed it (for example range_clamped).

applied array<string> required

Which caps actually shaped this response (e.g. range_clamped). Empty = nothing was clamped.

darkpool boolean nullable

Whether this account can use Off-Exchange in the site.

flow boolean nullable

Whether the OPRA option-flow capability (flow) is granted to this principal in the app: site Pro plus a CBOE non-professional attestation (never on an itm_ key). Emitted explicitly — true and false — by the account endpoints, so the app reads the grant instead of inferring it from tier and attestation; absent on routes that do not report it.

gexDepth string nullable

GEX data depth when the route reports it. Camel-cased to match the browser capability bundle; absent on unrelated routes.

tier string required

The tier the request was served under.

cursor string nullable

Opaque continuation cursor (pass back as ?cursor=); absent when there is nothing more to read.

plane string nullable

Which serving tier answered the read (meta.plane). Informational provenance: treat it as an opaque label, because new values may appear.

Errors

Every error is the JSON error envelope; branch on error.code.

StatusMeaning
400

invalid_params — missing/bad date, a date in the future, top < 1, a malformed from/to, or from >= to

401

unauthenticated / token_expired

403

not_entitled_tier / attestation_required / not_entitled_symbol

502

internal — the db source failed upstream

503

internal — the db source is not configured here