nautechsystems/nautilus_trader · error · anyhow::Error

Limit-if-touched orders require a trigger price

Error message

Limit-if-touched orders require a trigger price

What it means

Hyperliquid Limit-if-Touched (LIT) orders are trigger orders with is_market=false, so a trigger price is mandatory on the exchange. When the adapter maps OrderType::LimitIfTouched and finds order.trigger_price() is None, it cannot populate the trigger_px field and fails with this bail! before any request reaches the venue.

Source

Thrown at crates/adapters/hyperliquid/src/common/parse.rs:633

            }
        }
        OrderType::LimitIfTouched => {
            if let Some(trigger_price) = order.trigger_price() {
                let raw = trigger_price.as_decimal();
                let trigger_price_decimal = if should_normalize_prices {
                    normalize_price(raw, price_decimals).normalize()
                } else {
                    raw.normalize()
                };
                HyperliquidExchangeOrderKind::Trigger {
                    trigger: HyperliquidExchangeTriggerParams {
                        is_market: false,
                        trigger_px: trigger_price_decimal,
                        tpsl: HyperliquidExchangeTpSl::Tp,
                    },
                }
            } else {
                anyhow::bail!("Limit-if-touched orders require a trigger price")
            }
        }
        _ => anyhow::bail!("Unsupported order type for Hyperliquid: {order_type:?}"),
    };

    Ok(HyperliquidExchangePlaceOrderRequest {
        asset,
        is_buy,
        price: price_decimal,
        size: size_decimal,
        reduce_only,
        kind,
        cloid,
    })
}

/// Default slippage buffer in basis points for MARKET orders.
pub const DEFAULT_MARKET_SLIPPAGE_BPS: u32 = 50;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass a trigger_price when creating the LimitIfTouchedOrder (OrderFactory::limit_if_touched).
  2. Pre-validate that order.trigger_price().is_some() for LimitIfTouched orders before calling submit_order.
  3. If no trigger is wanted, submit a plain OrderType::Limit order instead.

Example fix

// before
let order = self.order_factory.limit_if_touched(
    instrument_id, OrderSide::Sell, quantity, limit_price, None, TimeInForce::Gtc,
);
// after
let order = self.order_factory.limit_if_touched(
    instrument_id, OrderSide::Sell, quantity, limit_price, Some(trigger_price), TimeInForce::Gtc,
);
Defensive patterns

Strategy: validation

Validate before calling

if matches!(order.order_type(), OrderType::LimitIfTouched) && order.trigger_price().is_none() {
    return Err("LIT order submitted to Hyperliquid without trigger price");
}

Type guard

fn lit_has_trigger(order: &OrderAny) -> bool {
    !matches!(order.order_type(), OrderType::LimitIfTouched) || order.trigger_price().is_some()
}

Prevention

When it happens

Trigger: Submitting or modifying an OrderType::LimitIfTouched order via submit_order/modify_order/order_request where the order was built without a trigger price.

Common situations: Constructing a limit_if_touched order from a factory call omitting the trigger_price argument; orders deserialized or restored from persistence losing their trigger price; porting strategies from venues where LIT trigger is derived implicitly.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/951721ca19ce24d2. Report an issue: GitHub.