Flow Signals API: How FlashAlpha Scores Unusual Options Activity (Sweeps, Blocks, Opening Bias, Intent)

Flow Signals API: How FlashAlpha Scores Unusual Options Activity (Sweeps, Blocks, Opening Bias, Intent)

Flow Signals API methodology: six published scoring components, audit-able breakdown per signal, sweep rule, intent classifier. Every score is reconstructible.

T
Tomasz Dobrowolski Quant Engineer
May 23, 2026
52 min read
FlowSignals UnusualOptions SweepDetection OptionsFlow DealerPositioning API OptionsAnalytics Methodology

The unusual-options-flow market is full of black boxes. Vendors publish "scored" feeds without specifying what the score means: which trades qualify, how the score is computed, what threshold separates a meaningful signal from background noise. For a quantitative trader or a developer building a screener, this is unworkable. You cannot calibrate against a number whose derivation is hidden, and you cannot ignore false positives whose drivers you cannot see.

The FlashAlpha Flow Signals API (GET /v1/flow/signals/{symbol}) takes the opposite stance. The score is the deterministic, weighted average of six normalised components. Every component is returned in the response under score_breakdown. The classification of every trade as a sweep or block, an opening or closing flow, a bullish or bearish bet, follows rules documented in code and reproduced in this article. This is the methodology paper.

6
Independently weighted scoring components, all surfaced in the response
500ms
Same-side coalescing window for sweep detection across venues
0-100
Auditable composite score with high/medium/low/minimal conviction labels

What the Flow Signals Feed Actually Is

The flow signals endpoint takes the raw block-sized prints from the OPRA tape, groups same-side prints that arrived within 500ms of each other on the same contract into single execution intents, and produces one scored, classified FlowSignal per group. The output is the input layer for any system that needs to react to unusual activity: a trading dashboard, an alert ruleset, a backtest universe selector, or an LLM that needs structured options-flow context.

FlowSignal

One classified unit of unusual options activity. Represents either a single block-sized print or a coalesced sweep group on one option contract. Carries the trade specifics (ts, strike, expiry, side, price, size, premium), the structural classification (sweep or block), the directional intent (bullish, bearish, or neutral), the opening or closing bias from the OI simulator, a 0-100 composite score with full per-component breakdown, and a chain-context enrichment (greeks, IV-vs-ATM, delta notional).

The pipeline is intentionally split across pure-static components so every step is independently testable on synthetic tapes - no clock, no HTTP, no global state outside the inputs.

Pipeline Stages

1. FlowDataClient.NotableTradesAsync: windowed pull from the ingest service's notable-trade ring (default 240-minute window, 100-contract minimum block size, hard-capped at 512 most-recent prints).
2. FlowAnalyticsService.LoadAsync: settled greek snapshots, OI-simulator state per contract, and current spot.
3. UnusualFlowScorer.Score: pure classification and scoring against the trade group, OI context, and weights.
4. UnusualFlowEnricher.Enrich: chain overlay adding greeks-derived fields (IV-vs-ATM, moneyness, estimated delta notional, hypothetical GEX impact-if-opening) and symbol-level reference levels.
5. Controller: tier gate, optional filters (minScore, intent, structure), JSON shaping.

Sweep Coalescing: 500ms Same-Side Same-Contract

The single most important pre-processing step is sweep coalescing. A real institutional execution often crosses multiple venues in rapid succession - one bid lifted on PHLX, another at the same instant on CBOE, a third on AMEX - because that is how exchanges route a multi-leg sweep. On the tape, that single intent looks like three prints. Without coalescing, the score-it-once-per-print approach would either double-count the intent or under-rate it.

Sweep Coalescing Rule $$ \text{group}(t_i, t_{i+1}) \iff \text{side}(t_i) = \text{side}(t_{i+1}) \land (t_{i+1} - t_i) \le 500\text{ms} $$

Same-contract same-side prints whose timestamps fall within 500 milliseconds of the prior print join the current group. Any group with two or more prints is classified as a sweep; a singleton block-sized print is a block. The size used for scoring is the sum across the group; the price is the size-weighted average; the timestamp is the last print in the group.

