Flow Signals API
Scored, classified unusual-flow feed for one underlying. Sweep vs block, NBBO aggressor, opening/closing bias, directional intent, and a transparent 0-100 score with component breakdown and chain enrichment.
Endpoint
X-Api-Key)
Rate Limited: Yes
Alpha plan+
Parameters
| Name | In | Required | Default | Description |
|---|---|---|---|---|
symbol |
path | yes | - | Underlying symbol |
minScore |
query | no | 0 |
Drop signals below this score (0-100) |
intent |
query | no | all | Filter by bullish / bearish / neutral |
structure |
query | no | all | Filter by block / sweep. A lone block-sized print is a block; sweep = ≥2 same-side prints on one contract within ~500ms |
windowMinutes |
query | no | 240 |
Look-back window in minutes (1-10080) |
limit |
query | no | 50 |
Max signals returned (1-500) |
expiry |
query | no | all expiries | Filter the chain to a single expiry (yyyy-MM-dd) |
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://lab.flashalpha.com/v1/flow/signals/NVDA?minScore=70&structure=sweep&windowMinutes=240"
import requests
resp = requests.get(
"https://lab.flashalpha.com/v1/flow/signals/NVDA",
params={"minScore": 70, "structure": "sweep", "windowMinutes": 240},
headers={"X-Api-Key": "YOUR_API_KEY"}
)
data = resp.json()
for sig in data["signals"]:
print(f"{sig['ts']} {sig['structure']:>5} {sig['right']} {sig['strike']} "
f"score={sig['score']} intent={sig['intent']} premium=${sig['premium']:,.0f}")
const params = new URLSearchParams({
minScore: 70, structure: "sweep", windowMinutes: 240
});
const resp = await fetch(
`https://lab.flashalpha.com/v1/flow/signals/NVDA?${params}`,
{ headers: { "X-Api-Key": "YOUR_API_KEY" } }
);
const data = await resp.json();
data.signals.forEach(s =>
console.log(`${s.ts} ${s.structure} ${s.right}${s.strike} score=${s.score} ${s.intent}`)
);
Response
{
"symbol": "NVDA",
"as_of": "2026-05-21T16:30:45Z",
"window_minutes": 240,
"expiry": null,
"underlying_price": 900.25,
"chain": {
"call_wall": 950.0,
"put_wall": 850.0,
"max_pain": 900.0,
"gamma_flip": 905.0
},
"count": 1,
"signals": [
{
"ts": "2026-05-21T15:58:12Z",
"expiry": "2026-05-23",
"strike": 950.0,
"right": "C",
"side": "buy",
"price": 12.40,
"size": 1500,
"premium": 1860000.0,
"dte": 7,
"structure": "sweep",
"aggressor": "above_ask",
"open_close_bias": "opening_bias",
"open_close_confidence": 0.43,
"contract_net_oi_delta": 4200,
"intent": "bullish",
"score": 87,
"conviction": "high",
"tags": ["sweep", "opening", "whale", "golden"],
"score_breakdown": {
"premium": 22, "size_vs_oi": 18, "aggressor": 14,
"sweep": 12, "opening_bias": 9, "tenor": 12
},
"enrichment": {
"iv": 0.62,
"delta": 0.28,
"gamma": 0.0041,
"iv_vs_atm": 0.08,
"moneyness": "OTM",
"estimated_delta_notional": 37810500.0,
"hypothetical_gex_impact_if_opening": 4984267.88
}
}
]
}
Per-signal fields
| Field | Type | Description |
|---|---|---|
ts | string | ISO 8601 timestamp of the print (or first leg of a sweep) |
expiry / strike / right | string / number / string | Contract key (right is C or P) |
side | string | Upstream aggressor classification: buy, sell, or mid |
price / size / premium | number | premium = price × size × 100 |
dte | number | Days to expiry |
structure | string | block (lone block-sized print) or sweep (≥2 same-side prints on one contract within ~500ms) |
aggressor | string | NBBO aggressor strength at trade: above_ask / at_ask / mid / at_bid / below_bid |
open_close_bias | string | Contract-level OI-simulator bias: opening_bias, closing_bias, or unknown |
open_close_confidence | number | OI simulator's confidence weight |
contract_net_oi_delta | number | Simulator's signed net intraday OI delta for the contract |
intent | string | Directional intent: bullish, bearish, or neutral |
score | number | Composite score 0-100, ordered highest first |
conviction | string | Score bucket label (e.g. high) |
tags | string[] | Any of sweep, block, opening, closing, 0dte, whale (premium ≥ $1M), golden (top decile in response and score ≥ 70) |
score_breakdown | object | Sub-components that sum to score: premium, size_vs_oi, aggressor, sweep, opening_bias, tenor |
enrichment.iv / delta / gamma | number, nullable | Greeks from the settled chain snapshot at the signal's strike |
enrichment.iv_vs_atm | number, nullable | Signal IV minus ATM IV for the expiry |
enrichment.moneyness | string | ITM / ATM / OTM / unknown |
enrichment.estimated_delta_notional | number, nullable | Delta-weighted dollar notional for the print (delta-equivalent shares × spot) |
enrichment.hypothetical_gex_impact_if_opening | number, nullable | Standalone gamma-$ this print would add if opening and fully dealer-absorbed. Not applied to the live chain |
Top-level fields
| Field | Description |
|---|---|
window_minutes | Echo of the requested look-back window |
expiry | Echo of the requested expiry filter (or null if all expiries) |
underlying_price | Spot at request time (0 when the settled chain snapshot is unavailable) |
chain.call_wall / put_wall / max_pain / gamma_flip | Settled-chain reference levels, computed once per request |
count | Number of signals returned (after filters and limit) |
signals | Array of signals, highest score first |
How scoring works
Every block-sized print in the window is coalesced into a signal, classified, and scored on a 0-100 scale. score_breakdown returns the component contributions that sum to score. The components map to the trade characteristics they're named after:
premium- contribution from the print's dollar premiumsize_vs_oi- contribution from print size relative to the contract's existing open interestaggressor- contribution from NBBO aggressor strength; the score weights conviction in the trade's own directionsweep- contribution when the print is part of a same-side sweep across ≥2 quotes within ~500msopening_bias- contribution when the OI simulator's contract-level bias says the position is being opened rather than unwoundtenor- contribution from the contract's DTE
Weights are server-tunable, so absolute component contributions may shift over time, but the components keep summing to score and overall signal ordering stays stable across tuning changes. The golden tag fires only when the score is in the response's top decile and at least 70 absolute, so a weak window may yield none at all.
Notes & caveats
open_close_biasis a contract-level signal from the OI simulator's net intraday delta. It is not a per-print opening/closing label - individual trades inside the same contract carry the same bias.intentcollapses toneutralwheneveropen_close_biasisclosing_bias(direction can't be attributed on unwinds) or when the tradesideismid. Thesidefield (buy/sell/mid) is distinct from the NBBOaggressorlabel.structureis alwaysblockorsweep.singleis reserved and not currently emitted, so filteringstructure=singlereturns nothing.enrichment.*fields arenullandmoneynessis"unknown"when the signal's contract isn't in the settled chain snapshot (illiquid / just-listed).hypothetical_gex_impact_if_openingis explicitly conditional - the standalone gamma-$ this single print would add if opening and fully dealer-absorbed. It is not applied to the live chain (which already folds in intraday OI), so don't sum it against/v1/flow/gex.- If the settled chain snapshot is unavailable for the symbol, the feed degrades rather than 404s: scoring still runs on trade + OI-simulator context, but
underlying_priceis0, allchainlevels arenull, and everyenrichmentblock is null/"unknown".
Common Use Cases
- Unusual options activity feed - drop into a watchlist as a "smart-money tape," filtered by
minScoreandstructure=sweep - Directional alerting - fire on
intent=bullishorintent=bearishsignals withconviction=highand theopeningtag - Flow-confirmed trade triggers - pair with a directional signal and require a same-side high-score sweep before sizing in
- Catalyst hunting - scan for the
whaletag (≥$1M premium) to surface name-specific positioning before the move - Score-component research - use
score_breakdownto back-test which components drove the best forward returns on your universe
Ready to build?
Get your free API key and start pulling live options data in 30 seconds.