{"record":{"id":"135eb44d2c303257","repo":"nautechsystems/nautilus_trader","slug":"interactive-brokers-only-accepts-a-quote-quantity","errorCode":null,"errorMessage":"Interactive Brokers only accepts a quote quantity (`cash_qty`) for BUY orders; a SELL must use the base quantity","messagePattern":"Interactive Brokers only accepts a quote quantity \\(`cash_qty`\\) for BUY orders; a SELL must use the base quantity","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/execution/transform/policy.rs","lineNumber":52,"sourceCode":"pub(super) fn apply_account_policy(ib_order: &mut IBOrder, order: &OrderAny) {\n    if let Some(account_id) = order.account_id() {\n        ib_order.account = account_id.to_string();\n    }\n}\n\npub(super) fn apply_quantity_policy(\n    ib_order: &mut IBOrder,\n    order: &OrderAny,\n    instrument_provider: &InteractiveBrokersInstrumentProvider,\n) -> anyhow::Result<()> {\n    if let Some(instrument) = instrument_provider.find(&order.instrument_id())\n        && instrument.is_inverse()\n        && order.is_quote_quantity()\n    {\n        // IBKR accepts a cash quantity (`cash_qty`) only for BUY orders on these instruments\n        // (e.g. PAXOS crypto); a SELL must use the base/coin quantity (`total_quantity`).\n        if order.order_side() != OrderSide::Buy {\n            anyhow::bail!(\n                \"Interactive Brokers only accepts a quote quantity (`cash_qty`) for BUY orders; \\\n                 a SELL must use the base quantity\"\n            );\n        }\n        ib_order.cash_qty = Some(order.quantity().as_f64());\n        ib_order.total_quantity = 0.0;\n    }\n    Ok(())\n}\n\npub(super) fn apply_trailing_order_policy(\n    ib_order: &mut IBOrder,\n    order: &OrderAny,\n    price_magnifier: f64,\n) -> anyhow::Result<()> {\n    if !matches!(\n        order.order_type(),\n        NautilusOrderType::TrailingStopMarket | NautilusOrderType::TrailingStopLimit","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/execution/transform/policy.rs#L34-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Express the SELL quantity in base currency: use instrument.make_qty(base_amount) instead of quote quantity when constructing the order","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)","If your intent is a notional-based SELL, place it on a non-inverse instrument or use IBKR's base-quantity API semantics"],"exampleFix":"// before\nlet order = order_factory.market(OrderSide::Sell, instrument.make_qty(1000.0.into())); // wrong units\n// after\nlet base_qty = quote_notional / price;\nlet order = order_factory.market(OrderSide::Sell, instrument.make_qty(base_qty));","handlingStrategy":"validation","validationCode":"if instrument.is_inverse() && order.is_quote_quantity() && order.order_side() != OrderSide::Buy {\n    return Err(anyhow::anyhow!(\"SELL with quote quantity unsupported on inverse IBKR instruments; convert to base quantity\"));\n}","typeGuard":"fn is_ibkr_cash_qty_compatible(instrument: &Instrument, order: &dyn Order) -> bool {\n    !(instrument.is_inverse() && order.is_quote_quantity() && order.order_side() != OrderSide::Buy)\n}","tryCatchPattern":null,"preventionTips":["Always size inverse-instrument orders in base currency unless placing BUY cash-qty orders deliberately","Add a pre-submit check in your strategy's order factory wrapper","Unit-test both order sides against inverse instruments in your CI"],"tags":["interactive-brokers","order-quantity","rust","trading"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}