nautechsystems/nautilus_trader · error
quantity for {currency} loses precision when decreasing raw
Error message
quantity for {currency} loses precision when decreasing raw scale What it means
When the quantity's source precision is higher than the target precision, the raw value must be divided down by 10^(source-target). If the raw value is not exactly divisible, the conversion would lose precision, so ensure! raises this error rather than truncating silently — preserving exact discrete values.
Source
Thrown at crates/portfolio/src/manager.rs:1432
fn wallet_money_from_quantity(quantity: Quantity, currency: Currency) -> anyhow::Result<Money> {
anyhow::ensure!(!quantity.is_undefined(), "quantity was undefined");
Quantity::from_raw_checked(quantity.raw, quantity.precision)?;
check_fixed_raw_u128(u128::from(quantity.raw), quantity.precision)?;
let source_precision = quantity.precision.max(FIXED_PRECISION);
let target_precision = currency.precision.max(FIXED_PRECISION);
let raw = i128::try_from(u128::from(quantity.raw))
.map_err(|_| anyhow::anyhow!("quantity for {currency} exceeds signed raw bounds"))?;
let raw = match source_precision.cmp(&target_precision) {
Ordering::Less => {
let scale = 10_i128.pow(u32::from(target_precision - source_precision));
raw.checked_mul(scale).ok_or_else(|| {
anyhow::anyhow!("quantity for {currency} overflowed while increasing raw scale")
})?
}
Ordering::Greater => {
let scale = 10_i128.pow(u32::from(source_precision - target_precision));
anyhow::ensure!(
raw % scale == 0,
"quantity for {currency} loses precision when decreasing raw scale"
);
raw / scale
}
Ordering::Equal => raw,
};
check_fixed_raw_i128(raw, currency.precision)?;
let raw: MoneyRaw = raw
.try_into()
.map_err(|_| anyhow::anyhow!("quantity for {currency} exceeds Money raw bounds"))?;
Money::from_raw_checked(raw, currency).map_err(Into::into)
}
fn reservation_precisions_match(
account: &dyn Account,
reservations: &AHashMap<Currency, Money>,View on GitHub (pinned to 18893faf8b)
Solutions
- Round/quantize the quantity to the currency precision before calling the wallet update
- Align the currency's precision configuration with the instrument quote precision
- Use the instrument's size/price precision when constructing Quantity values
- If truncation is acceptable for your use case, explicitly round before the call instead of relying on the manager
Example fix
// before let qty = Quantity::new(0.123456789, 9); // currency precision 2 manager.update_balance_locked_wallet(&instrument.id(), asset, qty)?; // after let qty = Quantity::new(qty.as_f64(), currency.precision.max(FIXED_PRECISION)); // pre-rounded manager.update_balance_locked_wallet(&instrument.id(), asset, qty)?;
Defensive patterns
Strategy: validation
Validate before calling
let target_p = currency.precision.max(FIXED_PRECISION);
if quantity.precision > target_p {
let scale = 10_u64.pow((quantity.precision - target_p) as u32);
anyhow::ensure!(quantity.raw % scale == 0, "quantity {} not representable at precision {target_p}", quantity);
} Try / catch
manager.update_balance_locked_wallet(&id, currency, quantity)
.unwrap_or_else(|e| { warn!("precision loss for {currency}: {e}; rounding quantity"); }); Prevention
- Round quantities to the currency/FIXED precision before wallet updates
- Configure currency precision to cover the instrument's quote precision
- Clamp adapter-reported fill precision to the instrument specification
When it happens
Trigger: Converting a Quantity with more decimal places than the target currency's (or FIXED) precision, where the raw value has non-zero digits in the dropped positions — e.g. quantity precision 8 converted to currency precision 2 with raw not a multiple of 10^6.
Common situations: Trading instruments quoted with more precision than the settlement currency supports; misconfigured currency precision; adapters reporting fills with extra precision beyond the instrument's spec.
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
- quantity for {currency} exceeds signed raw bounds
- quantity for {currency} overflowed while increasing raw scal
- Instrument not found in cache: {symbol}
- List of Positions is empty
- value rounded to zero for quantity
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a3bc1a77d748c35e.
Report an issue: GitHub.