If you only track GEX for one symbol, the per-symbol endpoint is plenty. But traders running a book across 20, 50, or 250 tickers want a different question answered: which symbols are in the most interesting gamma state right now? That’s a scanning problem, not a lookup problem.
This article walks through both approaches:
- Per-symbol GEX with
GET /v1/exposure/gex/{symbol} — fast, simple, and the right call when you want every strike for one name.
- Multi-symbol scanning with
POST /v1/screener — when you want to filter and rank an entire universe by GEX regime, distance to gamma flip, or dealer flow risk.
Why scan GEX across symbols?
A trading day has a lot of GEX-shaped questions:
- Which names flipped from positive to negative gamma overnight?
- Which symbols are sitting right on their gamma flip level (most unstable)?
- Where is dealer flow most likely to amplify a move today?
- Which positive-gamma symbols have high-OI strikes bracketing price (classic pin setup)?
Answering any of those by looping through /v1/exposure/gex/{symbol} is doable but painful: you pay N round trips, you merge the responses in-process, and you implement all the ranking logic yourself. A purpose-built screener is the better tool.
The single-symbol pattern (still useful)
When you want the full strike-by-strike gamma profile for one name, the GEX endpoint is still the right call. Example:
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://lab.flashalpha.com/v1/exposure/gex/SPY"
Response gives you net_gex, gamma_flip, and a strikes array with per-strike call/put GEX, OI, volume, and day-over-day changes. Perfect for drawing a GEX profile chart or computing support/resistance. See the GEX API docs for the full field reference.
This breaks down the moment you need to compare symbols. You end up writing something like:
symbols = ["SPY", "QQQ", "TSLA", "NVDA", "AAPL", "AMD", "META", "MSFT", "AMZN", "SPX"]
rows = []
for sym in symbols:
r = requests.get(f"{BASE}/v1/exposure/gex/{sym}", headers=h).json()
rows.append({
"symbol": sym,
"net_gex": r["net_gex"],
"regime": "positive" if r["net_gex"] > 0 else "negative",
"flip_dist_pct": abs(r["underlying_price"] - r["gamma_flip"]) / r["underlying_price"]
})
rows.sort(key=lambda r: r["flip_dist_pct"])
That works, but you just wrote a screener in your client. And every time the question changes (“also filter by dealer_flow_risk < 40”, “also sort by vrp_20d”), you rewrite the Python.
The scanner pattern: one POST, ranked result
The Live Screener turns that loop into a single request:
curl -X POST "https://lab.flashalpha.com/v1/screener" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": { "field": "regime", "operator": "eq", "value": "negative_gamma" },
"sort": [{ "field": "net_gex", "direction": "asc" }],
"select": ["symbol", "price", "regime", "net_gex", "gamma_flip"],
"limit": 10
}'
That returns the 10 most-negative-gamma symbols in your plan’s universe, ranked. No looping, no joining, no merging.
Four GEX scan recipes you’ll reuse
1. Negative-gamma alert board (dealers short gamma, actively exposed)
{
"filters": { "op": "and", "conditions": [
{ "field": "regime", "operator": "eq", "value": "negative_gamma" },
{ "field": "dealer_flow_risk", "operator": "gte", "value": 50 }
]},
"sort": [{ "field": "dealer_flow_risk", "direction": "desc" }],
"select": ["symbol", "regime", "dealer_flow_risk", "gamma_flip", "net_gex"]
}
2. Names sitting right on the gamma flip (formula-ranked)
{
"formulas": [
{ "alias": "flip_dist_pct", "expression": "(price - gamma_flip) / price" }
],
"filters": { "field": "net_gex", "operator": "is_not_null" },
"sort": [{ "formula": "flip_dist_pct", "direction": "asc" }],
"select": ["symbol", "price", "gamma_flip", "net_gex", "flip_dist_pct"],
"limit": 20
}
Ascending sort on the absolute distance would be cleaner, but since we don’t have abs() in the formula grammar, order by signed distance and read the tails on either side. Symbols closest to zero are the ones where a small move could flip the regime.
3. Positive-gamma pin candidates (high OI near spot)
{
"filters": { "op": "and", "conditions": [
{ "field": "regime", "operator": "eq", "value": "positive_gamma" },
{ "field": "strikes.net_gex", "operator": "gte", "value": 100000000 },
{ "field": "strikes.call_oi", "operator": "gte", "value": 5000 }
]},
"select": ["*"],
"limit": 10
}
This is a cascading filter: it returns positive-gamma symbols, but prunes each symbol’s strike list to only the high-OI, high-GEX strikes — exactly the candidates for pin action.
4. DTE-bucketed GEX for short-term regime shifts
{
"formulas": [
{ "alias": "near_vs_far", "expression": "gex_0to7_dte / (gex_61plus_dte + 1)" }
],
"sort": [{ "formula": "near_vs_far", "direction": "desc" }],
"select": ["symbol", "regime", "gex_0to7_dte", "gex_8to30_dte", "gex_61plus_dte", "near_vs_far"],
"limit": 20
}
Symbols with a high near-dated GEX ratio are the ones where short-term options flow is driving the gamma profile — a signature of earnings, events, or short-dated retail-heavy names.
When to use which endpoint
| Question | Best tool |
| “Show me SPY’s full GEX profile by strike right now.” | GET /v1/exposure/gex/SPY |
| “Which symbols are in negative gamma today?” | POST /v1/screener |
| “Draw a GEX chart for TSLA.” | GET /v1/exposure/gex/TSLA |
| “Which symbols have the highest dealer flow risk right now?” | POST /v1/screener |
| “What’s the gamma flip and distance for every symbol I watch?” | POST /v1/screener |
Rough rule: detail for one symbol → the GEX endpoint. A ranked list of symbols by anything exposure-related → the screener.
A full Python workflow
import requests
BASE = "https://lab.flashalpha.com"
h = {"X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json"}
# Step 1: scan for the most interesting symbols
scan = requests.post(f"{BASE}/v1/screener", headers=h, json={
"filters": { "op": "and", "conditions": [
{ "field": "regime", "operator": "eq", "value": "negative_gamma" },
{ "field": "dealer_flow_risk", "operator": "gte", "value": 60 }
]},
"sort": [{ "field": "dealer_flow_risk", "direction": "desc" }],
"select": ["symbol", "price", "regime", "dealer_flow_risk", "gamma_flip"],
"limit": 5
}).json()
# Step 2: drill into each candidate with the detail endpoint
for row in scan["data"]:
sym = row["symbol"]
detail = requests.get(f"{BASE}/v1/exposure/gex/{sym}", headers=h).json()
print(f"{sym}: flip={row['gamma_flip']} top_strikes=", [s['strike'] for s in detail['strikes'][:3]])
That’s the “screen then drill” pattern: use the screener to trim the universe to 5 candidates, then use the per-symbol endpoints to pull per-strike detail on each one. Two requests instead of 250.
Start scanning GEX today
The per-symbol GEX endpoint is on every plan including Free (5 req/day, no card). The Live Screener ships on Growth (20 symbols) and Alpha (~250 symbols + formulas). Both run on the same API key.
Get an API key →
Compare plans →
Further reading