A 30DTE option and a 0DTE option share the same ticker but live in completely different universes. With hours — not weeks — until expiration, the Greeks behave differently:
-
Gamma is extreme. ATM gamma scales as
1/√T— when T is measured in hours, not days, gamma is 3–10× higher than weekly options. - Theta decay is non-linear. 0DTE theta bleeds slowly in the morning, doubles by 2 PM, and can hit 5× the morning rate by 3:30 PM.
- Dealers hedge aggressively. Because gamma is so high, every $1 move in the underlying forces dealers to buy or sell significantly more shares than equivalent moves in longer-dated contracts.
- Pin risk is real. With massive OI concentrated in a few strikes, price can be magnetically attracted to high-OI levels as expiration approaches.
This isn't theory — it creates real order flow. When dealers are short 50,000 SPY contracts at the 590 strike and SPY drops $1, they must sell hundreds of thousands of shares to stay hedged. That selling is not discretionary. It's mechanical. And it moves the tape.
The question for every 0DTE trader is: are dealers helping you or hurting you right now?
The Data That Drives Every Strategy
Each strategy below uses specific fields from the Zero-DTE API endpoint. Here's a quick reference for the key signals:
| Signal | What It Tells You | Where to Find It |
|---|---|---|
| Gamma regime | Are dealers dampening moves (positive) or amplifying them (negative)? | regime.label |
| Gamma flip | The price where the regime changes — the key intraday pivot | regime.gamma_flip |
| Pin score | How likely is price to pin to a specific strike near close? (0–100) | pin_risk.pin_score |
| Expected move | How far the market expects price to travel by close | expected_move.remaining_1sd_dollars |
| Call wall / put wall | Intraday resistance and support from dealer gamma |
levels.call_wall, levels.put_wall
|
| Dealer hedging | How many shares dealers must trade for a given move |
hedging.spot_up_1pct, etc. |
| Theta per hour | How fast premium is decaying right now | decay.theta_per_hour_remaining |
| 0DTE % of total GEX | Does 0DTE positioning dominate intraday, or is the full chain in charge? | exposures.pct_of_total_gex |
import requests
resp = requests.get(
"https://lab.flashalpha.com/v1/exposure/zero-dte/SPY",
headers={"X-Api-Key": "YOUR_API_KEY"}
)
d = resp.json()
print(f"Regime: {d['regime']['label']}")
print(f"Gamma flip: ${d['regime']['gamma_flip']}")
print(f"Pin score: {d['pin_risk']['pin_score']}/100")
print(f"Expected move: ±${d['expected_move']['remaining_1sd_dollars']:.2f}")
print(f"Walls: ${d['levels']['put_wall']} support — ${d['levels']['call_wall']} resistance")
print(f"0DTE dominance: {d['exposures']['pct_of_total_gex']:.0f}% of total GEX")
Strategy 1: The Gamma Flip Fade
Condition: regime.label == "positive_gamma" and spot is between put wall and call wall.
When dealers are long gamma, they buy dips and sell rallies to stay delta-neutral. This creates a natural mean-reverting environment — every move toward the call wall gets sold, every dip toward the put wall gets bought. Price oscillates between the two walls.
The trade: Fade moves toward either wall. Buy SPY at the put wall, sell at the call wall — or use options: sell call spreads when price touches the call wall, sell put spreads when price touches the put wall.
regime = d["regime"]
levels = d["levels"]
price = d["underlying_price"]
if regime["label"] == "positive_gamma":
put_wall = levels["put_wall"]
call_wall = levels["call_wall"]
range_width = call_wall - put_wall
dist_to_put = (price - put_wall) / range_width
dist_to_call = (call_wall - price) / range_width
if dist_to_put < 0.2:
print(f"FADE: Near put wall ${put_wall} — dealers buying. Go long, target mid-range.")
elif dist_to_call < 0.2:
print(f"FADE: Near call wall ${call_wall} — dealers selling. Go short, target mid-range.")
else:
print(f"Range: ${put_wall}–${call_wall}. Wait for approach to a wall.")
Entry Timing
The gamma fade works best in the first half of the session (9:45 AM – 1 PM ET) when the walls are well-established and gamma hasn't yet accelerated to extreme levels. By 2 PM, gamma acceleration can make the walls "softer" — dealers still defend them, but the hedging force relative to the move size weakens.
Exit Management
- Target: Mid-range between put wall and call wall. Don't try to ride through to the other wall — take profits at the midpoint.
- Stop: If price closes a 5-minute candle beyond the wall by more than 0.3%, the wall has broken. Exit immediately.
- Time stop: If the trade hasn't moved in your direction within 30 minutes of entry, exit at scratch. 0DTE doesn't give you time to wait.
-
Regime change: If the API shows the regime has flipped to
negative_gamma, exit regardless of P&L — the thesis is invalidated.
Real-World Example
SPY opens at $590.40. The API shows positive gamma regime with put wall at $588 and call wall at $593. At 10:30 AM, SPY dips to $588.20 — approaching the put wall. You buy SPY (or a $588 call) targeting $590.50 (mid-range). Dealers are buying at the put wall, providing natural support. SPY bounces to $590.80 by 11:15 AM. You take profit at $590.50 — $1.80/contract, defined risk, and the mechanics were in your favor the entire time.
When this fails: If an exogenous catalyst (FOMC, CPI, breaking news) hits, the gamma flip can shift rapidly and the walls break. Check vol_context.iv_ratio_0dte_7dte — if it's above 1.0, the market is pricing an event and the walls are less reliable.
Strategy 2: The Pin Play
Condition: pin_risk.pin_score > 70 and time_to_close_hours < 2.
When massive OI is concentrated in a few strikes and expiration is approaching, price tends to get "pinned" to the magnet strike. Dealers continuously hedge around it, and max pain convergence pulls price toward the point of minimum option holder intrinsic value.
The trade: Sell an ATM straddle or tight iron butterfly at the magnet strike. You profit if price stays near the pin. The expected move narrows as close approaches — your risk shrinks with time.
pin = d["pin_risk"]
hours_left = d["time_to_close_hours"]
em = d["expected_move"]
if pin["pin_score"] > 70 and hours_left < 2:
magnet = pin["magnet_strike"]
distance = pin["distance_to_magnet_pct"]
print(f"PIN SETUP: Magnet at ${magnet} (pin score: {pin['pin_score']}/100)")
print(f"Spot is {distance:.2f}% from magnet")
print(f"Remaining expected move: ±${em['remaining_1sd_dollars']:.2f}")
print(f"OI concentration (top 3): {pin['oi_concentration_top3_pct']}%")
print(f"→ Sell butterfly/straddle at ${magnet}. Target pin into close.")
else:
print(f"Pin score: {pin['pin_score']}/100 — not high enough for pin play")
What Makes a Good Pin Setup
Not all high pin scores lead to successful pins. The best setups have these characteristics:
- Single dominant magnet strike. When OI is concentrated at one strike (e.g., the round number $590) rather than spread across $588/$589/$590/$591, the pin is stronger.
-
Max pain and magnet strike align. When
pin_risk.max_painequalspin_risk.magnet_strike, both the hedging force and the intrinsic value minimization point converge on the same level. - Positive gamma regime. Pinning requires mean reversion — dealers buying dips and selling rallies around the magnet. In negative gamma, there's no mean-reverting force to hold price at the strike.
- Low realized vol. A quiet tape lets the pin mechanics work. If realized intraday vol is spiking, the pin force may not be strong enough to overcome momentum.
Exit Management
- Take profit early. You don't need to hold to expiry. If price converges to within $0.25 of the magnet strike with 30+ minutes left, take 70% of max profit and close.
- Cut on wall break. If price breaks beyond the call wall or put wall, the pin has failed. Exit the butterfly at market.
- Pin score monitoring. The pin score updates in real-time. If it drops below 50 (e.g., a large block trade shifts OI), exit — the setup has deteriorated.
Strategy 3: The Negative Gamma Breakout
Condition: regime.label == "negative_gamma" and exposures.pct_of_total_gex > 50.
Negative gamma is the opposite of Strategy 1. Dealers are short gamma — they must sell into drops and buy into rallies, amplifying moves in both directions. The market trends, doesn't mean-revert. Fading is dangerous here.
The trade: Trade breakouts. Buy momentum in the direction of the move. Use the gamma flip as your trigger — a break below the flip accelerates downside as dealers switch from buyers to sellers.
regime = d["regime"]
exp = d["exposures"]
if regime["label"] == "negative_gamma" and exp["pct_of_total_gex"] > 50:
flip = regime["gamma_flip"]
price = d["underlying_price"]
print(f"⚠ NEGATIVE GAMMA — dealers amplify moves")
print(f"Gamma flip: ${flip}")
print(f"Spot: ${price} ({'below' if price < flip else 'above'} flip)")
# How much selling on a 1% drop?
hedge_down = d["hedging"]["spot_down_1pct"]
print(f"If SPY drops 1%: dealers {hedge_down['direction']} {abs(hedge_down['dealer_shares_to_trade']):,} shares")
print(f" Notional: ${abs(hedge_down['notional_usd']):,.0f}")
print(f"→ Trade breakouts, not mean reversion. Watch the flip.")
The Gamma Flip as a Trigger
The most powerful negative gamma signal is a break through the gamma flip. Above the flip, dealers are net long gamma (dampening). Below it, they're net short (amplifying). The transition creates a cascade:
- Price drops through the gamma flip
- Dealers flip from buying to selling
- Their selling pushes price further down
- More gamma is exposed, creating more selling
- The move accelerates until it hits a structural level (full-chain put wall, major OI strike)
Trade Structures for Breakouts
- Directional puts/calls. Buy ATM puts on a break below the flip. The negative gamma amplification gives you a momentum tailwind.
- Put debit spreads. Buy the ATM put, sell a put at the full-chain put wall. Defined risk, captures the move between the flip and support.
- Avoid selling premium. In negative gamma, short premium positions get destroyed by the amplification effect. Don't sell iron condors here.
Strategy 4: The Theta Harvest
Condition: regime.label == "positive_gamma", decay.gamma_acceleration > 2, and time_to_close_hours > 2.
0DTE theta decay is non-linear. The optimal window for premium selling is when gamma acceleration has kicked in (premium is decaying fast) but there's still enough time for mean reversion to protect you if price moves against. Typically 1–3 PM ET.
The trade: Sell an iron condor with short strikes at the call wall and put wall. The positive gamma regime means dealers are actively pushing price back toward center. Time decay accelerates in your favor.
decay = d["decay"]
regime = d["regime"]
hours_left = d["time_to_close_hours"]
if regime["label"] == "positive_gamma" and decay["gamma_acceleration"] > 2 and hours_left > 2:
levels = d["levels"]
em = d["expected_move"]
print(f"THETA HARVEST window open")
print(f"Gamma acceleration: {decay['gamma_acceleration']}x vs 7DTE")
print(f"Theta/hour: ${abs(decay['theta_per_hour_remaining']):,.0f}")
print(f"Time remaining: {hours_left:.1f}h")
print(f"")
print(f"Iron condor strikes:")
print(f" Short put: ${levels['put_wall']} (put wall)")
print(f" Short call: ${levels['call_wall']} (call wall)")
print(f" Expected range: ${em['lower_bound']:.2f}–${em['upper_bound']:.2f}")
The Theta Decay Curve
| Time (ET) | Theta/Hour | Gamma Accel. | Notes |
|---|---|---|---|
| 9:30 AM | 1× | 1.5–2× | Slow bleed. Gamma risk not worth the theta. |
| 11:00 AM | 1.3× | 2–2.5× | Starting to accelerate. Still early. |
| 1:00 PM | 2× | 2.5–3.5× | Sweet spot begins. Decay accelerating, gamma manageable. |
| 2:30 PM | 3.5× | 4–5× | Peak theta harvest zone. |
| 3:30 PM | 5–8× | 6–10× | Massive theta but gamma risk extreme. Closing, not entering. |
| 3:55 PM | 15×+ | 20×+ | Last 5 minutes. Do not enter. Close everything. |
Strategy 5: The Vol Spike Fade
Condition: vol_context.iv_ratio_0dte_7dte > 1.0 and regime is positive gamma.
When 0DTE IV exceeds 7DTE IV, the market is pricing a same-day event — FOMC, CPI, unexpected news. If the event passes without a large move, that premium collapses.
The trade: Sell 0DTE premium after the event. The vanna_interpretation field tells you what happens when vol drops: if it says vol_down_dealers_buy, a vol crush triggers dealer buying — supportive for longs.
vc = d["vol_context"]
ratio = vc["iv_ratio_0dte_7dte"]
if ratio > 1.0 and d["regime"]["label"] == "positive_gamma":
print(f"VOL SPIKE — 0DTE IV ({vc['zero_dte_atm_iv']}%) > 7DTE IV ({vc['seven_dte_atm_iv']}%)")
print(f"Ratio: {ratio:.2f}x — event premium in front expiry")
print(f"Vanna: {vc['vanna_interpretation']}")
if "vol_down_dealers_buy" in vc.get("vanna_interpretation", ""):
print(f"→ If vol collapses, dealers BUY — supportive for longs")
print(f"→ Sell 0DTE straddle or strangle after event passes")
How to Read the IV Ratio
| IV Ratio (0DTE / 7DTE) | Interpretation | Action |
|---|---|---|
| < 0.85 | No event premium. Normal conditions. | Use other strategies. |
| 0.85 – 1.0 | Slightly elevated front-end. | Monitor but don't act on vol alone. |
| 1.0 – 1.15 | Event premium. Same-day catalyst priced in. | Wait for event to pass, then sell premium. |
| > 1.15 | Significant event premium or intraday stress. | Sell after the event only. |
| > 1.3 | Extreme uncertainty. | Sit out. Risk/reward unfavorable. |
When to Sit Out
Not every day is a 0DTE day. The API tells you when conditions are unfavorable:
def should_trade_0dte(data):
if data.get("no_zero_dte"):
return False, "No 0DTE expiry today"
if data["exposures"]["pct_of_total_gex"] < 30:
return False, "0DTE isn't driving intraday — full chain dominates"
if data["pin_risk"]["pin_score"] < 30 and data["regime"]["label"] == "undetermined":
return False, "No clear signal — sit out"
if data["vol_context"]["iv_ratio_0dte_7dte"] > 1.3:
return False, "Extreme event premium — too risky"
return True, data["regime"]["label"]
tradeable, reason = should_trade_0dte(d)
print(f"Trade 0DTE? {'Yes' if tradeable else 'No'} — {reason}")
Per-Strike Breakdown — Building a Heatmap
The strikes array gives you per-strike granularity: GEX, DEX, OI, volume, IV, and Greeks for each 0DTE strike. This is the raw data behind the call wall, put wall, and magnet strike.
import pandas as pd
strikes_df = pd.DataFrame(d["strikes"])
strikes_df["net_oi"] = strikes_df["call_oi"] + strikes_df["put_oi"]
# Find the strikes with the most gamma impact
top_gex = strikes_df.nlargest(5, "net_gex")[["strike", "net_gex", "call_oi", "put_oi"]]
print("Top 5 GEX Strikes:")
print(top_gex.to_string(index=False))
# GEX by strike for charting
print("\nGEX Profile:")
for _, row in strikes_df.iterrows():
bar = "+" * int(abs(row["net_gex"]) / 50_000_000)
sign = "+" if row["net_gex"] > 0 else "-"
print(f" ${row['strike']:>6.0f} {sign}{bar} ({row['net_gex']:>+12,.0f})")
Risk Management for 0DTE
- Use defined-risk structures. Iron condors, butterflies, credit spreads — not naked strangles. The gamma spikes near close can produce moves that overwhelm any reasonable stop.
- Size to the worst case. If the iron condor can lose $500, that's your risk — not the "expected" $50 profit.
- Diversify across days, not strikes. One losing 0DTE trade should not damage your month. Keep each trade to 1–2% of account.
- Respect the gamma flip. If price crosses the flip and the regime changes, your thesis may be invalidated.
-
Monitor in real-time. 0DTE is not a set-and-forget trade. The
pin_score,regime, andexpected_moveall update in real-time.
Get the Data
The Zero-DTE endpoint is available on the Growth plan and Alpha plan. Every field referenced in this guide comes from a single API call.
- Get API Access — free tier available, no credit card
- Zero-DTE API Docs — full field reference
- Try It in the Playground — interactive API testing
-
Python SDK on PyPI —
pip install flashalpha - GitHub Examples — working code
Top comments (0)