Opening vs Closing Bias on Options Flow: How the OI Simulator Tags Trades and Why Closing Trades Are Neutral | FlashAlpha

Opening vs Closing Bias on Options Flow: How the OI Simulator Tags Trades and Why Closing Trades Are Neutral

How FlashAlpha infers opening vs closing options flow via the OI simulator, the 0.43 confidence cap, and why closing trades collapse to Neutral intent.

T
Tomasz Dobrowolski Quant Engineer
May 23, 2026
34 min read
OptionsFlow OpenInterest UnusualOptions OISimulator Methodology FlowSignals API

Consider two trades on the same SPY 590 call: a 5,000-lot buyer at the ask, and a 5,000-lot seller at the bid. Both prints look unusual. The classical unusual-activity feed would surface both as "high size" signals. But they mean opposite things if the buyer is opening a new position and the seller is closing one - one is fresh directional conviction, the other is risk being taken off.

The OPRA tape carries the price, size, side, and timestamp. It does not carry an open/close tag. Side classification gets you buyer-vs-seller; opening-vs-closing needs an inference layer on top. The FlashAlpha Flow Signals API runs that inference layer through the same OI simulator that powers the effective open interest methodology. This article explains the inference, the calibration that bounds it, and the design choices that follow.

0.43
OI simulator confidence weight - the ceiling on the opening-bias score component
3
Distinct bias tags surfaced: OpeningBias, ClosingBias, Unknown
Neutral
Intent assigned to every closing trade because direction is unrecoverable from the tape

Why Open vs Close Matters

A long call profits if the underlying rises. Opening a long call by buying it is bullish. Closing a long call by selling it is the unwind of an earlier bullish bet - directionally neutral by the time of the close. Same call, same option, opposite implications.

Opening flow
  • Fresh directional position
  • Adds dealer hedging requirement
  • Strong intent signal
  • Bullish if buy-call or sell-put
  • Bearish if sell-call or buy-put
Closing flow
  • Existing position being unwound
  • Reduces dealer hedging requirement
  • Direction of the original bet is unknown
  • Looks identical on the tape to opening flow
  • FlashAlpha intent: Neutral

For dealer-positioning analysis (the kind that feeds walls and gamma flip), the opening or closing nature determines the sign of the GEX adjustment. For trade-intent analysis (which an unusual-activity feed is), the open or close determines whether a signal carries a directional bet at all.

The OPRA Tape Cannot Tell You

The OPRA consolidated tape publishes each option trade with its price, size, exchange, side classification, and the NBBO at the time of execution. It does not publish whether the trade opened or closed a position - that information lives at the clearing firm, not on the tape.

Open interest itself is broadcast once per day, before the morning open, via OPRA's StatType=9 message. By 10:00 AM ET, that number is already stale relative to the day's executions. Without a real-time inference, an open or close classification at the per-trade level would require waiting for the next morning's OI broadcast and back-computing. The intraday signal you need disappears.

This is the core problem that the OI simulator was built to solve. The methodology is documented in the Effective Open Interest paper: a side-classified flow accumulator runs continuously against the OPRA feed and maintains a per-contract signed intraday OI delta. That delta is what the Flow Signals scorer reads to assign opening or closing bias.

How the Bias Is Inferred

The inference rule is straightforward. For each contract, the OI simulator maintains a signed running delta. If the day's flow has been net-buying on that contract, the delta is positive. If it has been net-selling, the delta is negative. A trade arriving on that contract inherits the directional sign of the accumulated delta as its opening-or-closing tag.

Opening / Closing Bias Classifier $$ \text{bias} = \begin{cases} \text{OpeningBias} & \Delta\text{OI}_{\text{intraday}} > 0 \\ \text{ClosingBias} & \Delta\text{OI}_{\text{intraday}} < 0 \\ \text{Unknown} & \Delta\text{OI}_{\text{intraday}} = 0 \text{ or no confidence} \end{cases} $$

