Historical API: Point-in-Time Replay
Ask what GEX, gamma flip, VRP, narrative, max pain, or the full stock summary looked like at any minute in history - returned in the same response shape as the live API. Backed by 6.7 B option rows since April 2018.
What's different from the live API
Every endpoint you already know on the live API is mirrored here. Point your existing SDK at a different host, add one query parameter, and you have a backtest-ready data source. No new response shapes to learn - GEX, gamma flip, regime labels, narrative text, VRP percentiles, SVI surfaces and everything else come back in the exact same JSON you already parse.
The analytics run through the same code path as live - so any fix or refinement that lands on api.flashalpha.com shows up here on the next deploy. The only difference is the data store underneath: minute-level quotes and greeks going back to April 2018 instead of the live feed.
historical.flashalpha.com
X-Api-Key as live. Alpha tier on every endpoint.The at parameter
Every analytics endpoint takes a required at query parameter - the as-of timestamp. Treated as ET wall-clock (same clock as the stored data). Do not shift by UTC offset.
| Format | Example | Semantics |
|---|---|---|
yyyy-MM-ddTHH:mm:ss | 2026-03-05T15:30:00 | Minute-level as-of |
yyyy-MM-dd | 2026-03-05 | Defaults to 16:00 ET (session close) |
Intraday-accurate vs EOD-stamped
Not every underlying series is minute-resolution. Here's what moves at the minute you ask for, and what's stamped at the close of that trade day:
| Data layer | Granularity | Notes |
|---|---|---|
| Option quotes + greeks (bid, ask, iv, δ, γ, θ, ν, ρ, vanna, charm) | 1 minute (9:30 → 16:00 ET) | Last value per contract at or before at |
| Stock spot (bid, ask, mid) | 1 minute | Same |
| Open interest | EOD | One value per trade day, applied to all intraday at= on that day |
| SVI params, forward prices | EOD | |
| Macro: VIX, VVIX, SKEW, MOVE, SPX, VIX9D/3M/6M, DGS10 | EOD | |
| Realized-vol lookback closes (HV20/HV60) | EOD | Last tick per day |
Why this is OK: intraday GEX / DEX / VEX / CHEX shifts are driven by greek + spot changes; OI is dealer-positioning context and barely moves intraday anyway.
Coverage: GET /v1/tickers
The only historical-specific endpoint. Lists every symbol with historical coverage, the date range, and any gaps. Regenerated after every backfill run, so whatever comes back is the current ground truth for what you can query.
Auth: required (X-Api-Key, Alpha tier)
Query params: symbol=SPY (optional) - returns a single object instead of the wrapped list
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://historical.flashalpha.com/v1/tickers"
Response 200:
{
"count": 1,
"tickers": [
{
"symbol": "SPY",
"coverage": {
"first": "2018-04-16",
"last": "2026-04-02",
"total_days": 2909,
"healthy_days": 1972
},
"tables": {
"stocks_days": 2009,
"options_days": 1972,
"option_eod_days": 2006,
"svi_days": 1972
},
"gaps": {
"missing_eod": 3,
"missing_svi": 36,
"uncovered_calendar": 3
},
"updated_at": "2026-04-14T07:07:36.55353"
}
]
}
| Field | Meaning |
|---|---|
coverage.first / coverage.last | Date range where every data layer is healthy - you can query any minute inside this window |
coverage.healthy_days | Trading days on which every data layer has data |
tables.*_days | Per-layer day counts - useful when a single layer is lagging |
gaps.missing_eod | Days where EOD option data hasn't been pulled yet (usually resolves on the next backfill) |
gaps.missing_svi | Days without an SVI fit |
gaps.uncovered_calendar | NYSE trading days that were never pulled (genuine exchange-closed days like 2018-12-05 Bush funeral, 2025-01-09 Carter funeral) |
updated_at | UTC timestamp of the last coverage refresh |
Available symbols. SPY is fully backfilled from 2018-04-16 through 2026-04-02 and extended on every refresh. Additional symbols are backfilled on demand - ask us to prioritize what you need. Live coverage is always queryable at GET /v1/tickers.
Analytics endpoints
Every live analytics endpoint is mirrored with the addition of a required at. Paths, query params, and response shapes are identical to the live docs - don't re-document them here. Click through for the per-endpoint reference:
VRP date-bounding matters. VRP percentile and z-score only consider history prior to at, so at any historical point the percentile reflects only what was knowable at that moment. No future leakage in backtests.
Example: replay March 16, 2020 (COVID crash, -12% close)
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://historical.flashalpha.com/v1/exposure/summary/SPY?at=2020-03-16T15:30:00"
{
"symbol": "SPY",
"underlying_price": 246.01,
"as_of": "2020-03-16T15:30:00",
"gamma_flip": 270.92,
"regime": "negative_gamma",
"exposures": {
"net_gex": -2633970601,
"net_dex": -169419489077,
"net_vex": 152461756844,
"net_chex": -13122349
},
"interpretation": {
"gamma": "Dealers short gamma - moves amplified, trend following likely",
"vanna": "Vol up = dealers buy delta - downside dampened if vol spikes",
"charm": "Time decay pushing dealers to sell - pressure into close"
}
}
Real dealer positioning, at 15:30 ET on the day SPY closed -12%. Not a re-derived reconstruction - these are the minute-level greeks as they were at that moment, run through today's analytics.
Field coverage vs live
Most fields are identical to the live API. These are the exceptions:
| Field | Status on historical | Why |
|---|---|---|
optionquote.bidSize, askSize, volume | Always 0 | Minute-resolution quotes don't carry sizes or volume |
optionquote.svi_vol | Always null with svi_vol_gated: "backtest_mode" | SVI surface available via /v1/adv_volatility; per-contract derivation not yet exposed |
exposure.call_volume, put_volume | Always 0 | No minute volume stored |
exposure.call_oi_change, put_oi_change | Always null | Prior-day OI comparison not yet computed |
narrative.data.top_oi_changes | Always [] | Same - per-strike prior-day OI diff not computed |
0DTE intraday greeks (δ/γ/θ/iv on zero-dte.strikes[]) | Often 0/null | Minute-level greeks on very-near-expiry contracts are still being backfilled; the strike distribution / OI is available |
summary.options_flow.total_*_volume, pc_ratio_volume | Always 0 / null | No minute volume stored |
summary.macro.vix_futures, fear_and_greed | Always null | CME VIX futures curves and CNN Fear & Greed aren't archived historically |
vrp.macro.hy_spread | Hard-coded 3.5 | Historical high-yield spread series isn't loaded yet |
Everything else - greeks, IV, exposures, flip, walls, regime, narrative, VRP percentiles, SVI fits, variance surface, arbitrage flags - is real, computed from the data as it stood at at.
How coverage grows
New trading days and new symbols are added by a gap-aware backfill that runs on a schedule. The coverage window on /v1/tickers is what you can query right now; it extends forward on each refresh. Transient upstream misses self-heal on subsequent runs, so a gap you see today may fill in later - check /v1/tickers before concluding that a specific date is unavailable.
Latency & caching
Point-in-time reads are fast (~50–300 ms typical). Composite endpoints that rebuild surfaces on demand - /v1/adv_volatility and /v1/stock/{symbol}/summary - can take ~500–1500 ms on a cold request for a new (symbol, at). Cache at your proxy or client for repeat queries on the same tuple - responses are deterministic for a given at, so they're safe to cache indefinitely.
Try it live
Point-and-replay - pick an endpoint, pick a minute in history, hit Replay. Works with your existing API key.
Ready to build?
Get your free API key and start pulling live options data in 30 seconds.