nautechsystems/nautilus_trader · error

Limit order missing price

Error message

Limit order missing price

What it means

Thrown by the Betfair execution client's submit_order when it translates a NautilusTrader order into a Betfair PlaceInstruction. Betfair limit orders are priced bets, so an OrderType::Limit order must carry a Price; order.price() returned None and instruction building aborts before any HTTP request is sent. This is a local validation failure, not a venue rejection.

Source

Thrown at crates/adapters/betfair/src/execution.rs:1778

        let instrument_id = order.instrument_id();
        let market_id = extract_market_id(&instrument_id)?;
        let (selection_id, handicap) = extract_selection_id(&instrument_id)?;

        let side = BetfairSide::from(order.order_side());
        let size = order.quantity().as_decimal();
        let handicap_opt = if handicap == Decimal::ZERO {
            None
        } else {
            Some(handicap)
        };
        let customer_order_ref = Some(make_customer_order_ref(order.client_order_id().as_str()));

        let instruction = match order.order_type() {
            OrderType::Limit => {
                let price = order
                    .price()
                    .ok_or_else(|| anyhow::anyhow!("Limit order missing price"))?
                    .as_decimal();

                // BSP LimitOnClose: participates in starting price calculation
                // with a price limit, using liability instead of size
                if matches!(
                    order.time_in_force(),
                    TimeInForce::AtTheClose | TimeInForce::AtTheOpen
                ) {
                    PlaceInstruction {
                        order_type: BetfairOrderType::LimitOnClose,
                        selection_id,
                        handicap: handicap_opt,
                        side,
                        limit_order: None,
                        limit_on_close_order: Some(LimitOnCloseOrder {
                            liability: size,
                            price,
                        }),

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Set the price when building the limit order: .price(Price::new(value, instrument.price_increment)) using the instrument's tick size.
  2. If you meant a BSP (Betfair Starting Price) bet, keep a price but set TimeInForce::AtTheClose or AtTheOpen (LimitOnClose) — the order quantity then acts as liability.
  3. Pre-validate orders in the strategy before submit_order and log client_order_id so bad orders are caught before reaching the adapter.

Example fix

// before
let order = factory.limit(
    instrument_id,
    side,
    order_qty,
) // no price set
    .build()?;

// after
let price = Price::new("2.04", instrument.price_increment);
let order = factory.limit(
    instrument_id,
    side,
    order_qty,
    price,
).build()?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_betfair_submit_ready(order: &OrderAny) -> bool {
    match order.order_type() {
        OrderType::Limit => order.price().is_some(),
        OrderType::Market => order.time_in_force() == TimeInForce::AtTheClose,
        _ => false,
    }
}

// before engine.submit_order(&order):
assert!(is_betfair_submit_ready(&order), "order {} not valid for BETFAIR", order.client_order_id());

Type guard

fn limit_order_has_price(order: &OrderAny) -> bool {
    order.order_type() == OrderType::Limit && order.price().is_some()
}

Prevention

When it happens

Trigger: Calling submit_order with a Limit order whose builder chain never set a price, e.g. OrderFactory/OrderBuilder usage that omits .price(...) or passes None, routed to the Betfair place_orders instruction builder at execution.rs:1778.

Common situations: Strategies ported from venues where limit orders can be marketable without an explicit price; test/kit orders built with stub factories that skip price; conditional code that submits before the price is computed.

Related errors


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