A positive accumulated delta on a contract means the simulator is reading the day's flow on that contract as net-opening. A new trade on the same contract is tagged OpeningBias. A negative accumulated delta means the day's flow is net-closing; the new trade is tagged ClosingBias. Zero delta or no simulator confidence means the bias is Unknown.

The bias is per-contract, not per-trade. Two trades on the same contract on the same day inherit the same bias tag - because the accumulated delta is the simulator's best view of what is happening on that contract overall, not a judgment about either individual trade. This is honest about the underlying inference: the simulator cannot tell you that this specific trade opens or closes, only what the contract's flow has been doing in aggregate today.

The 0.43 Confidence Ceiling

The simulator's per-trade confidence is 0.43 - meaning we treat 43% of side-classified volume as opening new positions, with the remaining 57% closing existing positions or being dealer-internalised. The number is empirical, calibrated daily against next-morning settled OI residuals. The full calibration story is in the Effective OI methodology paper.

That same 0.43 propagates into the Flow Signals scorer as a hard ceiling on the opening-bias score component:

Opening-Bias Component (from the Flow Signals scorer) $$ n_{\text{opening}} = \text{bias\_score} \times \text{oi\_confidence} $$ $$ \text{bias\_score} = \begin{cases} 1.0 & \text{OpeningBias} \\ 0.3 & \text{ClosingBias} \\ 0.5 & \text{Unknown} \end{cases} $$

Even a "perfect" opening signal (bias_score = 1.0) contributes only 0.43 to the normalised component, never 1.0. With the default weight of 1.2 and a total weight of 5.6, the opening-bias bucket can contribute at most:

$$ \max(\text{opening\_bias contribution}) = 100 \times \frac{1.2 \times 0.43}{5.6} \approx \textbf{9.2 points} $$

Roughly 9 of the 100 total score points. Meaningful, but never dominant. This ceiling is the most important honesty constraint in the entire scorer.

The reasoning: the underlying inference is calibrated to about 43% confidence per trade. A scoring model that gave full credit to opening signals would be claiming a precision the data cannot support. By multiplying through by the simulator's own confidence weight, the score reflects honest uncertainty rather than overclaiming. The trade-off is that opening bias never dominates the score - which is the point. It is one input among six, not the answer.

Why Closing Trades Have Neutral Intent

The intent classifier is the directional layer that sits on top of bias. It turns the combination of side (buy or sell) and right (call or put) into a Bullish / Bearish / Neutral label. The classifier has one strict rule that overrides every other consideration:

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

Every trade tagged ClosingBias gets intent = Neutral. No exceptions. The rationale is unrecoverability:

Why direction is unrecoverable on a close

A closing trade unwinds an existing position. The tape can tell you what is being unwound (a 5,000-lot sell of an existing long-call position is observable as a sell-call print), but it generally cannot tell you which direction the unwinder originally bet. A 5,000-lot long-call holder closing now might have been bullish a week ago and lost faith; or might be a bearish hedger closing a defensive long-call hedge; or might be a market-maker neutralising inventory; or might be a multi-leg strategy unwinder. Calling that close "Bullish" or "Bearish" would require knowing the original intent, which the OPRA tape does not carry.

The intent classifier refuses to guess. ClosingBias trades go to Neutral, and the consumer reads the open_close_bias = ClosingBias field directly if they want to analyse closing flow separately.

The opposite policy - assigning "Bearish" to closing buyers and "Bullish" to closing sellers under the assumption that they are exiting opposite-direction bets - is what most opaque UOA feeds implicitly do when they treat every print as directional. The result is a feed that double-signals the same news event: the open print fires bullish, the close print three days later fires bearish, and the watching trader is whipsawed by what was actually one round-trip. Refusing to attribute direction on closes avoids this.

How the Bias Fields Appear in the Response

Every signal in the /v1/flow/signals/{symbol} response carries three bias-related fields. Reading all three together is how you separate fresh positioning from unwind.

