nautechsystems/nautilus_trader · error · anyhow::Error

quantity size={} cannot be represented with precision={}

Error message

quantity size={} cannot be represented with precision={}

What it means

checked_quantity validates that an f64 size from IB can be exactly represented as a domain Quantity at the given precision. Quantity::new_checked rounds to precision; if the rounded value differs from the original size beyond a tiny tolerance, this error is bailed to avoid silently distorting order/tick quantities.

Source

Thrown at crates/adapters/interactive_brokers/src/data/parse.rs:35

use ibapi::contracts::{OptionComputation, tick_types::TickType};
use nautilus_core::UnixNanos;
use nautilus_model::{
    data::{
        Bar, BarType, IndexPriceUpdate, QuoteTick, TradeTick, greeks::OptionGreekValues,
        option_chain::OptionGreeks,
    },
    enums::{AggressorSide, BookAction, GreeksConvention},
    identifiers::{InstrumentId, TradeId},
    types::{Price, Quantity},
};

fn checked_quantity(size: f64, precision: u8) -> anyhow::Result<Quantity> {
    let quantity = Quantity::new_checked(size, precision)
        .map_err(|e| anyhow::anyhow!("invalid quantity size={size}: {e}"))?;
    let tolerance = 10_f64.powi(-i32::from(precision)) * 1e-9;
    if (quantity.as_f64() - size).abs() > tolerance {
        anyhow::bail!(
            "quantity size={} cannot be represented with precision={}",
            size,
            precision
        );
    }
    Ok(quantity)
}

/// Parse IB tick price and size data into a QuoteTick.
///
/// This builds a quote from individual tick updates. You typically need to accumulate
/// bid/ask prices and sizes from multiple tick updates before creating a QuoteTick.
///
/// # Errors
///
/// Returns an error if price or size conversion fails.
#[allow(clippy::too_many_arguments)]
pub fn parse_quote_tick(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Increase the precision argument to match the instrument's allowed quantity precision
  2. Verify the instrument definition in the cache has correct quantity precision
  3. Sanitize/round the size at the source (IB) before parsing
  4. Reject or rescale the tick if the size is genuinely finer-grained than the instrument supports

Example fix

// before
let qty = checked_quantity(size, 2)?;
// after
let qty = checked_quantity(size, instrument.precision() /* e.g. 6 */)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_representable(size: f64, precision: u8) -> bool {
    let rounded = round_to_precision(size, precision);
    (rounded - size).abs() <= 10f64.powi(-i32::from(precision)) * 1e-9
}
// guard: if !is_representable(size, precision) { return Err(...); }

Type guard

fn valid_quantity(size: f64, precision: u8) -> Option<f64> {
    if !size.is_finite() { return None; }
    let tol = 10f64.powi(-i32::from(precision)) * 1e-9;
    ((size.round() - size).abs() <= tol).then_some(size)
}

Try / catch

match checked_quantity(size, precision) {
    Ok(q) => q,
    Err(e) => { warn!("skipping tick with unusable size: {e}"); return Ok(()); }
}

Prevention

When it happens

Trigger: parse_quote_tick or parse_trade_tick passes a size like 0.1234567 to checked_quantity with a small precision (e.g. 2 or 3), so rounding changes the value more than the tolerance; also triggered by NaN/inf-ish or absurdly large f64 sizes.

Common situations: Crypto/forex instruments with sub-tick sizes exceeding the configured precision; precision derived from the instrument definition not matching IB-reported sizes; wrong precision passed by the caller.

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/b409a7b2cfb08b7b. Report an issue: GitHub.