Crypto Options Data API: BTC, ETH, IBIT and MSTR
Endpoints, symbol conventions and tier requirements for pulling crypto options exposure across CME futures, spot ETFs and the equity proxies - with the gotchas that cost people a day.
Your account is ready. Here's everything you need to start.
Keep your API key secure. Do not share it in public repositories or client-side code.
curl -H "X-Api-Key: YOUR_KEY" \
"https://lab.flashalpha.com/v1/exposure/gex/AAPL?expiration=2026-06-19"
pip install FlashAlpha
from flashalpha import FlashAlpha
fa = FlashAlpha("YOUR_KEY")
gex = fa.gex("AAPL", expiration="2026-06-19")
print(f"Gamma flip: {gex['gamma_flip']}")
Endpoints, symbol conventions and tier requirements for pulling crypto options exposure across CME futures, spot ETFs and the equity proxies - with the gotchas that cost people a day.
This is a developer reference rather than an analysis piece. For what the numbers mean, see crypto options dealer positioning.
Two conventions, and mixing them up is the most common first error.
| Instrument | Symbol | Convention | Notes |
|---|---|---|---|
| CME Bitcoin | BTC=F | Futures, encode as BTC%3DF | $5 / point, 5 BTC |
| CME Ether | ETH=F | Futures, encode as ETH%3DF | $50 / point, 50 ETH |
| Spot BTC ETF | IBIT | Plain equity ticker | 100 shares / contract |
| Spot ETH ETF | ETHA | Plain equity ticker | 100 shares / contract |
| Proxies | MSTR, COIN | Plain equity ticker | 100 shares / contract |
The =F suffix disambiguates futures from equities. In REST paths the = must be URL-encoded as %3D. SDK methods take the plain string "BTC=F" and handle encoding for you.
Gating is by endpoint, not by symbol, with one symbol-level exception. Worth reading carefully, because "IBIT is just an equity" does not mean every call is available on every plan.
| Call | Required plan |
|---|---|
Any =F futures symbol | Growth or higher |
GET /v1/exposure/gex/{symbol} full chain | Growth or higher |
GET /v1/exposure/gex/{symbol}?expiration= | All plans |
GET /v1/exposure/summary/{symbol} | Growth or higher |
GET /v1/exposure/narrative/{symbol} | Growth or higher |
GET /v1/exposure/zero-dte/{symbol} | Growth or higher |
Any endpoint with ?expiration= set to today (0DTE) | Growth or higher |
svi_vol field on the surface | Alpha or higher |
A request below the required tier returns 403 with error: "tier_restricted" and required_plan: "Growth". Accounts created before 2026-03-20 are grandfathered for 0DTE access on their existing plan.
?expiration=yyyy-MM-dd for a non-0DTE date gives you the strike map for that expiry on any plan. For most positioning work a single monthly expiry is what you actually wanted anyway.# Aggregate exposure, one call, all greeks
GET /v1/exposure/summary/IBIT
GET /v1/exposure/summary/MSTR
GET /v1/exposure/summary/BTC%3DF
# Gamma by strike - walls, flip
GET /v1/exposure/gex/IBIT
GET /v1/exposure/gex/IBIT?expiration=2026-09-18
GET /v1/exposure/gex/BTC%3DF
# Other greeks
GET /v1/exposure/dex/MSTR # delta
GET /v1/exposure/vex/MSTR # vanna - dominant in MSTR
GET /v1/exposure/chex/MSTR # charm
# Levels and context
GET /v1/levels/IBIT # key levels incl. max pain
GET /v1/stock/IBIT/summary # incl. IV term structure
The summary endpoint returns net GEX, DEX, VEX and CHEX, the regime label, the gamma flip, a hedging estimate for a 1% move, and the 0DTE breakdown in a single response. If you are polling several symbols, prefer it over four separate greek calls - see one call versus separate endpoints.
import requests
BASE = "https://api.flashalpha.com/v1"
HEADERS = {"X-API-Key": API_KEY}
def exposure(symbol: str) -> dict:
# SDK-free: encode "=" for futures symbols, leave equities alone
path = symbol.replace("=", "%3D")
r = requests.get(f"{BASE}/exposure/summary/{path}", headers=HEADERS, timeout=10)
r.raise_for_status()
return r.json()
complex_ = ["IBIT", "ETHA", "MSTR", "COIN", "BTC=F"]
for sym in complex_:
d = exposure(sym)
gex = d["exposures"]["net_gex"]
print(f"{sym:6} {d['regime']:16} net_gex ${gex:>14,.0f} flip {d['gamma_flip']:,.2f}")
That loop is the whole cross-wrapper divergence check. When the regime column is not uniform across the complex, the wrappers disagree - which is the thing worth knowing.
1. Unencoded =. /v1/exposure/gex/BTC=F will not route as intended. Encode it as BTC%3DF. If you are building URLs by string concatenation this is the bug you will hit first.
2. Comparing contracts across wrappers. One CME bitcoin contract is 5 BTC, roughly $317,000 of notional at a bitcoin price near 63,500. One IBIT contract is 100 shares, roughly $3,600. Open-interest counts differ by about two orders of magnitude and are not comparable. Compare the dollar exposure fields, never the contract counts.
3. Assuming crypto trades when the options do. IBIT, ETHA, MSTR and COIN options trade US equity hours. The underlying asset trades continuously. Exposure figures pulled outside the session reflect the last settled book, not a live one, and a large weekend move in coin will not be reflected in ETF exposure until the equity market reopens. Read the as_of timestamp on every response.
The same exposures are available historically for backtesting, on the /v1/historical/ prefix:
GET /v1/historical/exposure/gex/IBIT?date=2026-06-16
GET /v1/historical/exposure/summary/MSTR?date=2026-06-16
Coverage varies by symbol and start date. Check /v1/historical/coverage before assuming depth on the newer crypto listings, several of which have short histories. A worked study is in historical crypto gamma.
Two symbol conventions, one encoding rule, and a tier map that gates by endpoint rather than by symbol. CME contracts need %3D and a Growth entitlement; the ETFs and proxies are plain tickers but full-chain GEX and the exposure summary still require Growth, with single-expiry GEX available below that. The three mistakes that cost the most time are forgetting to encode the =, comparing contract counts across wrappers whose sizes differ by two orders of magnitude, and reading equity-hours exposure as though it reflected a continuously traded underlying. Check the as_of timestamp and compare dollars.
by Tomasz Dobrowolski
by Tomasz Dobrowolski
by Tomasz Dobrowolski
Get fast visibility into market shifts with full-chain analytics over low-latency REST and MCP polling.
Screen millions of option pairs per second using your custom EV rules, filters, and setups.
Export structured signals to your own execution stack or broker integration - FlashAlpha delivers the analytics, you keep control of order routing.