The 500ms window is deliberately conservative. Genuine cross-venue sweeps usually finish in under 100ms; the extra headroom catches venues that route via slower paths without false-coalescing prints that are merely temporally adjacent. If you need a stricter or looser definition, the value is a private constant in UnusualFlowScorer.SweepWindow - one source of truth, easy to retune.

The Six Scoring Components

Every coalesced group is scored along six axes. Each component is normalised to the unit interval [0,1] before weighting, the components are combined as a weighted average, and the result is scaled to a 0-100 integer. The breakdown is surfaced in every response so you can always answer "why is this score 78 and not 50?" without leaving the JSON.

1. Premium

The notional dollar value of the trade (price × size × 100 multiplier), log-normalised against a $10M cap.

Premium Component $$ n_{\text{premium}} = \text{clamp}\Bigg(\frac{\log_{10}(1 + P)}{\log_{10}(1 + P_{\text{cap}})},\; 0,\; 1\Bigg) $$

With the default $10M cap, a $1M trade scores about 0.86, a $100K trade about 0.71, and a $10M trade saturates at 1.00. The log normalisation is deliberate: linear scaling would push every $100K-$1M print to noise and only spotlight the largest tape, whereas the log form gives realistic mid-sized prints meaningful score contribution without letting one whale dominate the rank.

2. Size vs Open Interest

The ratio of trade size to the contract's settled OI, capped at 1.0 by default.

Size-vs-OI Component $$ n_{\text{size\_vs\_oi}} = \text{clamp}\Bigg(\frac{\text{size} / \max(1, \text{settled\_oi})}{\text{cap}},\; 0,\; 1\Bigg) $$

This component is the unusual-activity classic. A trade equal to or larger than the entire settled OI is a position change of the highest possible significance for that contract and saturates the score. The default cap of 1.0 means even a trade that is 50% of settled OI scores 0.5 - a meaningful contribution but not full credit until the trade hits the OI itself.

Honest caveat: this component is the strongest signal on contracts with low settled OI and the weakest on names with massive resting interest. A 50,000-lot SPY 0DTE print on a strike with 800,000 OI scores 0.0625; the same 50,000-lot on a single-name back-month strike with 30,000 OI saturates at 1.0. That is the intended behaviour - relative significance, not absolute size. If you want absolute-size ranking, sort the feed by premium instead.

3. Aggressor Strength

The combination of where the print landed inside the NBBO and how aggressive the side classifier called it.

Aggressor Label

A descriptive position relative to the NBBO at the time of the print. Five buckets: above_ask (price > ask + 0.005), at_ask (within ±0.005 of ask), below_bid (price < bid - 0.005), at_bid (within ±0.005 of bid), mid (everything in between). The label is purely descriptive - it tells you where, not how strongly.

Aggressor Strength (side-aware) $$ n_{\text{aggressor}} = \begin{cases} 0.4 & \text{side} = \text{mid} \\ 0.5 & \text{spread} \le 0 \text{ (crossed/locked)} \\ \dfrac{\text{price} - \text{bid}}{\text{ask} - \text{bid}} & \text{side} = \text{buy} \\ \dfrac{\text{ask} - \text{price}}{\text{ask} - \text{bid}} & \text{side} = \text{sell} \end{cases} $$

A buyer who lifts the offer scores near 1.0; a buyer who pays the midpoint scores around 0.5; a buyer who somehow gets filled below the mid scores low. Symmetrically for sellers. Mid prints get a flat 0.4 because they cannot be classified as aggressive in either direction with confidence. Crossed or locked NBBOs (spread ≤ 0) get 0.5, neutral, because the spread denominator is undefined.

4. Sweep Structure

Categorical score reflecting the execution structure detected during coalescing.

Structure Component $$ n_{\text{sweep}} = \begin{cases} 1.00 & \text{coalesced group, } \ge 2 \text{ prints (sweep)} \\ 0.55 & \text{singleton block-sized print (block)} \\ 0.20 & \text{single print below block size (rare here)} \end{cases} $$

Sweeps are the highest-value structure because they signal urgency: the participant was willing to walk multiple venues to get filled fast. A standalone block is meaningful but compatible with patient, single-venue execution. The "single" tier exists for completeness - the upstream ring is block-only by construction, so you rarely see it in practice.

