The Endpoint
GET https://lab.flashalpha.com/v1/exposure/zero-dte/{symbol}
Requires the Growth plan ($299/mo) or higher. Auth via X-Api-Key header. One parameter: the underlying symbol (SPY, QQQ, SPX, TSLA, etc.).
import requests
resp = requests.get(
"https://lab.flashalpha.com/v1/exposure/zero-dte/SPY",
headers={"X-Api-Key": "YOUR_API_KEY"}
)
data = resp.json()
The response contains 10 top-level sections. Let's walk through each one.
1. Context — Time and Market State
Every 0DTE decision depends on where you are in the trading day. These fields tell you:
| Field | Type | Description |
underlying_price | number | Current spot price of the underlying |
expiration | string | Today's 0DTE expiry date (yyyy-MM-dd) |
market_open | bool | Whether the market is currently open |
time_to_close_hours | number | Hours until 4:00 PM ET — the most important 0DTE context variable |
time_to_close_pct | number | Percentage of trading day elapsed (0 = open, 100 = close) |
print(f"SPY @ ${data['underlying_price']}")
print(f"Time to close: {data['time_to_close_hours']:.1f}h ({data['time_to_close_pct']:.0f}% elapsed)")
2. Gamma Regime
The regime object tells you whether dealers are suppressing or amplifying moves — the single most important intraday signal.
| Field | Description |
regime.label | positive_gamma (dealers dampen moves), negative_gamma (dealers amplify), or undetermined |
regime.gamma_flip | Price where 0DTE net GEX crosses zero — the key intraday pivot |
regime.spot_vs_flip | "above" or "below" the flip point |
regime.spot_to_flip_pct | Distance from spot to gamma flip as a percentage |
Trading Rule
Above the gamma flip: expect range-bound, mean-reverting action — fade moves toward high-GEX strikes. Below the flip: expect trending, volatile moves — trade breakouts, not mean reversion.
regime = data["regime"]
print(f"Regime: {regime['label']}")
print(f"Gamma flip: ${regime['gamma_flip']}")
print(f"Spot is {regime['spot_vs_flip']} flip by {regime['spot_to_flip_pct']:.2f}%")
3. Exposure Aggregates
The exposures object gives you the 0DTE Greek exposure totals and how they compare to the full options chain.
| Field | Description |
net_gex | Net 0DTE gamma exposure in dollars |
net_dex | Net 0DTE delta exposure |
net_vex | Net 0DTE vanna exposure |
net_chex | Net 0DTE charm exposure |
pct_of_total_gex | 0DTE GEX as % of full-chain GEX — above 50% means 0DTE dominates intraday |
total_chain_net_gex | Full-chain net GEX for comparison |
exp = data["exposures"]
pct = exp["pct_of_total_gex"]
print(f"0DTE Net GEX: ${exp['net_gex']:,.0f}")
print(f"0DTE accounts for {pct:.1f}% of total GEX")
if pct > 50:
print("→ 0DTE dominates — use 0DTE levels for intraday trading")
else:
print("→ Full chain dominates — check /v1/exposure/levels for broader levels")
Per-Strike GEX Calculation
$$ GEX_k = \sum_{j \in \text{0DTE}} \Gamma_{k,j} \times OI_{k,j} \times 100 \times S^2 $$
4. Expected Move
The expected_move object gives you the market-implied range for the rest of the day — it shrinks in real-time as the close approaches.
| Field | Description |
implied_1sd_dollars | Full-day 1σ expected move (from open) |
implied_1sd_pct | Same as above, in percent |
remaining_1sd_dollars | Remaining 1σ expected move from now until close |
remaining_1sd_pct | Same as above, in percent |
upper_bound | Current price + remaining 1σ move |
lower_bound | Current price − remaining 1σ move |
straddle_price | ATM 0DTE straddle mid — the market's direct expected move price |
atm_iv | 0DTE at-the-money implied volatility (decimal) |
Remaining Expected Move
$$ E[\text{move}] = S \cdot \sigma_{\text{ATM}} \cdot \sqrt{\frac{t_{\text{remaining}}}{252}} $$
em = data["expected_move"]
print(f"Expected range: ${em['lower_bound']:.2f} – ${em['upper_bound']:.2f}")
print(f"Remaining 1σ: ±${em['remaining_1sd_dollars']:.2f} ({em['remaining_1sd_pct']:.2f}%)")
print(f"Straddle price: ${em['straddle_price']:.2f}")
5. Pin Risk
The pin_risk object quantifies the probability of price being "pinned" to a high-OI strike near the close.
| Field | Description |
magnet_strike | Strike with strongest gravitational pull |
magnet_gex | GEX at the magnet strike |
distance_to_magnet_pct | How far spot is from the magnet (percentage) |
pin_score | 0–100 composite score — above 70 is high conviction |
max_pain | Strike minimizing total option holder intrinsic value |
oi_concentration_top3_pct | What percentage of total 0DTE OI sits in the top 3 strikes |
The pin score composites four factors:
- OI Concentration (30%) — top 3 strikes' share of total 0DTE OI
- Magnet Proximity (25%) — how close spot is to the highest-GEX strike
- Time Remaining (25%) — pin risk increases as expiration approaches
- Gamma Magnitude (20%) — higher gamma = stronger hedging force toward the pin
Max Pain
$$ K^* = \arg\min_{K} \left[ \sum_{i} OI_i^C \cdot \max(S - K_i, 0) + \sum_{j} OI_j^P \cdot \max(K_j - S, 0) \right] $$
pin = data["pin_risk"]
print(f"Magnet Strike: ${pin['magnet_strike']}")
print(f"Pin Score: {pin['pin_score']}/100")
print(f"Max Pain: ${pin['max_pain']}")
print(f"Distance to magnet: {pin['distance_to_magnet_pct']:.2f}%")
print(f"Top 3 OI concentration: {pin['oi_concentration_top3_pct']}%")
if pin["pin_score"] > 70 and data["time_to_close_hours"] < 2:
print("→ HIGH PIN RISK — price likely gravitates to magnet strike")
6. Dealer Hedging Estimates
The hedging object estimates how many shares dealers must trade to delta-hedge their 0DTE positions for various price move scenarios.
| Field | Description |
spot_up_half_pct | Hedging for a +0.5% move |
spot_down_half_pct | Hedging for a −0.5% move |
spot_up_1pct | Hedging for a +1.0% move |
spot_down_1pct | Hedging for a −1.0% move |
Each scenario returns dealer_shares_to_trade, direction (buy/sell), and notional_usd. In positive gamma, dealers sell into rallies and buy dips (liquidity providers). In negative gamma, they chase price (liquidity takers).
for scenario, label in [("spot_up_half_pct", "+0.5%"), ("spot_down_half_pct", "-0.5%"),
("spot_up_1pct", "+1.0%"), ("spot_down_1pct", "-1.0%")]:
h = data["hedging"][scenario]
print(f"If SPY moves {label}: dealers {h['direction']} {abs(h['dealer_shares_to_trade']):,} shares (${abs(h['notional_usd']):,.0f})")
7. Theta Decay & Gamma Acceleration
The decay object captures the non-linear time decay of 0DTE options — theta bleeds slowly in the morning and accelerates dramatically into the close.
| Field | Description |
net_theta_dollars | Total 0DTE theta in dollars |
theta_per_hour_remaining | Theta divided by hours remaining — accelerates as denominator shrinks |
gamma_acceleration | 0DTE ATM gamma / 7DTE ATM gamma — typically 2–5×, can hit 10×+ near close |
charm_regime | E.g. time_decay_dealers_buy — direction of charm-driven hedging |
charm_description | Human-readable charm interpretation |
ATM Gamma Acceleration
$$ \Gamma_{\text{ATM}} \propto \frac{1}{\sqrt{T}} \quad \Longrightarrow \quad \frac{\Gamma_{0\text{DTE}}}{\Gamma_{7\text{DTE}}} \approx \sqrt{\frac{7 \times 6.5}{t_{\text{remaining}}}} $$
decay = data["decay"]
print(f"Net Theta: ${decay['net_theta_dollars']:,.0f}")
print(f"Theta/Hour: ${decay['theta_per_hour_remaining']:,.0f}")
print(f"Gamma Acceleration: {decay['gamma_acceleration']}x vs 7DTE")
print(f"Charm: {decay['charm_description']}")
Optimal Premium Selling Window
Enter when gamma_acceleration is above 2× but time_to_close_hours is still above 2 — you capture the steepest part of the decay curve while leaving enough time for mean reversion to work.
8. Volatility Context
The vol_context object compares 0DTE implied volatility to longer-dated vol and vanna exposure.
| Field | Description |
zero_dte_atm_iv | 0DTE ATM implied volatility (%) |
seven_dte_atm_iv | 7DTE ATM implied volatility (%) |
iv_ratio_0dte_7dte | Ratio: <1.0 = 0DTE is "cheap"; >1.0 = event premium |
vix | Current VIX level |
vanna_exposure | 0DTE vanna exposure in dollars |
vanna_interpretation | E.g. vol_up_dealers_sell — what happens if vol spikes |
vc = data["vol_context"]
ratio = vc["iv_ratio_0dte_7dte"]
print(f"0DTE IV: {vc['zero_dte_atm_iv']}% | 7DTE IV: {vc['seven_dte_atm_iv']}%")
print(f"Ratio: {ratio:.2f} — {'EVENT PREMIUM' if ratio > 1.0 else 'normal'}")
print(f"Vanna: {vc['vanna_interpretation']}")
9. Flow Data
The flow object provides volume and open interest for 0DTE contracts.
| Field | Description |
total_volume / call_volume / put_volume | 0DTE volume breakdown |
total_oi / call_oi / put_oi | 0DTE open interest breakdown |
pc_ratio_volume | Put/call ratio by volume |
pc_ratio_oi | Put/call ratio by open interest |
volume_to_oi_ratio | >1.0 = heavy day-trading (intraday flow exceeds overnight positioning) |
10. Key Levels & Per-Strike Breakdown
The levels object identifies the most important intraday support and resistance from 0DTE positioning.
| Field | Description |
call_wall / call_wall_gex | Strike with highest call GEX — intraday resistance |
put_wall / put_wall_gex | Strike with highest put GEX — intraday support |
highest_oi_strike | Strike with the most total open interest |
max_positive_gamma | Strike with highest positive net gamma |
max_negative_gamma | Strike with highest negative net gamma |
The strikes array provides per-strike detail for contracts within strike_range of spot. Each strike includes:
{
"strike": 590,
"call_gex": 450000000, "put_gex": -380000000, "net_gex": 70000000,
"call_dex": 12500000, "put_dex": -15000000, "net_dex": -2500000,
"call_oi": 25000, "put_oi": 30000,
"call_volume": 15000, "put_volume": 12000,
"call_iv": 0.18, "put_iv": 0.19,
"call_delta": 0.50, "put_delta": -0.50,
"call_gamma": 0.025, "put_gamma": 0.025,
"call_theta": -1.0, "put_theta": -1.0
}
Putting It All Together — Intraday Signal Builder
Combine the response fields into a single decision framework:
import requests
def get_0dte_signal(symbol, api_key):
resp = requests.get(
f"https://lab.flashalpha.com/v1/exposure/zero-dte/{symbol}",
headers={"X-Api-Key": api_key}
)
d = resp.json()
if d.get("no_zero_dte"):
return {"signal": "no_data", "reason": d["message"]}
regime = d["regime"]["label"]
pin_score = d["pin_risk"]["pin_score"]
pct_total = d["exposures"]["pct_of_total_gex"]
hours_left = d["time_to_close_hours"]
# High-conviction pin setup
if pin_score > 70 and hours_left < 2 and regime == "positive_gamma":
return {
"signal": "PIN_LIKELY",
"target": d["pin_risk"]["magnet_strike"],
"confidence": pin_score,
"range": [d["expected_move"]["lower_bound"], d["expected_move"]["upper_bound"]],
"action": "Fade moves toward magnet strike. Sell premium."
}
# Negative gamma breakout risk
if regime == "negative_gamma" and pct_total > 50:
return {
"signal": "BREAKOUT_RISK",
"flip": d["regime"]["gamma_flip"],
"hedging_at_1pct": d["hedging"]["spot_down_1pct"]["notional_usd"],
"action": "Trade breakouts, not mean reversion. Dealers amplify moves."
}
# Default: range-bound with decay
return {
"signal": "RANGE_BOUND",
"walls": [d["levels"]["put_wall"], d["levels"]["call_wall"]],
"theta_per_hour": d["decay"]["theta_per_hour_remaining"],
"action": "Sell premium between put wall and call wall."
}
signal = get_0dte_signal("SPY", "YOUR_API_KEY")
print(signal)
When There Is No 0DTE Expiry
Not every symbol has 0DTE every day. SPY has 0DTE on Mon/Wed/Fri. SPX (SPXW) has daily 0DTE. When there is no 0DTE expiry today, the API returns:
{
"symbol": "SPY",
"no_zero_dte": true,
"message": "No 0DTE expiry for SPY today (Tuesday). Next expiry: 2026-03-18.",
"next_zero_dte_expiry": "2026-03-18"
}
Always check for no_zero_dte before accessing other fields.
Access & Pricing
| Plan | Price | Requests/Day | 0DTE Access |
| Starter (Free) | $0 | 10 | No |
| Basic | $49/mo | 250 | No |
| Growth | $299/mo | 2,500 | Yes |
| Alpha | $1,499/mo | Unlimited | Yes |
View Pricing & Sign Up
Full API Reference
Try It in the Playground
Related Reading