nautechsystems/nautilus_trader · error · anyhow::Error

AX minimum_order_size must be a positive whole number, was {

Error message

AX minimum_order_size must be a positive whole number, was {}

What it means

The parser requires minimum_order_size to be strictly positive with a zero fractional part, and separately hardcodes size_increment to Decimal::ONE. The adapter assumes whole-unit lots, so a venue-configured fractional minimum (e.g. 0.5) or zero is rejected rather than silently mis-sizing orders.

Source

Thrown at crates/adapters/architect_ax/src/http/parse.rs:206

    {
        &symbol_prefix[..symbol_prefix.len() - quote_code.len()]
    } else {
        symbol_prefix
    };

    let asset_class = AssetClass::from(definition.category);

    // Only resolve base currency for FX/crypto where the base code is a currency
    let base_currency = match asset_class {
        AssetClass::FX | AssetClass::Cryptocurrency => Some(get_currency(base_code)),
        _ => None,
    };

    let quote_currency = get_currency(quote_code);
    let settlement_currency = get_currency(definition.funding_settlement_currency.as_str());

    let price_increment = decimal_to_price(definition.tick_size, "tick_size")?;
    anyhow::ensure!(
        definition.minimum_order_size > Decimal::ZERO
            && definition.minimum_order_size.fract().is_zero(),
        "AX minimum_order_size must be a positive whole number, was {}",
        definition.minimum_order_size
    );
    let size_increment = decimal_to_quantity(Decimal::ONE, "size_increment")?;
    let lot_size = Some(size_increment);
    let min_quantity = Some(decimal_to_quantity(
        definition.minimum_order_size.normalize(),
        "minimum_order_size",
    )?);

    let (margin_init, margin_maint) = parse_margin_rates(
        definition.initial_margin_pct,
        definition.maintenance_margin_pct,
    )?;

    let mut info = Params::new();

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Check the symbol's contract metadata in AX and set a whole-number positive minimum_order_size
  2. If the venue legitimately supports fractional lots, the adapter's sizing model must be extended (derive size_increment from a venue field instead of ONE) — file an issue/PR rather than loosening the check
  3. Until resolved, exclude that symbol from subscription and trading so instrument loads succeed

Example fix

// before (AX contract metadata)
"minimum_order_size": "0.5"
// after
"minimum_order_size": "1"
Defensive patterns

Strategy: try-catch

Validate before calling

// If you control the definitions before they reach the parser
fn min_order_size_ok(v: Decimal) -> bool {
    v > Decimal::ZERO && v.fract().is_zero()
}

if !min_order_size_ok(definition.minimum_order_size) {
    anyhow::bail!("symbol {} has fractional/zero minimum_order_size {}; fix venue config", definition.symbol, definition.minimum_order_size);
}

Try / catch

match parse_instrument(&definition, ts_event, ts_init) {
    Ok(instrument) => Ok(instrument),
    Err(e) if e.to_string().contains("minimum_order_size") => {
        log::error!("symbol {} rejected for fractional min lot size; venue config must use whole units", definition.symbol);
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: An AX symbol is defined with minimum_order_size 0.5 (fractional crypto lots) or 0/omitted-default; the instrument load for that symbol then fails during parsing of tick_size/minimum_order_size validation.

Common situations: Crypto venues that genuinely support fractional minimum lots; new listings with unset minimums defaulting to 0; metadata copied from a permissive exchange into AX contract config.

Related errors


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