{"record":{"id":"f87d6a6caf1966db","repo":"nautechsystems/nautilus_trader","slug":"polymarketfeemodel-requires-a-fill-price-in-0-1","errorCode":null,"errorMessage":"PolymarketFeeModel requires a fill price in [0, 1]","messagePattern":"PolymarketFeeModel requires a fill price in \\[0, 1\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/models.rs","lineNumber":87,"sourceCode":"            }\n        };\n\n        let Some(schedule) = binary\n            .info\n            .as_ref()\n            .and_then(|info| info.get(\"fee_schedule\"))\n            .map(|value| serde_json::from_value::<FeeSchedule>(value.clone()))\n            .transpose()\n            .context(\"invalid Polymarket fee schedule\")?\n        else {\n            return Ok(Money::zero(instrument.quote_currency()));\n        };\n\n        validate_schedule(&schedule)?;\n\n        let fill_price = fill_px.as_decimal();\n        if !(Decimal::ZERO..=Decimal::ONE).contains(&fill_price) {\n            anyhow::bail!(\"PolymarketFeeModel requires a fill price in [0, 1]\");\n        }\n\n        let fee_equivalent = fill_quantity\n            .as_decimal()\n            .checked_mul(schedule.rate)\n            .and_then(|value| value.checked_mul(fill_price))\n            .and_then(|value| value.checked_mul(Decimal::ONE - fill_price))\n            .context(\"commission calculation overflow\")?;\n        let commission = match liquidity_side {\n            LiquiditySide::Maker => -fee_equivalent\n                .checked_mul(schedule.rebate_rate)\n                .context(\"commission calculation overflow\")?\n                .round_dp(5),\n            LiquiditySide::Taker => fee_equivalent.round_dp(5),\n            LiquiditySide::NoLiquiditySide => unreachable!(),\n        };\n\n        Money::from_decimal(commission, instrument.quote_currency()).map_err(Into::into)","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/models.rs#L69-L105","documentation":"Polymarket fees are charged as fee_rate * shares * price, which is only defined for prices in [0, 1] (probability space). get_commission validates the fill price and bails if it falls outside that closed interval. An out-of-range fill price indicates corrupted pricing data or a wrong instrument/price precision.","triggerScenarios":"Calling get_commission with a fill_px outside [0, 1] — e.g. a price in cents (55 instead of 0.55), a price built with the wrong precision, or a negative/garbage price from a bad data feed.","commonSituations":"Mixing prices from another venue/precision; synthetic test fills using 0–100 probability scale; corrupted fill reports from a broken data source.","solutions":["Convert fill prices to Polymarket's 0–1 decimal scale before fee calculation (divide by 100 if in percent).","Verify the Price was constructed with POLYMARKET_PRICE_PRECISION and the correct scale.","Validate fill prices at ingestion (reject/clamp values outside [0,1]) before the engine computes commission.","Check the data feed producing the fill price for precision bugs."],"exampleFix":"// before\nlet fill_px = Price::from_raw(55000000000); // wrong scale\n// after\nlet fill_px = Price::new(0.55.into(), POLYMARKET_PRICE_PRECISION)?;","handlingStrategy":"validation","validationCode":"let d = fill_px.as_decimal();\nif !(Decimal::ZERO..=Decimal::ONE).contains(&d) {\n    return Err(format!(\"fill price {d} outside [0,1]\"));\n}","typeGuard":"fn is_valid_probability_price(px: &Price) -> bool {\n    let d = px.as_decimal();\n    d >= Decimal::ZERO && d <= Decimal::ONE\n}","tryCatchPattern":"match fee_model.get_commission(&order, qty, px, &instrument) {\n    Ok(fee) => fee,\n    Err(e) if e.to_string().contains(\"fill price in [0, 1]\") => {\n        log::error!(\"invalid fill price {} — check data feed precision\", px);\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Build all Polymarket prices with POLYMARKET_PRICE_PRECISION on the 0–1 scale.","Never reuse prices from percent-scaled feeds without conversion.","Validate prices at ingestion boundaries."],"tags":["fees","validation","polymarket","prices"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}