5. Opening Bias

Whether the trade opens new positions or closes existing ones, derived from the OI simulator's signed intraday delta for the same contract.

Opening Bias Component $$ n_{\text{opening}} = \text{bias\_score} \times \text{oi\_confidence} $$ $$ \text{bias\_score} = \begin{cases} 1.0 & \text{net OI delta} > 0 \text{ (OpeningBias)} \\ 0.3 & \text{net OI delta} < 0 \text{ (ClosingBias)} \\ 0.5 & \text{net OI delta} = 0 \text{ (Unknown)} \end{cases} $$

The oi_confidence multiplier is the simulator's per-trade confidence weight, currently 0.43 (see Effective Open Interest Methodology for the calibration story). This is the most important design choice in the entire scorer.

Even a "perfect" opening signal contributes at most 0.43 to the normalised component, not 1.0. With the default weight of 1.2 and a total weight of 5.6, the opening-bias bucket can contribute at most 100 × 1.2 × 0.43 / 5.6 ≈ 9.2 points to the composite score. That ceiling is intentional: the simulator's calibrated confidence is 0.43, and a scoring model that gave full credit to opening signals would be overstating what the underlying inference can actually prove. Honest in, honest out.

6. Tenor

Days to expiration, normalised so short-dated trades score higher.

Tenor Component $$ n_{\text{tenor}} = \text{clamp}\Bigg(1 - \frac{\text{dte}}{T_{\text{cap}}},\; 0,\; 1\Bigg) $$

With the default tenor_cap_days of 45, a 0DTE print scores 1.0, a 22-DTE print scores 0.51, a 45+-DTE print scores 0. LEAPS get zero credit for tenor. The reasoning: shorter-dated flow has more time-discounted information value, and the unusual-activity use case is primarily a short-horizon signal. If you want a screener that surfaces LEAPS rolls, sort by premium and ignore the tenor component.

The Composite Score

Every component is combined into a single 0-100 integer through a weighted average, with each component's individual contribution rounded and exposed for auditability.

Composite Score $$ \text{contribution}_i = \text{round}\Bigg(100 \times \frac{w_i \cdot n_i}{\sum_j w_j}\Bigg) $$ $$ \text{score} = \text{clamp}\Bigg(\sum_i \text{contribution}_i,\; 0,\; 100\Bigg) $$

The default weights (tunable via the UnusualFlowWeights record, sum = 5.6) are:

Higher-weight components
  • opening_bias: 1.2 - the directional anchor (subject to 0.43 confidence ceiling)
  • premium: 1.0 - absolute notional ranking
  • size_vs_oi: 1.0 - relative significance ranking
  • sweep: 1.0 - execution-urgency proxy
Lower-weight components
  • aggressor: 0.8 - NBBO-position conviction
  • tenor: 0.6 - short-dated bias

The breakdown lives in the response under score_breakdown:

{
  "score": 78,
  "score_breakdown": {
    "premium":      22,
    "size_vs_oi":   10,
    "aggressor":    13,
    "sweep":        18,
    "opening_bias":  6,
    "tenor":         9
  }
}

This is the audit trail. Add the buckets and you get the score, with rounding to within ±1 from accumulating per-bucket rounds. Any score in the feed can be reconstructed from the trade + OI context using the formulas above. There are no hidden adjustments.

Intent Classification

Once the trade is scored structurally, the scorer assigns a directional intent. The rules are deliberately conservative.

Intent Classifier $$ \text{intent} = \begin{cases} \text{Neutral} & \text{bias} = \text{ClosingBias (unwind, direction unknown)} \\ \text{Neutral} & \text{side} = \text{Mid} \\ \text{Bullish} & \text{(BuyCall) or (SellPut)} \\ \text{Bearish} & \text{(SellCall) or (BuyPut)} \end{cases} $$

The closing-bias-collapses-to-Neutral rule is load-bearing. A closing trade tells you what is being unwound, but the direction the unwinder originally bet is generally unknown to the tape. Calling a closing trade "Bullish" or "Bearish" would over-claim. The honest answer is Neutral, and the consumer can read the open_close_bias field directly if they want to count closing flow separately.

Conviction Labels and the "Golden" Tag

