DEV Community

tomasz dobrowolski
tomasz dobrowolski

Posted on • Originally published at flashalpha.com

Historical Options Data API for Backtesting — Replay GEX, VRP & Dealer Positioning at Any Minute Since 2018

Every serious options project eventually hits the same wall: the live API shows you now, but the questions that actually matter — does this strategy work? what did dealers do during the last drawdown? how did VRP behave before earnings? — all require historical options data.

And historical options data, especially pre-computed historical analytics, is the one thing nobody sells.

FlashAlpha's Historical API changes that. The contract is simple: every live analytics endpoint, replayable at any minute since 2018-04-16, returned in the same response shape. One query parameter — at — and you get what GEX, DEX, VEX, CHEX, VRP, max pain, dealer regime, or the full stock summary looked like at that exact minute in history.


Why Historical Options Analytics Don't Exist Anywhere Else

Go look at the other options data providers. Polygon, ThetaData, ORATS, Intrinio, Tradier — all of them ship raw ticks or end-of-day snapshots. You can reconstruct parts of the analytics layer yourself if you have the time and the pipeline, but you will spend six months writing the join, the BSM pass, the SVI fit, the per-strike aggregation, the regime classifier, the leak-free percentile calculator — and you will still end up with something that only resembles the live product on a good day.

FlashAlpha's Historical API collapses that work into one HTTP call. The same ExposureCalculator, NarrativeBuilder, VrpCalculator, VolatilityAnalyzer, and AdvancedVolatilityCalculator classes that power the live endpoints also power the historical service. Calculator bug-fixes land in both services simultaneously. What you see live, you see historically — exactly the same shape, exactly the same methodology.

Pre-computed historical options analytics require minute-level options quotes with greeks for every strike and expiration, anchored to forward prices, joined to end-of-day open interest, fitted with SVI, and cross-referenced against macro (VIX, VVIX, SKEW, MOVE) — all aligned to the exact timestamp you ask for. The dataset behind it: 6.7 billion option rows, 2 million+ stock minute-bars, daily SVI fits, daily macro. Nobody else assembled this stack.


How the Historical Options API Works: The at Parameter

Every analytics endpoint takes one required query parameter: at. That's your as-of timestamp. Pass it and you get the response as it would have been computed at that minute.

Format Example Semantics
yyyy-MM-ddTHH:mm:ss 2026-03-05T15:30:00 Minute-level as-of. ET wall-clock.
yyyy-MM-dd 2026-03-05 Defaults to 16:00 ET (session close).

Option greeks, bid/ask, stock spot, and everything derived from them are truly intraday — one value per minute from 9:30 to 16:00 ET. Open interest, SVI parameters, and macro are EOD-stamped.

curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://historical.flashalpha.com/v1/exposure/summary/SPY?at=2020-03-16T15:30:00"
Enter fullscreen mode Exit fullscreen mode

One call. Full exposure dashboard — net GEX, net DEX, net VEX, net CHEX, gamma flip, regime label, interpretations, ±1% hedging estimates, 0DTE contribution — as of 15:30 ET on March 16, 2020. The day SPY closed -12%.


Full List of Replayable Historical Options Endpoints

This is not a subset. The Historical API mirrors the live API endpoint-for-endpoint:

Category Endpoint What you replay
Market data /v1/stockquote/{ticker} Stock bid/ask/mid/last at the minute
Market data /v1/optionquote/{ticker} Contract-level quotes + BSM greeks + OI
Market data /v1/surface/{symbol} 50×50 implied-vol surface grid
Exposure /v1/exposure/gex/{symbol} Historical gamma exposure by strike
Exposure /v1/exposure/dex/{symbol} Historical delta exposure by strike
Exposure /v1/exposure/vex/{symbol} Historical vanna exposure by strike
Exposure /v1/exposure/chex/{symbol} Historical charm exposure by strike
Exposure /v1/exposure/summary/{symbol} Full composite dashboard + regime + hedging
Exposure /v1/exposure/levels/{symbol} Gamma flip, call wall, put wall, max gamma
Exposure /v1/exposure/narrative/{symbol} Verbal analysis + prior-day GEX delta + VIX context
Exposure /v1/exposure/zero-dte/{symbol} 0DTE regime, pin risk, expected move, decay
Max pain /v1/maxpain/{symbol} Pain curve, pin probability, dealer alignment
Composite /v1/stock/{symbol}/summary Price, vol, flow, exposure, macro — one response
Volatility /v1/volatility/{symbol} RV ladder, IV-RV spread, skew, term structure
Volatility /v1/adv_volatility/{symbol} SVI params, forwards, total variance, arb flags
VRP /v1/vrp/{symbol} Full VRP dashboard with leak-free percentiles
Coverage /v1/tickers Loaded symbols and date ranges

