Queue Position Modeling for Passive Orders

Queue position is the difference between posting a limit order and actually getting filled. A bid can be the best price for seconds yet receive nothing because older orders stand ahead of it. Conversely, a fill is not automatically good news: it may arrive because informed sellers know the fair value is lower. A useful model therefore estimates both fill probability and the conditional cost of a fill.

Price-time priority is common but not universal. Pro-rata matching, retail priority, hidden liquidity, and venue-specific allocation rules alter the economics. Confirm the matching rule before fitting parameters. The reconstructed order-level state in order book replay is ideal; without IDs, queue position is a latent variable rather than an observed fact.

The basic queue calculation

For a newly posted buy at price \(p\), initial queue ahead is displayed bid size at \(p\):

def initial_queue_ahead(book, price, own_size):
    displayed = book.bid_size(price)
    return max(0, displayed - own_size)  # if book already includes our order

Thereafter, executions at the price reduce queue ahead, cancellations may reduce it, and new same-price orders join behind under price-time priority. The hard part is allocating cancelled size: with aggregated data we do not know whether cancellation came ahead of us. A naive assumption that every cancellation improves our rank systematically overstates fills.

ModelCancellation allocationTypical use
ConservativeNone helps our orderUpper bound on wait
UniformCancelled size allocated by rankFast baseline
ProbabilisticEstimate ahead-cancel share from IDsProduction approximation
Order-levelExact ID orderingBest available benchmark

A probabilistic queue model

Let \(Q0\) be displayed quantity ahead, \(Et\) executed quantity at our price, and \(C_t\) cancellations. With an estimated fraction \(\rho\) of cancellations ahead:

\[ Qt = \max(0, Q0 - Et - \rho Ct) \]

The order fills when cumulative consumption after priority reaches its size. Estimate \(\rho\) by instrument, time of day, side, spread regime, and volatility bucket from order-ID data. It is often lower than a uniform model implies because traders cancel young quotes after their signals change.

def queue_remaining(q0, executions, cancels, rho):
    return max(0.0, q0 - executions - rho * cancels)

def fill_fraction(q_remaining, own_qty, consumed_after):
    return min(1.0, max(0.0, (consumed_after - q_remaining) / own_qty))

The model must update in event time. A one-second bucket can hide a cancel-then-trade ordering that changes a simulated fill from zero to full.

Fill probability is only half the objective

Estimate a conditional response such as:

\[ E[r{t\rightarrow t+h} \mid \text{passive fill}, Xt] \]

where the sign is measured against the maker. A bid fill followed by a negative return is adverse selection. Combine this with fees, rebates, and opportunity cost:

ComponentBuy-limit interpretation
Fill probabilityChance to acquire exposure
Spread captureValue if price subsequently mean reverts
Rebate/feeVenue-dependent fixed bps
Adverse selectionExpected post-fill loss
Non-fill costMissed alpha or forced crossing later

This is why high fill rate can be a warning. Orders at the touch during a toxic sell program fill reliably and then lose. Link the queue estimate to imbalance, volatility, trade sign, and the features discussed in adverse selection.

Backtest and calibration traps

Never fill every resting order whenever a trade print reaches its price. Prints may reflect hidden execution, another venue, or liquidity ahead. Calibrate simulated fills against actual child-order outcomes, partitioned by queue percentile. Report predicted versus realized fill rates and post-fill returns, not one aggregate metric.

Queue behavior is nonstationary. Opening, closing, and event windows have different cancellation and displayed-depth patterns. Treat the close as its own regime, especially when auction liquidity takes over; auction mechanics explains why continuous-book assumptions then fail.

Key takeaways

  • Displayed depth is not queue position; priority and cancellation attribution matter.
  • Use order-level data to calibrate, then apply conservative models where IDs are absent.
  • Update queues in exchange event order, not coarse time buckets.
  • Optimize expected passive value: fills, fees, adverse selection, and non-fill cost.
  • Validate fill predictions by regime and queue percentile against live outcomes.
#queue position #limit orders #execution #market microstructure #Python