Two human-readable summaries ride alongside the raw score: a conviction bucket and an optional "golden" tag.

Score rangeConviction label
80 - 100high
60 - 79medium
40 - 59low
0 - 39minimal

The thresholds are calibrated so that, on a typical SPY session, the medium bucket and above contains the prints worth a human review and the high bucket contains the ones you would page someone for. They are absolute, not relative to today's distribution - a quiet session genuinely produces fewer high-conviction signals.

Golden Tag

A signal is tagged golden if its score is in the top decile of the current result set and meets the absolute floor of 70. This combines the relative ranking ("better than 90% of today's flow") with an absolute quality gate (no "best of a bad day" promotion). The tag is added after scoring, so it depends on the full result set the request returns.

Greeks Enrichment Overlay

Once a signal is scored, the enricher joins it with the settled greek snapshot for the same contract and adds a chain-context overlay. The enrichment is deliberately scoped to fields the data can actually prove.

iv, delta, gamma

Raw values from the settled greek snapshot. If the contract is illiquid or just-listed and has no snapshot, the fields are null.

iv_vs_atm

The contract's implied vol minus the ATM IV on its expiry. ATM IV is defined as the IV of the strike nearest spot on that expiry. Positive = trading rich vs the ATM smile; negative = trading cheap.

moneyness

A standard bucket from the absolute delta: |δ| ≥ 0.65 is ITM, ≤ 0.35 is OTM, anything in between is ATM. Same for calls and puts.

estimated_delta_notional

The directional dollar exposure of the traded quantity:

$$ \text{delta\_notional} = \text{size} \times 100 \times \delta \times S $$

Signed by the contract's own delta (calls positive, puts negative). This is what the trade is worth in stock-equivalent terms at the moment of execution.

hypothetical_gex_impact_if_opening

What this print alone would add to dealer gamma exposure if it were fully opening and fully dealer-absorbed:

$$ \text{gex}_{\text{hypo}} = \text{size} \times 100 \times \Gamma \times S^2 \times 0.01 $$

This is gamma dollars per 1% underlying move. The name says hypothetical and if opening on purpose: the live flow surface already folds intraday OI deltas into its chain-level numbers, so applying this per-signal estimate on top would double-count. Use it to size individual trades, not to recompute chain GEX.

At the symbol level, the enricher also returns the settled-chain reference levels (call wall, put wall, max pain, gamma flip) computed once per request. Those let a consumer cross-reference whether a high-scoring signal hits a meaningful structural strike or is firing in a no-man's-land.

The Summary Endpoint: Bullish vs Bearish Premium Roll-Up

The companion GET /v1/flow/signals/{symbol}/summary endpoint runs the same pipeline and aggregates premium across the directional and open/close buckets. It is the single number you want on a dashboard.

Summary Aggregations $$ \text{bullish\_premium} = \sum_{s\,:\,\text{intent}_s = \text{Bullish}} P_s $$ $$ \text{bearish\_premium} = \sum_{s\,:\,\text{intent}_s = \text{Bearish}} P_s $$ $$ \text{net\_directional\_premium} = \text{bullish\_premium} - \text{bearish\_premium} $$ $$ \text{opening\_premium} = \sum_{s\,:\,\text{open\_close} = \text{OpeningBias}} P_s $$ $$ \text{closing\_premium} = \sum_{s\,:\,\text{open\_close} = \text{ClosingBias}} P_s $$

Plus the top 10 signals (already sorted descending by score). One call gives you a watchlist-friendly direction signal and the underlying prints that produced it.

Closing premium counted separately on purpose. A large closing-flow session looks identical to a large opening-flow session on a naive net-directional aggregator. The split lets you build the distinction yourself: rising opening_premium with falling closing_premium is fresh positioning; the reverse is position unwinding.

How to Use It

The endpoint is on the Alpha plan. Defaults are sensible: 240-minute window, top 50 by score, all intents, all structures. Filter parameters narrow the result without re-running the pipeline.

Query parameterDefaultPurpose
windowMinutes240How far back to scan the notable-trade ring (1 - 10080)
minScore0Floor on composite score (0 - 100)
intent(any)bullish, bearish, or neutral
structure(any)sweep or block (the scorer only emits these two; the upstream notable-trade ring is block-only by construction)
limit50Max signals to return (1 - 500)
expiry(all)Filter chain to one expiry (YYYY-MM-DD)

