nautechsystems/nautilus_trader · error · anyhow::Error
AX requires whole contract quantities, was {}
Error message
AX requires whole contract quantities, was {} What it means
quantity_to_contracts converts a NautilusTrader fixed-precision Quantity to AX's whole-contract count. ArchitectX deals in integral contracts only, so the raw fixed-point value must be an exact multiple of the FIXED_PRECISION scale (i.e. a whole number); fractional sizes such as 0.5 or 1.25 are rejected with the offending decimal shown. Note this fires even for values < 1 (e.g. 0.5 is fractional, not zero-contract).
Source
Thrown at crates/adapters/architect_ax/src/common/parse.rs:196
}
/// Converts a [`Quantity`] to an i64 contract count for AX orders.
///
/// AX uses integer contracts only. Uses integer arithmetic to avoid
/// floating-point precision issues.
///
/// # Errors
///
/// Returns an error if:
/// - The quantity represents a fractional number of contracts.
/// - The quantity is zero.
pub fn quantity_to_contracts(quantity: Quantity) -> anyhow::Result<u64> {
let raw = quantity.raw;
let scale = 10_u64.pow(FIXED_PRECISION as u32) as QuantityRaw;
// AX requires whole contract quantities
if !raw.is_multiple_of(scale) {
anyhow::bail!(
"AX requires whole contract quantities, was {}",
quantity.as_f64()
);
}
// QuantityRaw is u128 under the `high-precision` feature and u64 otherwise,
// so the narrowing cast is conditional on the active feature set.
#[allow(clippy::unnecessary_cast)]
let contracts = (raw / scale) as u64;
if contracts == 0 {
anyhow::bail!("Order quantity must be at least 1 contract");
}
Ok(contracts)
}
/// Converts a [`ClientOrderId`] to a deterministic AX `cid` in the non-negative `int64` range.
///
/// Inbound WebSocket `cid` values remain `u64` because venue messages can exceed `int64`.View on GitHub (pinned to a4b06ed870)
Solutions
- Round your order size to a whole number of contracts before submitting: qty = float(qty).__floor__() or an explicit round strategy
- Apply risk sizing in contract units rather than fractional notional
- Validate size against the instrument's lot_size before order creation
Example fix
# before (Python strategy)
order = self.factory.market(instrument_id, quantity=Quantity.from_str('2.7'))
# -> AX requires whole contract quantities, was 2.7
# after
order = self.factory.market(instrument_id, quantity=Quantity.from_int(2)) Defensive patterns
Strategy: validation
Validate before calling
qty = self._compute_position_size(...) # float contracts
whole = int(qty) # or use your rounding policy
if whole < 1:
self.log.info(f'Skipping order: size {qty} < 1 contract')
return
order = self.factory.market(instrument_id, quantity=Quantity.from_int(whole)) Type guard
from nautilus_trader.model.objects import Quantity
def is_whole_contracts(qty: Quantity) -> bool:
return qty.as_double() == int(qty.as_double()) Try / catch
# Prefer pre-submission validation; adapter errors arrive async via order rejected events.
# Python strategy guard:
if qty.as_double() % 1 != 0:
qty = Quantity.from_int(int(qty.as_double())) Prevention
- Round sizes to the instrument lot size (or whole contracts for AX) before order creation
- Unit-test sizing code with fractional inputs to prove flooring behavior
- Remember AX is whole-contract only when porting crypto strategies
When it happens
Trigger: Submitting an order to the architect_ax adapter with a fractional quantity — e.g. Quantity.from_str('0.5') on a futures contract — when the adapter converts the size for the venue; commonly a strategy tuned for crypto venues running against AX.
Common situations: Porting crypto strategies (where fractional BTC/ETH sizes are normal) to Architect futures; position sizing math (e.g. risk-based sizing) producing 2.7 contracts; symbol metadata missing so no lot-size rounding occurs upstream.
Related errors
- Order quantity must be at least 1 contract
- Unsupported bar specification for AX: {step}-{:?}
- AX timestamp must be non-negative, was {seconds}
- AX timestamp_ns must be non-negative, was {nanos}
- Unsupported order type: {:?}, the Architect AX adapter accep
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/8a55bcbfa42e4644.
Report an issue: GitHub.