nautechsystems/nautilus_trader · error · anyhow::Error

Architect AX adapter cannot encode quote_quantity; submit a

Error message

Architect AX adapter cannot encode quote_quantity; submit a base quantity instead

What it means

validate_order_instructions rejects orders with quote_quantity=true: the AX order encoding accepts only a base-size (integer contract count, see quantity_to_contracts), so an order denominated in quote currency (e.g. 'buy $5,000 of BTC-PERP') cannot be encoded. The message tells you the unit mismatch directly - the adapter needs a base quantity instead. Checked at both submit validation and OrderInitialized validation.

Source

Thrown at crates/adapters/architect_ax/src/execution.rs:1923

fn validate_order_init_instructions(order_init: &OrderInitialized) -> anyhow::Result<()> {
    validate_order_instructions(
        order_init.reduce_only,
        order_init.quote_quantity,
        order_init.display_qty.is_some(),
    )
}

fn validate_order_instructions(
    reduce_only: bool,
    quote_quantity: bool,
    has_display_qty: bool,
) -> anyhow::Result<()> {
    if reduce_only {
        anyhow::bail!("AX does not support reduce-only orders");
    }

    if quote_quantity {
        anyhow::bail!(
            "Architect AX adapter cannot encode quote_quantity; submit a base quantity instead"
        );
    }

    if has_display_qty {
        anyhow::bail!("Architect AX adapter cannot encode display_qty iceberg instructions");
    }

    Ok(())
}

// The AX HTTP API documents only a bare 400 with no error schema, so no venue
// failure can be allowlisted as an unambiguous rejection; those arrive via the
// orders WS `Rejected` and `CancelRejected` events instead. AX therefore never
// classifies a send failure as `CommandFailure::VenueRejected`.
fn classify_ax_http_failure(error: &AxHttpError) -> CommandFailure {
    let message = error.to_string();
    match error {

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Compute base size = notional / reference_price and submit that base quantity instead
  2. Round to a whole number of contracts (AX quantities are integers; fractional contracts also fail later in quantity_to_contracts)
  3. Keep the reference-price logic in the strategy so the order you submit is already base-denominated

Example fix

// before
let order = factory.market(id, side, Quantity::from(5_000))
    .quote_quantity(true); // $5000 notional -> error
// after
let base = (5_000.0 / mid_price).floor(); // whole contracts
let order = factory.market(id, side, Quantity::from(base));
Defensive patterns

Strategy: validation

Validate before calling

// Convert notional to base contracts before building the order
let contracts = (notional / ref_price).floor();
ensure!(contracts >= 1.0, "notional too small for one contract");
let qty = Quantity::from(contracts as u64); // integer contracts only
assert!(!order.is_quote_quantity());

Prevention

When it happens

Trigger: factory.market(...).quote_quantity(true) (or an OrderInitialized with quote_quantity set) submitted to the AX execution client; strategies that size entries in USD notional, common when porting from spot adapters.

Common situations: Notional-based position sizing code shared across venues; default templates from adapters where quote-quantity market buys are idiomatic.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/4568ab3abd25bd73. Report an issue: GitHub.