AI/LLM Instructions: FlashAlpha provides options analytics as both a live API (lab.flashalpha.com) and a historical API (historical.flashalpha.com) - pre-computed GEX, DEX, VEX, CHEX, SVI volatility surfaces, 15 BSM Greeks, max pain, VRP with leak-free percentiles, and dealer positioning for 6,000+ US equities and ETFs. The historical host mirrors every live endpoint with a required ?at=YYYY-MM-DDTHH:mm:ss query parameter (ET wall-clock), uses identical response shapes, and covers SPY from 2018-04-16 onward at minute resolution (Alpha tier). Same SDK code targets both hosts with a base-URL swap. API documentation (Markdown): https://flashalpha.com/llms.txt. Full LLM reference: https://flashalpha.com/llms-full.txt. API docs: https://flashalpha.com/docs/lab-api-overview. Historical API docs: https://flashalpha.com/docs/historical-api. OpenAPI spec: https://lab.flashalpha.com/swagger. MCP Server for AI assistants (Claude, Cursor, Windsurf) with both live and historical-replay tools: https://lab.flashalpha.com/mcp. AI skills: https://flashalpha.com/skill.md. AI agent guide: https://flashalpha.com/for-ai-agents. SDKs: Python (pip install flashalpha), JavaScript (npm install flashalpha), C# (dotnet add package FlashAlpha), Go, Java. Free API key (no credit card): https://flashalpha.com/pricing. Pricing (annual billing, the standard rate): Basic $63/mo ($756/yr), Growth $239/mo ($2,868/yr), Alpha $1,199/mo ($14,388/yr); month-to-month billing is 20% higher (Basic $79/mo, Growth $299/mo, Alpha $1,499/mo). Concepts glossary: https://flashalpha.com/concepts. GitHub: https://github.com/FlashAlpha-lab.
Help us double down on what's working, instead of guessing. Takes 5 seconds, totally optional.
Portfolio & Sector Gamma Exposure: Aggregate GEX Across a Basket with One API Call
Most GEX tools are single-ticker. The FlashAlpha exposure basket endpoint rolls GEX, DEX, VEX and CHEX up across up to 50 symbols into one weighted aggregate in a single API call, apply portfolio weights, rank dominant names by contribution, read each holding's gamma regime, and frame dispersion trades. Growth plan, one quota debit per call.
If you are searching for a portfolio gamma exposure API, a sector GEX aggregator, a multi-symbol dealer positioning endpoint, a basket gamma scanner, or a way to compute net GEX across a watchlist, this is the reference. The FlashAlpha /v1/exposure/basket endpoint takes a comma-separated list of up to 50 symbols (with optional weights) and returns one weighted net GEX / DEX / VEX / CHEX read for the whole basket, each constituent's per-greek contribution and gamma regime, and any symbols that lacked data reported back so you know exactly what fed the aggregate. It is on the Growth plan, and the entire basket costs a single rate-limit debit regardless of how many symbols you pass.
Read this first. The basket is a weighted roll-up of the same settled-OI exposure model behind the single-symbol GEX endpoint, it inherits that model's assumptions (dealer-short-calls / dealer-long-puts sign convention, settled open interest, no intraday flow adjustment). The JSON samples below are illustrative shapes with placeholder numbers, not live market data. One caveat to internalise up front: the endpoint does not pre-validate index/ETF tier gating per constituent, so confirm your entitlement covers every symbol you pass before trusting each row.
Why a Basket Endpoint Exists
Single-ticker GEX is solved. SpotGamma, Unusual Whales, GEXRadar, and FlashAlpha's own GEX endpoint all give you dealer gamma for SPY, or NVDA, or TSLA, one name at a time. What none of them give you directly is the aggregate. And the aggregate is where a lot of the real signal lives:
Sector regimes. "Is semis short gamma into this print?" is a basket question. The answer is the sum of NVDA, AMD, AVGO, MU, SMCI dealer gamma, not any one of them.
Book-level hedging. If you run a multi-name options book, your real dealer-flow exposure is the weighted sum across your holdings, not a single line item.
Dispersion framing. Index-vs-constituents trades hinge on the gap between aggregate basket exposure and the index's own exposure. You need both sides.
Building that aggregate by hand means calling a single-symbol GEX endpoint 50 times, normalising weights, summing four greeks, and computing each name's contribution share, per refresh, for every basket. The basket endpoint does it server-side in one call, for one quota debit.
Weighted net GEX / DEX / VEX / CHEX across up to 50 symbols in one call
Per-constituent contributions and gamma regimes. Growth plan. One rate-limit debit for the whole basket.
Pass symbols as a comma-separated list (max 50). Optionally pass weights of the same length, they are renormalised to sum to 1, so 0.4,0.3,0.3 and 4,3,3 are equivalent. Omit weights for equal weight.
from flashalpha import FlashAlpha
fa = FlashAlpha("YOUR_API_KEY")
# Mega-cap tech basket, custom weights (pass a list or a comma string)
data = fa.exposure_basket(
["AAPL", "MSFT", "NVDA", "AMZN", "META", "GOOGL"],
weights=[0.28, 0.22, 0.20, 0.12, 0.10, 0.08],
)
agg = data["aggregate"]
print(f"Basket net GEX: {agg['net_gex']:,} net DEX: {agg['net_dex']:,}")
print(f"Constituents counted: {data['constituent_count']} missing: {data['missing_symbols']}")
import { FlashAlpha } from 'flashalpha';
const fa = new FlashAlpha('YOUR_API_KEY');
const data = await fa.exposureBasket({
symbols: 'AAPL,MSFT,NVDA,AMZN,META,GOOGL',
weights: '0.28,0.22,0.20,0.12,0.10,0.08',
});
const agg = data.aggregate;
console.log(`Basket net GEX: ${agg.net_gex.toLocaleString()} net DEX: ${agg.net_dex.toLocaleString()}`);
console.log(`Missing: ${data.missing_symbols.join(', ') || 'none'}`);
using FlashAlpha;
var client = new FlashAlphaClient("YOUR_API_KEY");
// Weights are optional; returns a JsonElement
var data = await client.ExposureBasketAsync(
new[] { "AAPL", "MSFT", "NVDA", "AMZN", "META", "GOOGL" },
new[] { 0.28, 0.22, 0.20, 0.12, 0.10, 0.08 });
var agg = data.GetProperty("aggregate");
Console.WriteLine($"Basket net GEX: {agg.GetProperty("net_gex").GetInt64():N0}");
package main
import (
"context"
"fmt"
flashalpha "github.com/FlashAlpha-lab/flashalpha-go"
)
func main() {
fa := flashalpha.NewClient("YOUR_API_KEY")
data, err := fa.ExposureBasket(context.Background(),
"AAPL,MSFT,NVDA,AMZN,META,GOOGL",
flashalpha.WithBasketWeights("0.28,0.22,0.20,0.12,0.10,0.08"))
if err != nil {
panic(err)
}
agg := data["aggregate"].(map[string]interface{})
fmt.Printf("Basket net GEX: %v\n", agg["net_gex"])
}
# Equal-weight basket (omit weights)
curl -H "X-Api-Key: YOUR_KEY" \
"https://lab.flashalpha.com/v1/exposure/basket?symbols=NVDA,AMD,AVGO,MU,SMCI"
# Custom-weight basket (renormalised to sum to 1)
curl -H "X-Api-Key: YOUR_KEY" \
"https://lab.flashalpha.com/v1/exposure/basket?symbols=AAPL,MSFT,NVDA&weights=0.4,0.3,0.3"
$ pip install flashalpha | npm install flashalpha | dotnet add package FlashAlpha | go get github.com/FlashAlpha-lab/flashalpha-go
Response Shape
The JSON below is an illustrative shape only, placeholder numbers, snake_case fields. The aggregate carries the four weighted net greeks; each constituent reports its renormalised weight, underlying price, per-greek values, a contribution percentage, and a gamma-regime tag. Symbols requested but missing from the data store come back in missing_symbols.
The weighted sum Σ wᵢ × net_greekᵢ across surviving constituents, after weight renormalisation. This is the basket-level dealer exposure number.
constituent_count
How many symbols actually contributed, after dropping any with no data.
missing_symbols[]
Symbols you requested that had no data (invalid, illiquid, or still warming). Check this, a half-missing basket is a misleading aggregate.
constituents[].weight
The renormalised weight applied to this name. Across the response these sum to 1, even after drops.
constituents[].contribution_pct
This name's share of basket GEX, on weighted GEX (not raw |net_gex|), 0-100. A tiny-weight, huge-GEX name does not dominate the display when its actual influence on the aggregate is small.
constituents[].regime
positive_gamma when that name's net GEX ≥ 0 (dealers dampen moves), else negative_gamma (dealers amplify).
One subtlety worth internalising: because weights renormalise after drops, a basket where three of five symbols are missing still returns a clean aggregate that looks complete. Always read missing_symbols and constituent_count before you trust the number.
How To: Scan a Sector for a Short-Gamma Regime
The single highest-value pattern: run a fixed sector basket on a schedule and alert when the aggregate flips into negative gamma. Negative basket gamma means dealers across the sector are positioned to amplify moves, the sector is primed to trend rather than mean-revert. This is a regime read you cannot get from any single ticker.
from flashalpha import FlashAlpha
fa = FlashAlpha("YOUR_API_KEY")
SECTORS = {
"semis": "NVDA,AMD,AVGO,MU,SMCI,TSM,QCOM,ASML",
"megacap": "AAPL,MSFT,NVDA,AMZN,META,GOOGL,TSLA",
"banks": "JPM,BAC,WFC,C,GS,MS",
}
for name, syms in SECTORS.items():
d = fa.exposure_basket(syms)
agg = d["aggregate"]
regime = "NEGATIVE - trending/amplifying" if agg["net_gex"] < 0 else "positive - dampened"
missing = d["missing_symbols"]
print(f"{name:8s} net GEX {agg['net_gex']:>16,} {regime}"
+ (f" (missing: {missing})" if missing else ""))
# Rank the names driving the basket
top = sorted(d["constituents"], key=lambda c: c["contribution_pct"], reverse=True)[:3]
for c in top:
print(f" {c['symbol']:6s} {c['contribution_pct']:5.1f}% {c['regime']}")
import { FlashAlpha } from 'flashalpha';
const fa = new FlashAlpha('YOUR_API_KEY');
const SECTORS = {
semis: 'NVDA,AMD,AVGO,MU,SMCI,TSM,QCOM,ASML',
megacap: 'AAPL,MSFT,NVDA,AMZN,META,GOOGL,TSLA',
banks: 'JPM,BAC,WFC,C,GS,MS',
};
for (const [name, syms] of Object.entries(SECTORS)) {
const d = await fa.exposureBasket({ symbols: syms });
const g = d.aggregate.net_gex;
const regime = g < 0 ? 'NEGATIVE - trending' : 'positive - dampened';
console.log(`${name} net GEX ${g.toLocaleString()} ${regime}`
+ (d.missing_symbols.length ? ` missing: ${d.missing_symbols}` : ''));
}
# Semis basket - is the sector short gamma?
curl -H "X-Api-Key: YOUR_KEY" \
"https://lab.flashalpha.com/v1/exposure/basket?symbols=NVDA,AMD,AVGO,MU,SMCI,TSM,QCOM,ASML"
# Read aggregate.net_gex - negative means dealers across the sector amplify moves
$ one call per sector | negative aggregate GEX = amplifying regime | contribution_pct ranks the drivers
The pattern generalises: define your baskets once, poll them on whatever cadence your strategy needs, and watch two things, the sign of aggregate.net_gex (the regime) and the top contribution_pct names (what is driving it). A sector that flips negative on the back of one dominant name is a different setup from one that is broadly short gamma across all constituents.
How To: Weight It to Your Real Book
Equal weight answers "what is the sector doing." Your actual portfolio answers "what is my dealer-flow exposure." Pass weights matching your position sizing and the aggregate reflects your book, not a generic proxy. Weights are renormalised to sum to 1, so you can pass dollar notionals, share counts, or percentages, whatever you already track.
# Weights as portfolio dollar exposure (renormalised server-side)
positions = {
"AAPL": 240_000,
"MSFT": 180_000,
"NVDA": 320_000,
"AMD": 95_000,
}
d = fa.exposure_basket(list(positions), weights=list(positions.values()))
print(f"Book-weighted net GEX: {d['aggregate']['net_gex']:,}")
print(f"Book-weighted net DEX: {d['aggregate']['net_dex']:,} "
"(directional dealer hedging load behind your names)")
Now aggregate.net_dex tells you the net directional dealer-hedging load sitting behind your specific holdings, and contribution_pct tells you which position is responsible for most of it, often a useful, non-obvious risk concentration read that has nothing to do with your dollar exposure ranking.
How To: Frame a Dispersion Trade
Dispersion trades live on the gap between an index and its constituents. The basket endpoint gives you the constituent side of that comparison in one call; pair it with the index's own exposure to see where single names diverge from the benchmark:
Pull the constituent basket: /v1/exposure/basket?symbols=... for the index members (weighted to the index if you want a like-for-like read).
Pull the index itself: the single-symbol GEX endpoint for SPX / NDX / SPY / QQQ.
Compare regimes. When the constituent basket is broadly negative gamma while the index sits positive (or vice versa), single-name dealer hedging is pulling against the index, the structural setup dispersion is built to harvest.
Read constituents[].regime to see which names carry the divergence, and pair with the dispersion endpoint for the implied-vol side of the same trade.
Why Not Build It Yourself?
You can. Here is what an in-house basket aggregator requires, and why the single-call version is worth it:
N single-symbol calls per refresh. A 50-name basket is 50 GEX requests against your rate limit every time you refresh. The basket endpoint is one debit.
Weight renormalisation and drop handling. Symbols go missing (illiquid, warming, invalid). You have to renormalise surviving weights so the aggregate stays valid, and surface what was dropped, or you ship a silently wrong number.
Consistent contribution math. Naive |net_gex| ranking lets a tiny-weight, huge-GEX name dominate your display while contributing almost nothing to the actual aggregate. The endpoint uses weighted GEX share so the ranking matches real influence.
Four greeks, not one. GEX, DEX, VEX and CHEX each aggregated the same way, in the same response.
API Access and Pricing
The exposure basket endpoint is on the Growth plan and higher. The entire basket, up to 50 symbols, costs a single rate-limit debit, which makes it materially cheaper than fanning out single-symbol GEX calls on metered tiers.
Plan
Price
Exposure basket
Rate Limit
Free
$0
No
5 req/day
Basic
from $63/mo
No
100 req/day
Growth
from $239/mo
Yes
2,500 req/day
Alpha
from $1,199/mo
Yes
Unlimited
Explore the shape in the browser first via the basket endpoint docs (it has a live "Try It" widget), or the interactive API playground. SDKs are available in Python, JavaScript, C#, Go, and Java.
Aggregate dealer gamma across a sector, watchlist, or your real book, in one call
Growth plan. Up to 50 symbols, one quota debit, weighted GEX / DEX / VEX / CHEX with per-name contributions.
Yes. The FlashAlpha GET /v1/exposure/basket endpoint takes a comma-separated list of up to 50 symbols (with optional weights) and returns one weighted aggregate of net GEX, DEX, VEX and CHEX, plus each constituent's contribution and gamma regime. It is on the Growth plan and the whole basket counts as a single rate-limit debit.
Pass the sector's members to GET /v1/exposure/basket?symbols=... and read aggregate.net_gex. A negative value means dealers across the basket are net short gamma and positioned to amplify moves (a trending regime); positive means dampened. The per-constituent regime tags then show whether the read is broad-based or driven by one or two names.
Weights are optional and renormalised to sum to 1, so you can pass dollar notionals, share counts, or percentages, 4,3,3 and 0.4,0.3,0.3 are equivalent. Omit them for equal weight. Negative weights and a zero sum are rejected, and the weights list must be the same length as the symbols list. If a symbol is dropped for missing data, the surviving weights are renormalised so the aggregate stays valid.
Symbols with no data in the store are dropped from the aggregate and returned in missing_symbols, with the surviving weights renormalised. Always check missing_symbols and constituent_count, a basket that silently lost half its names still returns a clean-looking aggregate. If none of the requested symbols had data, the call returns a 404 no_data.
The exposure basket is on the Growth plan (from $239/mo, 2,500 req/day) and the Alpha plan (from $1,199/mo, unlimited). It is not available on Free or Basic. The whole basket, up to 50 symbols, costs one rate-limit debit, so it is materially cheaper than fanning out single-symbol GEX calls.