Code Example: Top 10 Bullish Sweeps on SPY

import requests

resp = requests.get(
    "https://lab.flashalpha.com/v1/flow/signals/SPY",
    headers={"X-Api-Key": "YOUR_KEY"},
    params={
        "windowMinutes": 240,
        "intent": "bullish",
        "structure": "sweep",
        "minScore": 70,
        "limit": 10,
    },
)
data = resp.json()

print(f"{data['count']} qualifying signals on {data['symbol']}")
print(f"Chain context: call_wall={data['chain']['call_wall']}, "
      f"put_wall={data['chain']['put_wall']}, "
      f"gamma_flip={data['chain']['gamma_flip']}")

for s in data["signals"]:
    print(
        f"  {s['ts']}  {s['expiry']} {s['strike']}{s['right']}"
        f"  size={s['size']:>5}  ${s['premium']:>10,.0f}"
        f"  score={s['score']}  ({s['conviction']})"
        f"  {','.join(s['tags'])}"
    )

Code Example: Watchlist Direction Card

import requests
from concurrent.futures import ThreadPoolExecutor

WATCHLIST = ["SPY", "QQQ", "IWM", "NVDA", "TSLA", "AAPL"]
HEADERS = {"X-Api-Key": "YOUR_KEY"}

def fetch_summary(symbol):
    r = requests.get(
        f"https://lab.flashalpha.com/v1/flow/signals/{symbol}/summary",
        headers=HEADERS,
        params={"windowMinutes": 60},
    )
    return symbol, r.json()

with ThreadPoolExecutor(max_workers=8) as pool:
    for sym, d in pool.map(fetch_summary, WATCHLIST):
        net = d["net_directional_premium"]
        direction = "BULLISH" if net > 0 else "BEARISH" if net < 0 else "NEUTRAL"
        print(
            f"{sym:6} {direction:8} "
            f"net=${net:>14,.0f}  "
            f"open=${d['opening_premium']:>12,.0f}  "
            f"close=${d['closing_premium']:>12,.0f}"
        )

Use Cases and Honest Scope

The endpoint is designed for four workflows.

1. Real-time unusual-activity dashboards

Poll the signals endpoint every 15-60 seconds; render the high-conviction signals with their score breakdown. The audit trail is the differentiator - your users see why a signal qualified.

2. Watchlist direction cards

Hit the summary endpoint across a watchlist. The net_directional_premium field is one signed number per ticker, cheap enough to refresh on a tight cadence.

3. Event-driven alerts

Subscribe to "score ≥ 80 AND tag contains 'golden' AND intent = bullish on watchlist". The fields are first-class JSON; the gating logic is straightforward to build.

4. LLM context injection

Feed the top-N signals (with score breakdown and enrichment) into a market-commentary prompt. The structured fields and explicit conviction labels let the model write grounded summaries rather than hallucinated narratives.

What it is not designed for:

  • Full tape replay. The notable ring is hard-capped at 512 prints; the endpoint is a windowed scan, not an exhaustive trade history. For full replay, use the raw /v1/flow/options/{symbol}/recent surface.
  • Single-print precision intent. Intent is a heuristic from side and call/put. Multi-leg structures (verticals, butterflies, calendars) are not detected at this layer. A bear-call-spread leg that buys the lower call still reads as a bullish single leg here.
  • Replacing per-strike GEX. The enrichment provides per-signal greeks, but the chain-level live GEX number lives at /v1/flow/gex, computed against effective OI. Use both: signals for intent and significance, /v1/flow/gex for chain-level dealer exposure.

Why the Score Breakdown Matters

Every unusual-activity vendor in the market publishes a score. Almost none of them tell you what is inside it. The buyer is forced to trust the number, the implicit weighting, and the (undisclosed) calibration choices the vendor made years ago and may or may not have revisited.

Typical vendor approach
  • Black-box composite score
  • No per-component breakdown
  • Sweep detection rule undocumented
  • Intent classification logic undisclosed
  • Confidence ceilings hidden inside
  • Tuning the threshold requires guesswork
