nautechsystems/nautilus_trader · error

BettingAccount requires a sports betting instrument

Error message

BettingAccount requires a sports betting instrument

What it means

BettingAccount's balance-locking calculation is only defined for sports betting instruments; its locked-balance math (settling at odds) does not apply to conventional asset classes. The guard rejects any instrument whose instrument_class is not SportsBetting.

Source

Thrown at crates/model/src/accounts/betting.rs:202

        }

        if event.is_reported {
            self.balances_locked.clear();
        }

        self.base_apply(event);
        Ok(())
    }

    fn calculate_balance_locked(
        &self,
        instrument: &InstrumentAny,
        side: OrderSide,
        quantity: Quantity,
        price: Price,
        use_quote_for_inverse: Option<bool>,
    ) -> anyhow::Result<Money> {
        anyhow::ensure!(
            instrument.instrument_class() == InstrumentClass::SportsBetting,
            "BettingAccount requires a sports betting instrument"
        );
        anyhow::ensure!(
            use_quote_for_inverse != Some(true),
            "`use_quote_for_inverse` is not applicable for betting accounts"
        );

        let locked = match side {
            OrderSide::Sell => quantity.as_decimal(),
            OrderSide::Buy => quantity.as_decimal() * (price.as_decimal() - Decimal::ONE),
        };

        Ok(Money::from_decimal(locked, instrument.quote_currency())?)
    }

    fn calculate_pnls(
        &self,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use a standard account type (e.g. MarginAccount/CashAccount) for non-betting instruments
  2. Ensure the instrument passed is an actual sports betting instrument matching the market data
  3. Check account factory/registration so betting accounts are only used with betting venues
Defensive patterns

Strategy: type-guard

Validate before calling

if instrument.instrument_class() != InstrumentClass.SPORTS_BETTING:
    raise ValueError(f"{instrument.id} is not a sports betting instrument")

Type guard

def is_betting_instrument(instrument) -> bool:
    return instrument.instrument_class() == InstrumentClass.SPORTS_BETTING

Try / catch

try:
    locked = betting_account.calculate_balance_locked(instrument, side, qty, px, None)
except Exception as e:
    log.error(f"betting balance lock failed: {e}")

Prevention

When it happens

Trigger: Calling BettingAccount.calculate_balance_locked with a regular instrument (forex, crypto, equity) instead of a sports betting instrument.

Common situations: Configuring a betting account but routing fills/orders for standard instruments, or reusing a betting account type in a conventional trading setup.

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/8bf9b23f075ff0b7. Report an issue: GitHub.