nautechsystems/nautilus_trader · error

trigger_price `{new_trigger:?}` rounds to 0 ticks at precisi

Error message

trigger_price `{new_trigger:?}` rounds to 0 ticks at precision {price_precision}

What it means

For trigger-type orders (StopMarket, StopLimit, MarketIfTouched, LimitIfTouched) the trigger price must convert to a positive tick count at the price_precision. A trigger of zero or one so small it rounds to 0 ticks is invalid, so the adapter ensures trigger_price_ticks > 0 before validating amounts.

Source

Thrown at crates/adapters/lighter/src/execution.rs:1997

        let base_amount = quantity_to_ticks(&new_qty, instrument.size_precision())?;
        anyhow::ensure!(
            base_amount > 0,
            "quantity `{new_qty}` rounds to 0 ticks at size_precision {}",
            instrument.size_precision(),
        );
        let trigger_price_ticks = match new_trigger {
            Some(trigger) if trigger.raw != 0 => price_to_ticks(&trigger, price_precision)?,
            _ => 0,
        };

        if matches!(
            order.order_type(),
            OrderType::StopMarket
                | OrderType::StopLimit
                | OrderType::MarketIfTouched
                | OrderType::LimitIfTouched
        ) {
            anyhow::ensure!(
                trigger_price_ticks > 0,
                "trigger_price `{new_trigger:?}` rounds to 0 ticks at precision {price_precision}",
            );
        }
        validate_order_amount(&instrument, new_qty, price_ticks, price_precision)?;

        let ReservedTxContext {
            context,
            send_reservation,
        } = self.build_tx_context(credential)?;

        let captured_nonce = context.nonce;
        let captured_api_key_index = context.api_key_index;

        let mut rollback_guard =
            TxDispatchGuard::new(self.dispatch.clone(), credential, None, captured_nonce);

        let tx = ModifyOrderTxInfo {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Supply a real trigger_price above one tick at price_precision for trigger order types.
  2. Verify the instrument's price_precision/price_increment and express the trigger in those units.
  3. Guard the command: reject trigger prices <= price_increment before calling modify.

Example fix

// before
let cmd = ModifyOrder { trigger_price: Some(Price::from(0)), ..cmd };
// after
if trigger.as_decimal() <= instrument.price_increment().as_decimal() {
    return Err(anyhow!("trigger {} below one tick", trigger));
}
let cmd = ModifyOrder { trigger_price: Some(trigger), ..cmd };
Defensive patterns

Strategy: validation

Validate before calling

if let Some(t) = cmd.trigger_price {
    if t.as_decimal() < instrument.price_increment().as_decimal() {
        return Err("trigger_price below one tick".into());
    }
}

Try / catch

if let Err(e) = client.modify_order(&cmd).await {
    if e.to_string().contains("trigger_price") && e.to_string().contains("0 ticks") {
        // fix trigger or cancel/re-place with a valid trigger
    }
}

Prevention

When it happens

Trigger: prepare_signed_modify_order computes trigger_price_ticks from new_trigger, and for one of the four trigger order types the value is <= 0 — e.g. trigger_price of 0 on the command, or an extremely low price below one tick at the instrument's price precision.

Common situations: Uninitialized/placeholder trigger (0) passed in a ModifyOrder; price-precision mismatch after switching markets (e.g. tick size 0.01 vs trigger 0.004); Decimal parsing yielding 0 from a malformed string.

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