FlashAlpha Flow Signals
  • Every component formula in this article
  • score_breakdown object on every response
  • 500ms sweep window documented in code
  • Intent classifier rules explicit
  • 0.43 OI confidence ceiling published
  • Threshold tuning informed by visible per-bucket math

The score is the product. The methodology is the warranty.

Verify a signal yourself

Pick any signal in the feed, read its score_breakdown, and reconstruct the components from the trade + chain context using the formulas above. If a number in the breakdown does not match the formula, that is a bug we want to know about. The whole stack is built on the premise that you can.

Limitations and Calibration Notes

Three honest limitations of the current scorer:

Side classification is upstream

The Buy/Sell/Mid label comes from the ingest service's quote-rule classifier (the same Lee-Ready style logic used by the OI simulator). Rapid quote updates around news prints can flip individual classifications. The aggregator effect is monitored in the residual reconciliation pipeline for the OI simulator (see the methodology paper); the same classifier feeds the aggressor strength and the intent classifier here. If you need per-print classification certainty, treat the score as one input among several rather than a standalone signal.

Multi-leg structures are not detected

The pipeline groups same-side same-contract prints into sweeps but does not infer that a simultaneous buy-call-A and sell-call-B is a vertical spread. Each leg is scored independently and labelled with its own (possibly opposite) intent. A higher-level structure detector is a candidate for a future revision but is not in scope today.

The default weights are calibrated, not derived

The 1.0 / 1.0 / 0.8 / 1.0 / 1.2 / 0.6 weighting was set by eye after looking at a representative range of SPY, NVDA, and TSLA sessions. There is no claim that these weights are statistically optimal; they are documented defaults that you can override per-request via the UnusualFlowWeights record at the service layer. If you have a backtest that prefers a different weighting, the API is open to a future ?weights= parameter - we have not built it yet because no customer has asked for it. The audit trail in score_breakdown exists partly so customers can build their own re-weighting on top of our normalised components.

How It Fits Into the Wider Flow Stack

Flow signals are one of three independent flow surfaces on the same API key:

SurfaceWhat it answersEndpoints
Flow analytics"Where is dealer positioning right now, accounting for today's flow?"/v1/flow/levels, /v1/flow/pin-risk, /v1/flow/summary, /v1/flow/gex, /v1/flow/dex, /v1/flow/dealer-risk, /v1/flow/oi, /v1/flow/live
Flow signals (this article)"Which individual trades today were unusual, and what did they look like?"/v1/flow/signals/{symbol}, /v1/flow/signals/{symbol}/summary
Raw flow data"Give me the trades themselves so I can run my own logic"/v1/flow/options/{symbol}/recent, /blocks, /summary, /history, /cumulative, leaderboards, outliers

The three surfaces share the same OI simulator state and the same settled greek snapshot, so the numbers across them reconcile. The composite use case is: scan the signals feed for high-conviction intent, cross-check the chain context against /v1/flow/gex, and drop into raw trades for any signal that needs deeper inspection.

Frequently Asked Questions