No Look-Ahead Bias: Leak-Free Historical Percentiles

The feature that most historical options data services get wrong is the one that matters most for backtesting: no future leakage. If you ask FlashAlpha for VRP percentile at 2022-06-14T15:30:00, the percentile is computed only from rows dated before 2022-06-14. The percentile at that moment reflects what was knowable at that moment.

Most backtests silently cheat. If your "historical VRP percentile" uses a percentile computed against the full 2018–2026 dataset, every 2019 observation is scored against knowledge that didn't exist in 2019. That's look-ahead bias. It inflates Sharpe ratios. It makes dead strategies look live.

FlashAlpha's Historical API makes the honest version the default — it's actually harder to cheat than to do it right. Deep dive on leak-free percentiles →


How to Backtest a GEX-Regime Options Strategy With Python

Every strategy that conditions on dealer positioning ("short premium when dealers are long gamma", "fade gaps when GEX is negative", "buy straddles when we cross gamma flip") needs historical regime labels per minute. That's /v1/exposure/summary/{symbol} replayed across your training window.

import httpx, pandas as pd

API_KEY = "..."
dates = pd.bdate_range("2022-01-01", "2024-12-31")
rows = []
for d in dates:
    ts = d.strftime("%Y-%m-%dT15:30:00")
    r = httpx.get(
        "https://historical.flashalpha.com/v1/exposure/summary/SPY",
        params={"at": ts},
        headers={"X-Api-Key": API_KEY},
    ).json()
    rows.append({
        "date": d,
        "net_gex": r["exposures"]["net_gex"],
        "regime": r["regime"],
        "gamma_flip": r["gamma_flip"],
        "spot": r["underlying_price"],
    })

df = pd.DataFrame(rows)
# Join next-day returns, condition on regime, measure edge
Enter fullscreen mode Exit fullscreen mode

That's the full research dataframe. Join forward returns, condition on regime, measure the edge.


Using Historical Dealer Positioning as ML Features

For machine-learning workflows, the Historical API is the feature store you were about to build yourself. Every minute of SPY since 2018-04-16 gives you net GEX, gamma flip distance, VRP z-score, net DEX, 0DTE contribution, vol surface shape, macro regime — about 40 dealer-positioning features per timestamp, all aligned to a single at key.

The numbers:

  • 8 years × 252 trading days × 390 minutes ≈ 786K minute-level sample rows for SPY alone
  • ~40 features per row → roughly 31 million feature observations
  • Walk-forward percentiles and z-scores included — no leakage in your training set

Pull the grid you want — daily close, half-hourly, or every minute — dump to parquet, and feed into XGBoost, a tabular transformer, or whatever architecture you prefer. Before FlashAlpha, assembling this with correct greeks and leak-free percentiles was a multi-engineer, multi-quarter project. Now it's a weekend script.


Historical Options Data Coverage and Pricing

Symbols SPY (more backfill on request)
Date range 2018-04-16 → today (extended each pipeline run)
Option rows 6.7 billion
Stock minute-bars 2 million+
Intraday granularity 1 minute (quotes + greeks + spot)
EOD layer Open interest, SVI params, forwards, macro
Minimum tier Alpha ($1,499/mo)
Base URL https://historical.flashalpha.com

Authentication uses the same X-Api-Key as the live API. GET /v1/tickers returns loaded symbols, date ranges, and any pipeline gaps — self-describing coverage so you never waste a call.


Validate Historically, Deploy Live — Same Response Shape

The historical and live services share the calculator layer. When a bug gets fixed, it's fixed in both places the same day. When a field gets added to the live response, it appears historically too.

That means you can validate strategies historically and deploy them live without a rewrite. Same response shape, same field names, same regime labels, same interpretation text. The deploy is a config flip: swap the base URL from historical.flashalpha.com to api.flashalpha.com and change at to "now."


Known Gaps in Historical Coverage

A small number of live fields aren't reconstructible historically:

  • Minute-level volume: not stored; volume fields return 0. Greeks, bid/ask, and OI all populated normally.
  • VIX futures and CNN Fear & Greed: external sources not archived; return null.
  • Option bid/ask sizes: not carried at minute resolution. Bid/ask prices are populated.
  • Prior-day OI diffs in narrative.top_oi_changes: not computed yet; empty array.
  • svi_vol per contract in /v1/optionquote: SVI params are at the expiry level; implied_vol (BSM) is populated.

None of these affect the core exposure, VRP, or volatility surface workflows.


Get Started With Historical Options Data

Originally published at flashalpha.com.

Top comments (0)