nautechsystems/nautilus_trader · error

ProbabilityPriceFeeModel requires a binary option instrument

Error message

ProbabilityPriceFeeModel requires a binary option instrument

What it means

ProbabilityPriceFeeModel prices fees using the fill price as a probability, which is only meaningful for binary options. The constructor of get_commission checks the instrument type and bails if it is not a BinaryOption, because for other instruments the [0,1] price-as-probability math is invalid.

Source

Thrown at crates/execution/src/models/fee.rs:453

    feature = "python",
    pyo3::pyclass(
        module = "nautilus_trader.execution",
        extends = PyFeeModel,
        skip_from_py_object
    )
)]
pub struct ProbabilityPriceFeeModel;

impl FeeModel for ProbabilityPriceFeeModel {
    fn get_commission(
        &self,
        order: &OrderAny,
        fill_quantity: Quantity,
        fill_px: Price,
        instrument: &InstrumentAny,
    ) -> anyhow::Result<Money> {
        if !matches!(instrument, InstrumentAny::BinaryOption(_)) {
            anyhow::bail!("ProbabilityPriceFeeModel requires a binary option instrument");
        }

        let fill_price = fill_px.as_decimal();
        if !(Decimal::ZERO..=Decimal::ONE).contains(&fill_price) {
            anyhow::bail!("ProbabilityPriceFeeModel requires a fill price in [0, 1]");
        }

        let fee_rate = match order.liquidity_side() {
            Some(LiquiditySide::Maker) => instrument.maker_fee(),
            Some(LiquiditySide::Taker) => instrument.taker_fee(),
            Some(LiquiditySide::NoLiquiditySide) | None => anyhow::bail!("Liquidity side not set"),
        };

        let one_minus_p = Decimal::ONE - fill_price;
        let commission = mul_checked(fill_quantity.as_decimal(), fee_rate)
            .and_then(|v| mul_checked(v, fill_price))
            .and_then(|v| mul_checked(v, one_minus_p))
            .map(|v| v.round_dp(5))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use MakerTakerFeeModel or a fixed/perpetual fee model for non-binary-option instruments
  2. Restrict the ProbabilityPriceFeeModel to venues/accounts trading binary options
  3. Add an instrument-type check in config loading to pick the correct fee model automatically

Example fix

// before
let fee_model = FeeModelAny::ProbabilityPrice(ProbabilityPriceFeeModel::new(...)?); // used for FX pair
// after
let fee_model = if matches!(instrument, InstrumentAny::BinaryOption(_)) {
    FeeModelAny::ProbabilityPrice(ProbabilityPriceFeeModel::new(...)?)
} else {
    FeeModelAny::MakerTaker(MakerTakerFeeModel::new(...)?)
};
Defensive patterns

Strategy: validation

Validate before calling

if !matches!(instrument, InstrumentAny::BinaryOption(_)) {
    // choose a different fee model for this instrument
}

Type guard

fn is_binary_option(i: &InstrumentAny) -> bool { matches!(i, InstrumentAny::BinaryOption(_)) }

Try / catch

match fee_model.get_commission(&order, qty, px, &instrument) {
    Ok(fee) => fee,
    Err(e) if e.to_string().contains("binary option instrument") => return Err(e.into()),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `ProbabilityPriceFeeModel::get_commission` (or its `new` via get_commission dispatch) passing any InstrumentAny other than InstrumentAny::BinaryOption, e.g. a CurrencyPair, FuturesContract, or CryptoOption.

Common situations: Wiring the wrong fee model in a backtest config for a non-binary market; reusing a fee model across instruments in a portfolio; copy-pasting a binary-option backtest setup for spot/perp trading.

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/5fd1c32b25d284d3. Report an issue: GitHub.