The methodology is fully documented and the per-component breakdown is in every response. A typical UOA feed publishes an opaque score; FlashAlpha publishes the six normalised components (premium, size-vs-OI, aggressor, sweep, opening bias, tenor), their weights, and their individual contributions to the composite. Any score in the feed can be reconstructed from the trade and chain context using the formulas in the methodology paper.
Same-contract same-side prints whose timestamps fall within 500 milliseconds of the previous print are coalesced into one execution intent. A coalesced group of two or more prints is a sweep; a singleton block-sized print is a block. The 500ms window catches the cross-venue routing latency of genuine multi-exchange sweeps without false-coalescing temporally adjacent but unrelated prints.
From the OI simulator's signed intraday delta for the contract. A positive accumulated delta means the simulator is reading the day's flow on this contract as net-opening, and the trade is tagged OpeningBias. A negative delta tags it ClosingBias. Zero delta tags it Unknown. The simulator's confidence weight (0.43) is included as a multiplier on the score component, so a "perfect" opening signal contributes at most 0.43 of the bucket's max, intentionally reflecting the underlying inference confidence.
A closing trade unwinds an existing position. The tape can tell you what is being unwound but generally cannot tell you which direction the unwinder originally bet. Calling a closing flow "Bullish" or "Bearish" would over-claim. The honest answer is Neutral. The closing classification is still surfaced through open_close_bias = ClosingBias and the dedicated closing_premium aggregate on the summary endpoint, so consumers can analyse closing flow independently.
Because the OI simulator's per-trade confidence is 0.43, calibrated against next-morning settled OI residuals. The scorer multiplies the opening-bias raw score by this confidence so a "perfect" opening signal contributes at most 0.43 of the bucket's normalised credit. Giving full credit would overstate what the underlying inference can prove. With the default weights, opening bias can contribute about 9 of the 100 total score points - meaningful but not dominant. This is an intentional honesty constraint, not a bug.
Yes. Every component formula is published in the methodology paper, the per-component contributions are returned in score_breakdown, and the default weights are documented (1.0 premium, 1.0 size-vs-OI, 0.8 aggressor, 1.0 sweep, 1.2 opening_bias, 0.6 tenor, sum 5.6). Sum the breakdown buckets and you get the composite score to within rounding. Reconstruct each normalised component from the trade and OI context and the formulas should match the published numbers exactly.
A relative + absolute conviction badge. A signal is tagged golden if its score is in the top decile of the current result set and meets the absolute floor of 70. The dual gate prevents a quiet session from promoting a mediocre signal just because everything else was even quieter, while still surfacing the standout signals on a busy session.
Because the live chain on the flow surface already folds intraday OI deltas in. Adding the per-signal hypothetical impact on top would double-count. The field is named hypothetical_gex_impact_if_opening to make the conditional explicit: it tells you the standalone gamma-dollar impact of this print if it were fully opening and fully dealer-absorbed, not what to add to the chain. For chain-level live GEX, use the /v1/flow/gex endpoint - it is already simulation-aware.
It depends on what you mean by "predictive". Aggregate net directional premium across a watchlist has weak but non-zero correlation with same-day direction; individual signals are noisy. The Flow Signals score is a quality filter, not a directional oracle. Treat the feed as a screening layer that surfaces trades worth looking at, then add chart context, IV regime, and position relative to walls. The score_breakdown object lets you audit each signal so you can backtest which sub-patterns actually work on your time horizon and execution model.
Most are. FlashAlpha is the explicit exception: every Flow Signals score is the deterministic output of six published formulas, each component's contribution is returned in the score_breakdown object, and the default weights are documented in this article. You can reconstruct any score from the trade + chain context using the formulas above. If a published score does not match the formula, that is a bug we want to know about. Black-box scores cannot be audited, cannot be calibrated, and cannot be trusted at scale - that is the whole reason the methodology paper exists.
Not reliably. A call buyer could be opening a directional bet (bullish), closing a short call they previously wrote (also reduces upside risk but is not fresh conviction), hedging a short stock position (the original bet was bearish), or running one leg of a multi-leg structure (depends on the other legs). The Flow Signals intent classifier handles the open-vs-close ambiguity using the OI simulator and refuses to attribute direction on closing trades. Even with that filter, "smart money buying calls" is a screening signal, not a forecast. Cross-reference with dealer positioning before treating it as a directional read.
Treat any "follow the smart money" rule as a hypothesis to be backtested on your own time horizon, not a strategy. The Flow Signals feed gives you the raw, scored, audit-able data; whether a specific filter (e.g., top-10 bullish opening sweeps with score ≥ 80, held for N days) generates alpha is an empirical question depending on the underlying, the time window, execution cost, and your benchmark. Persist signals to a database, label outcomes after N days, and measure. The Python scanner article shows the persistence pattern. The audit-friendly score_breakdown lets you iterate on which sub-components carry the signal.

Related Reading

Live Market Pulse

Get tick-by-tick visibility into market shifts with full-chain analytics streaming in real time.

Intelligent Screening

Screen millions of option pairs per second using your custom EV rules, filters, and setups.

Execution-Ready

Instantly send structured orders to Interactive Brokers right from your scan results.

Join the Community

Discord

Engage in real time conversations with us!

Twitter / X

Follow us for real-time updates and insights!

GitHub

Explore our open-source SDK, examples, and analytics resources!