nautechsystems/nautilus_trader · error · anyhow::Error
Cannot calculate average price: fill quantity is zero
Error message
Cannot calculate average price: fill quantity is zero
What it means
Position::calculate_avg_px requires a nonzero fill quantity (last_qty) to blend into the average; when only the fill quantity is zero it bails, since there is no new price contribution to average and semantics would be ambiguous.
Source
Thrown at crates/model/src/position.rs:1078
qty: f64,
avg_pg: f64,
last_px: f64,
last_qty: f64,
) -> anyhow::Result<f64> {
// Prices can be negative for options and spreads, so only quantities
// are checked for non-negativity here.
debug_assert!(
qty >= 0.0 && last_qty >= 0.0,
"Invariant: average price calc requires non-negative quantities \
(qty={qty}, last_qty={last_qty})"
);
if qty == 0.0 && last_qty == 0.0 {
anyhow::bail!("Cannot calculate average price: both quantities are zero");
}
if last_qty == 0.0 {
anyhow::bail!("Cannot calculate average price: fill quantity is zero");
}
if qty == 0.0 {
return Ok(last_px);
}
let start_cost = avg_pg * qty;
let event_cost = last_px * last_qty;
let total_qty = qty + last_qty;
// Runtime check to prevent division by zero even in release builds
if total_qty <= 0.0 {
anyhow::bail!(
"Total quantity unexpectedly zero or negative in average price calculation: qty={qty}, last_qty={last_qty}, total_qty={total_qty}"
);
}
Ok((start_cost + event_cost) / total_qty)View on GitHub (pinned to 18893faf8b)
Solutions
- Filter out order-filled events with zero quantity before applying them to the position.
- When qty is zero you only need the existing avg price — read it directly instead of calling calculate_avg_px.
- Fix the event source so real fills carry their actual quantity.
Example fix
// before
let avg = position.calculate_avg_px_close_px();
// after
if last_event_qty() == 0.0 {
return position.avg_px_close(); // no fill to blend
}
let avg = position.calculate_avg_px_close_px(); Defensive patterns
Strategy: validation
Validate before calling
if last_qty == 0.0 { return Ok(existing_avg_px); } Prevention
- Filter zero-quantity fills at the event-ingestion layer.
- Model fees/adjustments separately from quantity-bearing fills.
When it happens
Trigger: Calling calculate_avg_px (via calculate_avg_px_open_px / calculate_avg_px_close_px) with a zero-quantity fill event while the existing quantity is nonzero.
Common situations: Processing canceled/partially-filled events misreported as zero-quantity fills, synthetic test events with qty 0, or fee-only adjustments modeled as zero-qty fills.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot calculate average price: both quantities are zero
- Total quantity unexpectedly zero or negative in average pric
- Cannot update position {}: not found in cache
- Cannot update position {position_id}: not found in cache
- Duplicate position fill
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/80c3b7dfebb1899c.
Report an issue: GitHub.