[BUG] Missing cap_queue_ahead in QuoteTick (L1) matching engine path

Author: GwangPyoCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

Summary

When backtesting with queue_position=True using QuoteTick data, cap_queue_ahead is never called during quote updates.

If the displayed size at the best bid or ask decreases without price movement (e.g., due to cancellations), queue_ahead_total remains frozen at its initial value. This leads to an invalid state where queue_ahead_total exceeds the total displayed size at that price level (ahead > displayed).

This logic is already present in the OrderBookDelta path, but missing in the QuoteTick path.

Code Reference

File: crates/execution/src/matching_engine/mod.rs

  1. Delta path (handles size updates properly): In adjust_queue_for_delta (line 880 in develop):
rust
} else if delta.action == BookAction::Update {
    if self.is_order_granular_delta(delta.flags) {
        self.adjust_l3_queue_on_update(&delta.order);
    } else {
        self.cap_queue_ahead(
            delta.order.price.raw(),
            delta.order.size.raw(),
            delta.order.side,
        );
    }
}
  1. QuoteTick path (missing cap_queue_ahead): In decrement_l1_queue_on_quote (line 1023 in develop):
rust
if self.tob_initialized {
    if bid_price_raw < self.prev_bid_price_raw {
        self.adjust_l1_queue_on_price_move(bid_price_raw, bid_size_raw, OrderSide::Buy);
    }
    if ask_price_raw > self.prev_ask_price_raw {
        self.adjust_l1_queue_on_price_move(ask_price_raw, ask_size_raw, OrderSide::Sell);
    }
}
self.resolve_pending_l1_snapshots(bid_price_raw, bid_size_raw, ask_price_raw, ask_size_raw);

Because decrement_l1_queue_on_quote only triggers on price moves and never invokes cap_queue_ahead, resting orders do not reflect size decreases at the same price.

Steps to Reproduce

  1. Configure an engine with config.queue_position = true.
  2. Feed an initial QuoteTick (e.g., bid_price = 100.0, bid_size = 3000).
  3. Submit a resting limit buy order at 100.0.
    • queue_ahead_total is set to 3000.
  4. Feed a subsequent QuoteTick at the same price with reduced size (bid_price = 100.0, bid_size = 500), with no trade ticks.
  5. Check order queue status:
    • Current displayed book size is 500.
    • queue_ahead_total is still 3000.

Expected Behavior

queue_ahead_total should be capped at the current displayed level size (500 in the example above), consistent with the behavior in adjust_queue_for_delta.

Actual Behavior

queue_ahead_total remains at 3000. The order remains unfilled until at least 3000 contracts trade at 100.0, even though only 500 contracts exist at that level.

Proposed Fix

Call cap_queue_ahead at the end of decrement_l1_queue_on_quote:

rust
self.cap_queue_ahead(bid_price_raw, bid_size_raw, OrderSide::Buy);
self.cap_queue_ahead(ask_price_raw, ask_size_raw, OrderSide::Sell);

Source: nautechsystems/nautilus_trader