nautechsystems/nautilus_trader · error · anyhow::Error

Failed to convert avg fill price to Decimal: {converted_avg_

Error message

Failed to convert avg fill price to Decimal: {converted_avg_price}

What it means

The adapter converts the IB average fill price (already scaled by the instrument's price magnifier) into a Decimal with from_f64_retain. If the computed avg fill price is NaN or infinite, the conversion returns None and this error is thrown, preventing corrupt notional tracking in order_fill_progress.

Source

Thrown at crates/adapters/interactive_brokers/src/execution/core_updates.rs:935

        let is_spread_order = is_spread_instrument_id(instrument_id);
        if filled <= 0.0 || !parse::should_use_avg_fill_price(avg_fill_price, instrument_id) {
            return Ok(());
        }

        let Some(instrument) = instrument_provider.find(instrument_id) else {
            return Ok(());
        };

        let price_magnifier = instrument_provider.get_price_magnifier(instrument_id) as f64;
        let converted_avg_price = avg_fill_price * price_magnifier;
        let avg_px = Price::new(converted_avg_price, instrument.price_precision());

        order_avg_prices.lock().insert(client_order_id, avg_px);

        let filled_decimal = Decimal::from_f64_retain(filled)
            .ok_or_else(|| anyhow::anyhow!("Failed to convert filled qty to Decimal: {filled}"))?;
        let avg_decimal = Decimal::from_f64_retain(converted_avg_price).ok_or_else(|| {
            anyhow::anyhow!("Failed to convert avg fill price to Decimal: {converted_avg_price}")
        })?;

        let mut progress = order_fill_progress.lock();
        let (previous_filled, previous_notional) = progress
            .get(&client_order_id)
            .copied()
            .unwrap_or((Decimal::ZERO, Decimal::ZERO));
        let total_notional = filled_decimal * avg_decimal;
        progress.insert(client_order_id, (filled_decimal, total_notional));
        drop(progress);

        let fill_delta = filled_decimal - previous_filled;
        if fill_delta <= Decimal::ZERO || !is_spread_order {
            return Ok(());
        }

        let notional_delta = total_notional - previous_notional;
        let partial_avg_decimal = notional_delta / fill_delta;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate avg_fill_price is finite and positive before multiplying by the magnifier.
  2. Verify the instrument's price_magnifier matches the IB contract definition (e.g. 100 for US futures).
  3. Log the raw IB execution report when triggered to find the malformed price source.

Example fix

// before
let converted_avg_price = avg_fill_price * price_magnifier;
// after
if !avg_fill_price.is_finite() || avg_fill_price <= 0.0 {
    tracing::warn!("Skipping avg price update, invalid avg fill price: {avg_fill_price}");
    return Ok(());
}
let converted_avg_price = avg_fill_price * price_magnifier;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate avg fill price and magnifier before scaling
fn valid_avg_price(avg_fill_price: f64, magnifier: f64) -> bool {
    avg_fill_price.is_finite()
        && avg_fill_price > 0.0
        && magnifier.is_finite()
        && magnifier > 0.0
        && (avg_fill_price * magnifier).is_finite()
}

Type guard

fn is_representable_decimal(x: f64) -> bool {
    x.is_finite() && Decimal::from_f64_retain(x).is_some()
}

Try / catch

let avg_decimal = match Decimal::from_f64_retain(converted_avg_price) {
    Some(d) => d,
    None => {
        tracing::error!("Invalid avg fill price {converted_avg_price}; skipping update");
        return Ok(());
    }
};

Prevention

When it happens

Trigger: update_order_avg_price computes converted_avg_price = avg_fill_price * price_magnifier; if avg_fill_price is NaN/inf (or the magnifier is bogus producing inf), Decimal::from_f64_retain fails and the error is raised.

Common situations: IB reports an avg fill price of NaN (e.g. certain combo or what-if executions); wrong price_magnifier configured for the instrument causing overflow to infinity.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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