nautechsystems/nautilus_trader · error

Pending position quantity overflow

Error message

Pending position quantity overflow

What it means

When computing a position's quantity for an order (used to decide whether the order closes or opens the position), the matching engine starts from the position's current quantity and checked-adds the quantity_change of every pending fill belonging to that position. If the accumulated Decimal overflows its maximum precision/width, the engine raises this error instead of producing a wrong signed quantity.

Source

Thrown at crates/execution/src/matching_engine/mod.rs:5089

    }

    fn position_quantity_remaining(
        &mut self,
        order: &OrderAny,
        position: &Position,
    ) -> anyhow::Result<Quantity> {
        self.purge_applied_fills();
        let mut quantity = match position.side {
            PositionSide::Long => position.quantity.as_decimal(),
            PositionSide::Short => -position.quantity.as_decimal(),
            PositionSide::Flat => Decimal::ZERO,
        };

        for fill in self.pending_fills.values() {
            if fill.position_id == Some(position.id) {
                quantity = quantity
                    .checked_add(fill.quantity_change)
                    .ok_or_else(|| anyhow::anyhow!("Pending position quantity overflow"))?;
            }
        }

        if (order.is_buy() && quantity >= Decimal::ZERO)
            || (order.is_sell() && quantity <= Decimal::ZERO)
        {
            return Ok(Quantity::zero(position.quantity.precision));
        }
        Ok(Quantity::from_decimal_dp(
            quantity.abs(),
            position.quantity.precision,
        )?)
    }

    fn purge_applied_fills(&mut self) {
        let cache = self.cache.borrow();
        self.pending_fills.retain(|trade_id, fill| {
            fill.position_id = fill

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect pending_fills for the position and confirm they are being consumed/drained after each match cycle.
  2. Reduce order quantity or precision so accumulated quantities fit within the Decimal max supported (max ~18-20 digits with configured precision).
  3. Check for logic that re-queues the same fill repeatedly (e.g. reduce-only or OCO handling) and fix the duplication.
  4. Sanitize instrument quantity/precision configuration so position quantity plus pending fills stays in representable range.

Example fix

// before: accumulating pending fills without bound
let mut quantity = position.quantity();
for fill in pending_fills.values() { quantity = quantity.checked_add(fill.quantity_change).expect("overflow"); }
// after: cap/validate incoming order quantity against representable range
assert!(order.quantity() <= max_representable_qty(instrument), "quantity too large");
let mut quantity = position.quantity();
Defensive patterns

Strategy: validation

Validate before calling

// keep order quantities within a range that survives accumulation with pending fills
let max_qty = Decimal::from_str("999999999999999999")?; // leave headroom below Decimal max
assert!(order.quantity() <= max_qty, "order quantity risks position quantity overflow");

Try / catch

match engine_result {
    Err(e) if e.to_string().contains("Pending position quantity overflow") => {
        log::error!("quantity overflow computing position for {}: {e}", order.client_order_id());
        // cancel the order and investigate pending_fills accumulation
    }
    other => other,
}

Prevention

When it happens

Trigger: Summing position.quantity with many pending fills' quantity_change values whose total exceeds the Decimal max (e.g. extremely large order quantities combined with high precision, or a runaway loop creating unbounded pending fills against one position).

Common situations: Backtests with unrealistic quantity magnitudes or very high price precision instruments; a bug causing pending_fills to accumulate without being drained; OCO/contingent logic repeatedly re-adding fills for the same position.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/1bb2fc85597e21ec. Report an issue: GitHub.