nautechsystems/nautilus_trader · error

Tick size is not exactly representable at Polymarket price…

Error message

Tick size {tick_size} is not exactly representable at Polymarket price precision {POLYMARKET_PRICE_PRECISION}

What it means

After computing min_price = tick_size at POLYMARKET_PRICE_PRECISION, tick_relative_price_bounds verifies the Decimal round-trips exactly. This error is thrown when the tick size has more decimal places than Polymarket's price precision supports, so it cannot be represented exactly.

Solutions

  1. Use only tick sizes that are exact at POLYMARKET_PRICE_PRECISION (e.g. 0.1, 0.01, 0.001 depending on the constant).
  2. If the venue added a new tick precision, bump POLYMARKET_PRICE_PRECISION or extend the supported-tick handling and update tests.
  3. Drop/ignore the instrument update with a warning rather than rebuilding with a rounded price.

Example fix

// before
let tick_size = parse_decimal_exact(new_tick_size)?;
let (min_price, max_price) = tick_relative_price_bounds(tick_size)?;
// after
let tick_size = parse_decimal_exact(new_tick_size)?;
if tick_size.normalize().scale() > POLYMARKET_PRICE_PRECISION as u32 {
    anyhow::bail!("unsupported tick precision for {new_tick_size}");
}
let (min_price, max_price) = tick_relative_price_bounds(tick_size)?;
Defensive patterns

Strategy: validation

Validate before calling

fn tick_representable(tick: Decimal, precision: u8) -> bool {
    tick.normalize().scale() <= precision as u32
}

Type guard

fn is_supported_tick(tick: Decimal) -> bool {
    [dec!(0.1), dec!(0.01), dec!(0.001)].contains(&tick.normalize())
}

Try / catch

match tick_relative_price_bounds(tick_size) {
    Ok(bounds) => bounds,
    Err(e) => { warn!("tick not representable: {e}"); bail!("unsupported tick precision") }
}

Prevention

When it happens

Trigger: create_instrument_from_def or rebuild_instrument_with_tick_size receiving a tick size like 0.001 when POLYMARKET_PRICE_PRECISION only allows fewer decimal places (e.g. 0.01/0.001 vs a 2-dp precision), making min_price.as_decimal() != tick_size.

Common situations: Polymarket introducing non-power-of-ten or finer tick sizes than the adapter's fixed precision, or a market message carrying a tick size with excessive precision.

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

Appendix: source

Thrown at crates/adapters/polymarket/src/http/parse.rs:325

        .ts_event(ts_event)
        .ts_init(ts_init)
        .build()?;

    Ok(InstrumentAny::BinaryOption(rebuilt))
}

// Returns the tradeable price bounds `[tick_size, 1 - tick_size]` for a Polymarket outcome,
// mirroring the venue range enforced in `PolymarketOrderBuilder::validate_limit_price`.
pub(crate) fn tick_relative_price_bounds(tick_size: Decimal) -> anyhow::Result<(Price, Price)> {
    anyhow::ensure!(
        tick_size > Decimal::ZERO,
        "Tick size {tick_size} must be positive"
    );

    let min_price = Price::from_decimal_dp(tick_size, POLYMARKET_PRICE_PRECISION)?;
    let max_price = Price::from_decimal_dp(Decimal::ONE - tick_size, POLYMARKET_PRICE_PRECISION)?;

    anyhow::ensure!(
        min_price.as_decimal() == tick_size,
        "Tick size {tick_size} is not exactly representable at Polymarket price precision {POLYMARKET_PRICE_PRECISION}"
    );
    Ok((min_price, max_price))
}

fn build_info_json(def: &PolymarketInstrumentDef) -> serde_json::Value {
    let mut map = serde_json::Map::new();
    map.insert(
        "token_id".to_string(),
        serde_json::Value::String(def.token_id.to_string()),
    );
    map.insert(
        "condition_id".to_string(),
        serde_json::Value::String(def.condition_id.to_string()),
    );
    map.insert(
        "market_id".to_string(),

View on GitHub (pinned to 18893faf8b)