- API Reference
- Exposure Analytics
- Exposure Term Structure
Exposure Term Structure API
Per-greek exposure aggregated by DTE bucket and also rolled up per expiry, returning in one call the same shape as four full-chain exposure requests, grouped by time.
Endpoint
X-Api-Key)
Rate Limited: Yes
Growth plan+
Parameters
| Name | In | Required | Default | Description |
|---|---|---|---|---|
symbol |
path | yes | - | Underlying symbol |
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://lab.flashalpha.com/v1/exposure/term-structure/SPY"
import requests
resp = requests.get(
"https://lab.flashalpha.com/v1/exposure/term-structure/SPY",
headers={"X-Api-Key": "YOUR_API_KEY"}
)
data = resp.json()
for b in data["by_dte_bucket"]:
print(f"{b['bucket']}: net GEX {b['net_gex']:,}")
const resp = await fetch(
"https://lab.flashalpha.com/v1/exposure/term-structure/SPY",
{ headers: { "X-Api-Key": "YOUR_API_KEY" } }
);
const data = await resp.json();
data.by_dte_bucket.forEach(b =>
console.log(b.bucket + ": net GEX " + b.net_gex.toLocaleString()));
Response
{
"symbol": "SPY",
"underlying_price": 771.545,
"as_of": "2026-10-20T15:00:13.2736319Z",
"by_dte_bucket": [
{
"bucket": "0-7d",
"dte_range": [
0,
7
],
"net_gex": 2263386460.457581,
"net_dex": 3668142447.8108096,
"net_vex": -12492467540.83055,
"net_chex": -3575513.0028283484,
"contract_count": 1824
},
{
"bucket": "8-30d",
"dte_range": [
8,
30
],
"net_gex": -2527189885.378595,
"net_dex": -3832623033.601969,
"net_vex": -37271689327.87788,
"net_chex": -561836.8501622429,
"contract_count": 2132
},
{
"bucket": "31-60d",
"dte_range": [
31,
60
],
"net_gex": -826935449.0296762,
"net_dex": 10452606474.0568,
"net_vex": -64477592394.37408,
"net_chex": -307311.1391100585,
"contract_count": 1856
}
],
"by_expiry": [
{
"expiration": "2026-10-20",
"dte": 0,
"is_opex": false,
"is_triple_witching": false,
"net_gex": 2667890538.6361294,
"net_dex": 2945811803.9974084,
"net_vex": -2063750986.3162327,
"net_chex": -2670291.338181202,
"pct_of_chain_gex": 25.5
},
{
"expiration": "2026-10-21",
"dte": 1,
"is_opex": false,
"is_triple_witching": false,
"net_gex": 176274301.48442113,
"net_dex": 688882127.4214486,
"net_vex": -2446060189.9199533,
"net_chex": -362998.5155044674,
"pct_of_chain_gex": 1.68
},
{
"expiration": "2026-10-22",
"dte": 2,
"is_opex": false,
"is_triple_witching": false,
"net_gex": 379252380.44424677,
"net_dex": 512628469.3498911,
"net_vex": 1162052720.325477,
"net_chex": -14409.015712281423,
"pct_of_chain_gex": 3.63
}
],
"gamma_concentration": {
"totals": {
"gross_gex_usd": 48848586864.88095,
"net_gex_usd": -631433267.4420052,
"call_gex_usd": 24108576798.71947,
"put_gex_usd": -24740010066.161476,
"contract_count": 12036
},
"by_expiry": [
{
"expiry": "2026-10-20",
"valuation_cutoff_at": "2026-10-20T20:00:00Z",
"last_trading_at": "2026-10-20T20:15:00Z",
"last_trading_status": "scheduled_regular_session",
"settlement_at": null,
"settlement_status": "unknown",
"calendar_days_to_expiry": 0,
"gross_share_pct": 14.450827249911322,
"gross_gex_usd": 7059024901.866819,
"net_gex_usd": 2667890538.6361294,
"call_gex_usd": 4863457720.251474,
"put_gex_usd": -2195567181.615345,
"contract_count": 196
},
{
"expiry": "2026-10-21",
"valuation_cutoff_at": "2026-10-21T20:00:00Z",
"last_trading_at": "2026-10-21T20:15:00Z",
"last_trading_status": "scheduled_regular_session",
"settlement_at": null,
"settlement_status": "unknown",
"calendar_days_to_expiry": 1,
"gross_share_pct": 5.1896166168198095,
"gross_gex_usd": 2535054381.0215206,
"net_gex_usd": 176274301.484421,
"call_gex_usd": 1355664341.2529707,
"put_gex_usd": -1179390039.7685497,
"contract_count": 231
},
{
"expiry": "2026-10-22",
"valuation_cutoff_at": "2026-10-22T20:00:00Z",
"last_trading_at": "2026-10-22T20:15:00Z",
"last_trading_status": "scheduled_regular_session",
"settlement_at": null,
"settlement_status": "unknown",
"calendar_days_to_expiry": 2,
"gross_share_pct": 3.240858197358899,
"gross_gex_usd": 1583113431.7044764,
"net_gex_usd": 379252380.4442464,
"call_gex_usd": 981182906.0743613,
"put_gex_usd": -601930525.6301149,
"contract_count": 256
}
],
"next_active_expiry": "2026-10-20",
"largest_gross_expiry": "2026-10-30",
"symbol": "SPY",
"underlying_price": 771.545,
"snapshot_id": "576cf4f0913042f16397efde277ec84ac43bd943989197f809852ca977979e6f",
"generated_at": "2026-10-20T15:00:13.2736319Z",
"quote_at": "2026-10-20T15:00:12.966Z",
"greeks_oldest_at": "2026-10-20T14:52:30Z",
"greeks_newest_at": "2026-10-20T15:00:11Z",
"calculation_version": "gamma-context-v2",
"pricing_basis": "captured_cached_gamma_current_spot",
"data_status": "stale",
"reasons": [
{
"code": "expiry_clock_unverified",
"message": "Excluded 302 contract(s): expiry_clock_unverified.",
"contract_count": 302
},
{
"code": "gamma_unavailable",
"message": "Excluded 388 contract(s): gamma_unavailable.",
"contract_count": 388
},
{
"code": "oi_vintage_unknown",
"message": "The source does not carry a verified OI observation date; zero OI is a stored value, not evidence of a completed OI refresh.",
"contract_count": null
}
],
"oi_as_of": null,
"oi_vintage_status": "unknown",
"eligible_contract_count": 12036,
"rejected_contract_count": 690,
"observed_min_strike": 50,
"observed_max_strike": 1480,
"gex_unit": "usd_delta_notional_per_1pct_move",
"sign_convention": "calls_positive_puts_negative",
"analysis_type": "current_distribution"
},
"endpoint_version": "2026.09.30",
"data_as_of": {
"node": "fa4",
"equity_feed": "2026-10-20T15:00:12.966Z",
"equity_options_feed": "2026-10-20T15:00:12Z",
"index_feed": "2026-10-20T15:00:11.131Z",
"index_options_feed": "2026-10-20T15:00:01Z",
"futures_feed": "2026-10-20T15:00:06.476Z",
"futures_options_feed": "2026-10-20T15:00:06.524Z",
"flow_feed": "2026-10-20T14:59:00Z",
"oi_feed": "2026-10-19T20:00:00Z",
"macro_feed": "2026-10-19T21:00:20Z"
}
}
Real response from the live API (2026-10-20 15:00 UTC), with lists shortened to three items. Download the full response (JSON).
Key Response Fields
| Section / Field | Description |
|---|---|
by_dte_bucket[].bucket | Bucket name. Buckets are 0-7d / 8-30d / 31-60d / 61-180d / 180d+. |
by_dte_bucket[].dte_range | Inclusive [lower, upper] DTE bounds (final bucket carries int.MaxValue as the upper bound). |
by_dte_bucket[].net_* | Sum of GEX / DEX / VEX / CHEX over every contract whose DTE falls in the bucket. |
by_dte_bucket[].contract_count | Number of contracts feeding the bucket. |
by_expiry[] | One row per expiry, ordered ascending. is_opex / is_triple_witching use the holiday-adjusted rule. |
by_expiry[].pct_of_chain_gex | This expiry's |net_gex| as a share of Σ |net_gex| across all expiries (0-100). A legacy net-based share, not the gross share in gamma_concentration. |
gamma_concentration | SPY/QQQ: gross and net gamma distribution of the same captured chain (totals, by_expiry[] with gross_share_pct, next_active_expiry, largest_gross_expiry) plus snapshot_id, pricing_basis, data_status and reasons. Other symbols return the block with data_status: "unavailable" and reason unsupported_symbol. Definitions match Expiry Impact. |
Errors
| Status | Description |
|---|---|
403 | Requires Growth plan or higher |
404 | Symbol not found or no data |
About
The term-structure endpoint slices a symbol's options chain by time rather than by strike, aggregating GEX, DEX, VEX and CHEX into standard DTE buckets and rolling the same greeks up per individual expiry. A single call returns what would otherwise require four separate full-chain exposure requests, already grouped along the time axis.
Buckets that match no contracts are omitted rather than emitted as zero rows, and pct_of_chain_gex falls back to 0 for every row when the chain's total |net_gex| is zero (a safe-divide guard). The per-expiry rollup carries OPEX and triple-witching flags so you can spot where the chain's gamma concentration sits in time.
For SPY and QQQ the response also carries gamma_concentration: gross gamma shares by expiry, computed with the same inputs as Expiry Impact and Strike Dependency. Gross shares answer how much gamma each expiry holds; pct_of_chain_gex keeps its legacy net-based definition. For QQQ, values come from the raw-quote common-anchor repricer QQQ GEX uses, so the legacy arrays can be empty while gamma_concentration is populated.
Common Use Cases
- Plot the exposure term-structure curve - the per-DTE-bucket rows draw a gamma curve across the chain so you can see whether positioning is front- or back-loaded in time
- Find the dominant expiry -
pct_of_chain_gexranks each expiry's share of total chain gamma to pinpoint where dealer concentration sits - Separate pinning from structural positioning - isolate the near-dated 0-7d buckets that drive expiry pinning from longer-dated, slower-moving exposure
- Flag event expiries in time - the per-expiry OPEX and triple-witching flags mark where gamma concentration coincides with scheduled unwinds
- Handle sparse buckets safely - empty buckets are omitted rather than zero-filled and
pct_of_chain_gexsafe-divides to0, so charts stay clean on thin chains - Pair with skew and VRP across tenors - read the gamma curve alongside skew term structure and VRP history to align positioning with the vol term structure
Related
Research
gamma_concentration was replayed on every 2022-2025 SPY and QQQ session. Its front-expiry share matched expiry impact on every snapshot, and for SPY concentration across expiries carried some information beyond the expiring share.
- Does expiring gamma move the market? - results and method
- Are covered calls worth it? -
gamma_concentration.totals.net_gex_usdas a covered-call filter across six deltas and five expiries - Research pack
trader-context-spy-qqq-2022-2025-v2-34105d743fac- data, audit and reproduction (Alpha)
Related reading
- GEX/DEX/VEX/CHEX: an 8-year backtest vs VIX - what the exposure greeks predict across the term structure
Complementary endpoints
- Gamma Exposure (GEX) - the per-strike gamma sheet behind each bucket's totals
- Exposure Sheet - the full per-strike greek sheet aggregated here by expiry
- Skew Term Structure - how implied skew evolves across the same tenors
- VRP History - realized-vs-implied premium to frame the term structure