nautechsystems/nautilus_trader · error · anyhow::Error

Interactive Brokers only accepts a quote quantity (`cash_qty

Error message

Interactive Brokers only accepts a quote quantity (`cash_qty`) for BUY orders; a SELL must use the base quantity

What it means

IBKR accepts a quote-quantity (`cash_qty`) order only for BUY sides on inverse instruments (e.g. PAXOS crypto pairs). When the adapter's quantity policy detects an inverse instrument and a quote-quantity order, a SELL side cannot be expressed as a cash quantity, so it bails instead of emitting a malformed IB order.

Source

Thrown at crates/adapters/interactive_brokers/src/execution/transform/policy.rs:52

pub(super) fn apply_account_policy(ib_order: &mut IBOrder, order: &OrderAny) {
    if let Some(account_id) = order.account_id() {
        ib_order.account = account_id.to_string();
    }
}

pub(super) fn apply_quantity_policy(
    ib_order: &mut IBOrder,
    order: &OrderAny,
    instrument_provider: &InteractiveBrokersInstrumentProvider,
) -> anyhow::Result<()> {
    if let Some(instrument) = instrument_provider.find(&order.instrument_id())
        && instrument.is_inverse()
        && order.is_quote_quantity()
    {
        // IBKR accepts a cash quantity (`cash_qty`) only for BUY orders on these instruments
        // (e.g. PAXOS crypto); a SELL must use the base/coin quantity (`total_quantity`).
        if order.order_side() != OrderSide::Buy {
            anyhow::bail!(
                "Interactive Brokers only accepts a quote quantity (`cash_qty`) for BUY orders; \
                 a SELL must use the base quantity"
            );
        }
        ib_order.cash_qty = Some(order.quantity().as_f64());
        ib_order.total_quantity = 0.0;
    }
    Ok(())
}

pub(super) fn apply_trailing_order_policy(
    ib_order: &mut IBOrder,
    order: &OrderAny,
    price_magnifier: f64,
) -> anyhow::Result<()> {
    if !matches!(
        order.order_type(),
        NautilusOrderType::TrailingStopMarket | NautilusOrderType::TrailingStopLimit

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Express the SELL quantity in base currency: use instrument.make_qty(base_amount) instead of quote quantity when constructing the order
  2. Convert the quote value to base via the instrument's price/size before submitting (e.g. divide quote notional by price, rounded to size increment)
  3. If your intent is a notional-based SELL, place it on a non-inverse instrument or use IBKR's base-quantity API semantics

Example fix

// before
let order = order_factory.market(OrderSide::Sell, instrument.make_qty(1000.0.into())); // wrong units
// after
let base_qty = quote_notional / price;
let order = order_factory.market(OrderSide::Sell, instrument.make_qty(base_qty));
Defensive patterns

Strategy: validation

Validate before calling

if instrument.is_inverse() && order.is_quote_quantity() && order.order_side() != OrderSide::Buy {
    return Err(anyhow::anyhow!("SELL with quote quantity unsupported on inverse IBKR instruments; convert to base quantity"));
}

Type guard

fn is_ibkr_cash_qty_compatible(instrument: &Instrument, order: &dyn Order) -> bool {
    !(instrument.is_inverse() && order.is_quote_quantity() && order.order_side() != OrderSide::Buy)
}

Prevention

When it happens

Trigger: Calling nautilus_order_to_ib_order -> apply_quantity_policy with an inverse instrument (instrument.is_inverse()) and an order whose quantity is expressed in quote currency (order.is_quote_quantity()) while order.order_side() == OrderSide::Sell.

Common situations: Placing SELL orders on inverse crypto CFDs where the strategy sizes positions in quote (USD) value instead of base coin amount; porting strategies that work on BUYs and failing on the closing SELL.

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/135eb44d2c303257. Report an issue: GitHub.