FieldTypeMeaning
open_close_biasstringopening_bias, closing_bias, or unknown - the OI simulator's tag for this contract
open_close_confidencenumberThe simulator's confidence on this contract (0.43 when the simulator has signal, 0 when it does not)
contract_net_oi_deltaintegerThe signed accumulated intraday delta for this contract - the raw input the bias tag was derived from
intentstringbullish, bearish, or neutral - the directional label, gated by the closing-bias rule above
tagsarrayIncludes opening or closing when the bias is non-Unknown, for fast filtering
{
  "ts": "2026-05-22T15:42:18.103Z",
  "expiry": "2026-06-19",
  "strike": 595.0,
  "right": "C",
  "side": "buy",
  "size": 4500,
  "premium": 1080000.0,
  "open_close_bias": "opening_bias",
  "open_close_confidence": 0.43,
  "contract_net_oi_delta": 12800,
  "intent": "bullish",
  "tags": ["sweep", "opening", "whale"],
  "score": 76,
  "score_breakdown": {
    "premium":      23,
    "size_vs_oi":   10,
    "aggressor":    13,
    "sweep":        18,
    "opening_bias":  9,
    "tenor":         3
  }
}

The signal above is a 4,500-lot SPY 595 call buyer arriving on a contract with +12,800 accumulated intraday delta. The simulator reads the contract's day as net-opening; the bias is OpeningBias; the intent is Bullish; the opening-bias bucket contributes 9 score points (the maximum the 0.43 ceiling allows).

The summary endpoint splits opening from closing

The companion /v1/flow/signals/{symbol}/summary endpoint reports opening_premium and closing_premium as separate aggregates. A session with rising opening_premium and falling closing_premium is fresh positioning; the reverse is position unwinding. Combine both signals on a dashboard to read the direction of the day's flow without confusing fresh bets with exits.

Edge Cases and Honest Limitations

Three patterns are worth knowing.

Zero Delta on a New or Illiquid Contract

If a contract has had no flow today (delta = 0) or the simulator has zero confidence on it (no settled OI baseline or just-listed), the bias is Unknown. The opening-bias component contributes 0.5 × 0 = 0 to the score. Trades on these contracts can still rank high on other components (premium, sweep, size-vs-OI) but get no bias contribution.

Per-Contract, Not Per-Trade

Two trades on the same contract on the same day inherit the same bias tag. If a sweep buyer adds 3,000 contracts of opening flow and another buyer thirty minutes later closes 1,500 contracts, both prints might read OpeningBias if the simulator's net delta is still positive. The bias tag is the simulator's best estimate of the contract's day, not a per-trade judgment.

Roll Activity

On expiration weeks, large multi-leg rolls (close one expiration, open another) can produce a flurry of trades that the simulator's side classifier reads as one-directional. The opening-bias tag fires on the rolled-into expiration; the closing-bias tag fires on the rolled-out-of expiration. From the outside, this looks like simultaneous opening and closing flow on different contracts. Net dealer exposure is roughly preserved, but the per-signal bias tags read as expected for the underlying intent.

None of these limitations make the bias tag useless. They are why the score component is capped at the simulator's 0.43 confidence and why the intent classifier refuses to attribute direction on closes. The system is designed to under-claim rather than over-claim. If you need higher-precision open/close attribution, the right place to add it is downstream, with knowledge of the strategy (e.g., a vertical-spread detector that recognises matched legs as opening or closing the spread as a whole).

Filtering for Opening Flow Only

The signals endpoint does not have a direct ?bias=opening filter, but the tag list and the intent classifier let you achieve the same thing client-side.

import requests

resp = requests.get(
    "https://lab.flashalpha.com/v1/flow/signals/SPY",
    headers={"X-Api-Key": "YOUR_KEY"},
    params={"windowMinutes": 240, "minScore": 60},
)

opening_only = [
    s for s in resp.json()["signals"]
    if s["open_close_bias"] == "opening_bias"
]

