Historical API Historical GEX
ALPHA TIER HISTORICAL

Historical GEX Data API

Query gamma exposure by strike at any minute since April 2018. Same response shape as the live /v1/exposure/gex endpoint — just add an at= timestamp to replay GEX, gamma flip, call/put walls, and dealer hedging from any historical moment.

Coverage
2018-04-16 → 2026-04-02
Granularity
1 minute
Dataset Size
6.7B option rows
Format
JSON (REST)
New to GEX? What is gamma exposure? covers the formula and dealer hedging mechanics. For backtest patterns: backtesting GEX-regime strategies.

Endpoint

GET /v1/exposure/gex/{symbol}?at=...
Host: historical.flashalpha.com Auth: X-Api-Key Tier: Alpha

Parameters

NameInRequiredDefaultDescription
symbolpathyesUnderlying symbol (e.g. SPY)
atqueryyesAs-of timestamp. yyyy-MM-ddTHH:mm:ss for minute resolution, or yyyy-MM-dd (defaults to 16:00 ET close). Treated as ET wall-clock.
expirationquerynoallFilter to a single expiry (yyyy-MM-dd)
min_oiqueryno0Minimum open interest threshold

The at Parameter

Every historical endpoint hangs off at — the as-of timestamp. Greeks and spot are stored at 1-minute resolution (9:30→16:00 ET) and resolved with a LATEST ON per-contract query, so any at within the trading day returns the contract state as of that minute. Open interest is EOD and applies to all intraday timestamps for that day.

curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://historical.flashalpha.com/v1/exposure/gex/SPY?at=2020-03-16T15:30:00"
import httpx, pandas as pd
from tqdm import tqdm

# Replay net GEX at 15:30 ET for every trading day in 2024
dates = pd.bdate_range("2024-01-02", "2024-12-31")
rows  = []
for d in tqdm(dates):
    at = d.strftime("%Y-%m-%dT15:30:00")
    r  = httpx.get(
        f"https://historical.flashalpha.com/v1/exposure/gex/SPY?at={at}",
        headers={"X-Api-Key": "YOUR_API_KEY"}, timeout=10
    )
    if r.status_code == 200:
        j = r.json()
        rows.append({"date": d, "net_gex": j["net_gex"], "flip": j["gamma_flip"]})
df = pd.DataFrame(rows)
const at = "2020-03-16T15:30:00";  // COVID crash, 15:30 ET
const r  = await fetch(
  `https://historical.flashalpha.com/v1/exposure/gex/SPY?at=${at}`,
  { headers: { "X-Api-Key": "YOUR_API_KEY" } }
);
const j = await r.json();
console.log(`Net GEX: $${j.net_gex.toLocaleString()}`);
console.log(`Regime:  ${j.net_gex_label}`);
console.log(`Flip:    ${j.gamma_flip}`);

Response

Identical shape to the live /v1/exposure/gex endpoint, with two extra fields (as_of, as_of_requested) that echo the resolved timestamp.

{
  "symbol": "SPY",
  "underlying_price": 246.01,
  "as_of": "2020-03-16T15:30:00",
  "as_of_requested": "2020-03-16T15:30:00",
  "gamma_flip": 270.92,
  "net_gex": -2633970601,
  "net_gex_label": "negative",
  "strikes": [
    {
      "strike": 240,
      "call_gex": 145210000,
      "put_gex": 88420000,
      "net_gex": 233630000,
      "call_oi": 14211,
      "put_oi": 38820,
      "call_volume": 0,
      "put_volume": 0,
      "call_oi_change": null,
      "put_oi_change": null
    }
  ]
}

Field gaps vs live: call_volume / put_volume are always 0 (minute-resolution table doesn't carry sizes); call_oi_change / put_oi_change are null (no prior-day OI join yet).

What This Unlocks

  • Backtest GEX-regime strategies — pull regime labels at 15:30 ET for every day in your test window, join forward returns, measure edge. Walkthrough →
  • Replay specific events — what did dealer positioning look like at 15:30 ET on the COVID crash (2020-03-16, -12%)? GameStop squeeze (2021-01-27)? SVB collapse (2023-03-13)?
  • Train ML models on minute-level GEX features without lookahead bias — every at resolves with point-in-time semantics.
  • Validate GEX research from blogs / papers against the actual historical sequence.
  • Build dashboards that overlay historical gamma flip vs price for any day or window.

Coverage — Supported Tickers

Live coverage pulled from GET /v1/tickers. Additional symbols backfill on demand for Alpha customers (typically <48h).

SymbolFirst dateLast dateHealthy daysTotal days
SPY 2018-04-16 2026-04-02 1,972 2,909

(Coverage table fell back to last-known snapshot — live /v1/tickers was unreachable at render time.)

Errors

StatusCodeWhen
400invalid_atat missing or wrong format
400invalid_expirationexpiration not yyyy-MM-dd
401Missing or invalid X-Api-Key
403tier_restrictedPlan below Alpha
404no_data(symbol, at) outside coverage window or in a gap
429rate_limitedDaily quota exhausted (shared with live API)

Why Historical GEX Is Hard to Find

Most GEX dashboards show live exposure — useful for today, useless for backtests. The few vendors who store history typically keep EOD aggregates, which collapse the intraday flip and ruin any signal that depends on knowing where dealers stood at 14:00 ET vs 15:30 ET. FlashAlpha's historical service stores minute-level greeks per contract, so the GEX you query at 14:00 on 2020-03-16 is computed from the actual greeks and spot at that minute — not interpolated, not stamped with the close. More on why this is rare →

Ready to build?

Get your free API key and start pulling live options data in 30 seconds.