nautechsystems/nautilus_trader · error

fee price must be in [0, 1]

Error message

fee price must be in [0, 1]

What it means

fee_curve_rate requires price to be in the inclusive range [0, 1], since Polymarket binary-outcome prices are probabilities. A price outside that range (e.g. 1.5 or a percentage like 55 instead of 0.55) makes the fee curve meaningless and is rejected.

Source

Thrown at crates/adapters/polymarket/src/execution/parse.rs:616

        return Ok(Decimal::ZERO);
    }
    let commission = size
        .checked_mul(rate)
        .context("commission calculation overflow")?;
    Ok(commission.round_dp(5))
}

fn fee_curve_rate(
    fee_rate: Decimal,
    price: Decimal,
    fee_exponent: Decimal,
) -> anyhow::Result<Decimal> {
    anyhow::ensure!(fee_rate >= Decimal::ZERO, "fee rate must be non-negative");
    anyhow::ensure!(
        fee_exponent >= Decimal::ZERO,
        "fee exponent must be non-negative"
    );
    anyhow::ensure!(
        (Decimal::ZERO..=Decimal::ONE).contains(&price),
        "fee price must be in [0, 1]"
    );

    if fee_rate.is_zero() {
        return Ok(Decimal::ZERO);
    }
    let base = price * (Decimal::ONE - price);
    let base_f64: f64 = base
        .try_into()
        .context("fee curve base is not representable")?;
    let exponent_f64: f64 = fee_exponent
        .try_into()
        .context("fee exponent is not representable")?;
    let curve =
        Decimal::try_from(base_f64.powf(exponent_f64)).context("fee curve is not representable")?;
    fee_rate
        .checked_mul(curve)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Convert the price to the 0–1 decimal scale (divide percentages by 100) before calling compute_commission.
  2. Verify the price feed value actually came from the market book and is not scaled in cents.
  3. Add a pre-call range check so out-of-range prices are caught and logged upstream.

Example fix

// before
let price = Decimal::from_str("55.0")?; // percentage
let fee = compute_commission(fee_rate, price, fee_exponent)?;
// after
let price = Decimal::from_str("0.55")?; // probability scale
let fee = compute_commission(fee_rate, price, fee_exponent)?;
Defensive patterns

Strategy: validation

Validate before calling

if !(Decimal::ZERO..=Decimal::ONE).contains(&price) { return Err(anyhow!("price out of [0,1]: {price}")); }

Type guard

fn is_probability(p: Decimal) -> bool { p >= Decimal::ZERO && p <= Decimal::ONE }

Prevention

When it happens

Trigger: Calling compute_commission or adjust_market_buy_amount with a price outside [0, 1] — most commonly a percentage-scale price (e.g. 55.0) or a raw price > 1 from a mis-scaled feed.

Common situations: Unit confusion between percentage points and probability fractions; a venue feed returning cents (e.g. 55) instead of the 0–1 decimal; stale test fixtures with wrong scaling.

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