nautechsystems/nautilus_trader · error

ProbabilityPriceFeeModel requires a fill price in [0, 1]

Error message

ProbabilityPriceFeeModel requires a fill price in [0, 1]

What it means

ProbabilityPriceFeeModel treats the fill price as a probability, so it must lie within [0, 1]. get_commission validates the fill_px decimal against the inclusive range ZERO..=ONE and bails if it is outside, because fee math (fill_price * (1 - fill_price)) is only valid for probabilities.

Source

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

    )
)]
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))?;

        Money::from_decimal(commission, instrument.quote_currency()).map_err(Into::into)
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass binary-option fill prices normalized to the [0, 1] probability range
  2. Check the instrument's price_precision/price_increment so prices are parsed at the correct scale
  3. Verify the fill Price was constructed from the venue's probability quote, not a converted cash price

Example fix

// before
let px = Price::new(55.50, 2); // invalid probability
let fee = model.get_commission(&order, qty, px, &instrument)?;
// after
let px = Price::new(0.555, 3); // probability in [0, 1]
assert!((Decimal::ZERO..=Decimal::ONE).contains(&px.as_decimal()));
let fee = model.get_commission(&order, qty, px, &instrument)?;
Defensive patterns

Strategy: validation

Validate before calling

let d = fill_px.as_decimal();
if !(Decimal::ZERO..=Decimal::ONE).contains(&d) {
    return Err(anyhow::anyhow!("fill price {} not in [0,1]", d));
}

Type guard

fn is_probability_price(px: &Price) -> bool {
    (Decimal::ZERO..=Decimal::ONE).contains(&px.as_decimal())
}

Try / catch

let fee = model.get_commission(&order, qty, px, &instrument)
    .with_context(|| format!("prob-fee calc failed for px={px}"))?;

Prevention

When it happens

Trigger: Calling get_commission with a fill_px whose decimal value is < 0 or > 1, e.g. a Price expressed in whole currency units (like 55.50) rather than 0..1 probability units, or a mis-scaled price.

Common situations: Feeding a regular asset price into the binary-option fee model; price precision/increment config that scales binary option prices outside [0,1]; unit mismatch between venue pricing and internal Price representation.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/81bf9a6f72ceafec. Report an issue: GitHub.