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.

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.

Appendix: 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)