for s in opening_only:
    print(
        f"{s['ts']}  {s['expiry']} {s['strike']}{s['right']}"
        f"  {s['side']:>4}  size={s['size']:>5}"
        f"  intent={s['intent']:>8}  score={s['score']}"
    )

For the watchlist version, the summary endpoint exposes opening_premium directly - no client-side filtering needed.

Frequently Asked Questions

Whether a trade is opening a new position or closing an existing one. The OPRA tape carries the side (buyer or seller) but not the open/close tag. FlashAlpha infers it from the OI simulator's per-contract accumulated intraday delta: positive delta tags trades as OpeningBias, negative as ClosingBias, zero as Unknown.
Because the OI simulator's per-trade confidence weight is 0.43, calibrated against next-morning settled OI residuals. The scorer multiplies the bias score by this confidence so a perfect opening signal contributes at most 0.43 of the normalised credit. Giving full credit would overstate what the underlying inference can prove. With default weights, the opening-bias bucket can contribute at most about 9 of the 100 total score points - meaningful but never dominant.
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 require knowing the original intent. Refusing to attribute direction on closes is the honest answer. The closing classification is still surfaced through open_close_bias = closing_bias and the dedicated closing_premium aggregate on the summary endpoint, so consumers can analyse closing flow independently.
At the per-trade level it is a heuristic with 0.43 confidence - the simulator treats 43% of side-classified volume as opening, calibrated against next-morning settled OI residuals. At the per-contract level (which is what the bias tag actually reports), aggregate accuracy is high enough that the median residual across many contracts is close to zero. The score component is capped at the simulator's confidence so that a feed user is never relying on a precision the inference cannot back.
Client-side. The signals endpoint does not currently expose a ?bias= filter, but every signal carries the open_close_bias field and the tag list contains opening or closing when bias is non-Unknown. Filter on open_close_bias == "opening_bias" in your code. For watchlist-level direction signals, use the summary endpoint - it exposes opening_premium and closing_premium as separate aggregates already.
Because that is what the OI simulator can actually prove. The simulator maintains a per-contract accumulated intraday delta. It cannot tell you that this specific trade opens or closes, only what the contract's flow has been doing in aggregate today. Two trades on the same contract on the same day inherit the same bias tag. The honesty constraint is that the inference's resolution is per-contract per-day, and the bias tag reflects exactly that.
Not necessarily. A call buyer could be opening a fresh directional bet (bullish), closing a short call they previously wrote (neutral on the new direction), or hedging short underlying exposure (the original position was bearish). The OPRA tape carries the side but not the open/close. FlashAlpha infers it from the OI simulator's per-contract delta and tags every signal with open_close_bias. A bullish-intent classification only fires on OpeningBias trades; ClosingBias trades collapse to Neutral, because the original direction is unrecoverable from the tape.
The OPRA tape itself cannot tell you. The flow simulator infers it from the running per-contract OI delta: positive delta on the contract today means the day's flow has been net-opening, and new trades inherit OpeningBias; negative delta means net-closing and trades inherit ClosingBias. Two trades on the same contract on the same day get the same tag because that is the resolution the inference can honestly support. The signal carries an open_close_confidence field (currently 0.43) so you can weight the tag by the simulator's calibrated certainty rather than treating it as a binary truth.
Not at the per-trade level. The right framing: a call buyer is paying for upside exposure for some reason - it could be a bullish bet, a hedge against a short stock position, or one leg of a more complex structure. Same for put buyers. The Flow Signals intent classifier handles the most common ambiguity (open vs close) by collapsing closing trades to Neutral. Multi-leg structures (spreads, butterflies, condors) are not detected at this layer, so each leg is classified independently. Use the intent label as a screening signal, not a deterministic directional read.

Related Reading

Get Alpha access

The Flow Signals endpoints are on the Alpha plan. The same key unlocks raw flow data, advanced volatility (SVI surfaces, var swap), VRP analytics, and the live OI simulator state. View pricing, or open the interactive playground to try the endpoints before subscribing.

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!