The Endpoint
GET https://lab.flashalpha.com/v1/exposure/zero-dte/{symbol}
Requires the Growth plan ($239/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 every trading day; FlashAlpha's SPX 0DTE coverage is limited (it returns no_zero_dte on days SPX has no same-day expiry). 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 | 5 | No |
| Basic | $63/mo | 100 | No |
| Growth | $239/mo | 2,500 | Yes |
| Alpha | $1,199/mo | Unlimited | Yes |
View Pricing & Sign Up
Full API Reference
Try It in the Playground
Related Reading
The zero-DTE endpoint gives you everything needed to trade same-day expirations with a quantitative edge: gamma regime for direction bias, pin risk for convergence plays, expected move for strike selection, dealer hedging for flow context, and theta acceleration for timing. One API call, one JSON response, all updated in real-time. See the full API reference or try it in the playground.