nautechsystems/nautilus_trader · error

Missing `limit_offset` for trailing stop limit calculation

Error message

Missing `limit_offset` for trailing stop limit calculation

What it means

For a `TrailingStopLimit` order with `TriggerType::LastPrice` or `MarkPrice`, the calculator needs a `limit_offset` to compute the new limit price from the last price. `OrderAny::limit_offset()` returned `None`, so the calculation aborts — a trailing-stop-limit order without a limit offset is incomplete and cannot be repriced correctly.

Source

Thrown at crates/execution/src/trailing.rs:128

                anyhow::bail!("`TrailingOffsetType` {trailing_offset_type} not currently supported")
            }
        };
        let value = match order_side {
            OrderSide::Buy => basis + offset,
            OrderSide::Sell => basis - offset,
        };
        Price::from_decimal_dp(value, price_increment.precision).map_err(Into::into)
    };

    match trigger_type {
        TriggerType::LastPrice | TriggerType::MarkPrice => {
            let last = last.ok_or(OrderError::InvalidStateTransition)?;
            let cand_trigger = compute(trailing_offset, last)?;
            new_trigger_price = maybe_move(&mut trigger_price, cand_trigger, better_trigger);

            if order_type == OrderType::TrailingStopLimit {
                let limit_offset = order.limit_offset().ok_or_else(|| {
                    anyhow::anyhow!("Missing `limit_offset` for trailing stop limit calculation")
                })?;
                let cand_limit = compute(limit_offset, last)?;
                new_limit_price = maybe_move(&mut limit_price, cand_limit, better_limit);
            }
        }
        TriggerType::Default | TriggerType::BidAsk | TriggerType::LastOrBidAsk => {
            let (bid, ask) = (
                bid.ok_or_else(|| anyhow::anyhow!("Bid required"))?,
                ask.ok_or_else(|| anyhow::anyhow!("Ask required"))?,
            );
            let basis = match order_side {
                OrderSide::Buy => ask,
                OrderSide::Sell => bid,
            };
            let cand_trigger = compute(trailing_offset, basis)?;
            new_trigger_price = maybe_move(&mut trigger_price, cand_trigger, better_trigger);

            if order_type == OrderType::TrailingStopLimit {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set `limit_offset` on the TrailingStopLimit order at construction time (same unit semantics governed by `trailing_offset_type`).
  2. If the order should be a trailing stop market, change `order_type` to `TrailingStopMarket` so the limit-offset branch is not taken.
  3. Guard before calling: `if order.order_type() == OrderType::TrailingStopLimit && order.limit_offset().is_none() { ... }` and repair or reject the order.

Example fix

// before
let order = OrderAny::builder()
    .order_type(OrderType::TrailingStopLimit)
    .trailing_offset(Decimal::from(50))
    .trailing_offset_type(TrailingOffsetType::Ticks)
    .build()?;
// after
let order = OrderAny::builder()
    .order_type(OrderType::TrailingStopLimit)
    .trailing_offset(Decimal::from(50))
    .limit_offset(Decimal::from(10))
    .trailing_offset_type(TrailingOffsetType::Ticks)
    .build()?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_limit_offset(order: &OrderAny) -> Result<(), String> {
    if order.order_type() == OrderType::TrailingStopLimit && order.limit_offset().is_none() {
        return Err(format!(
            "TrailingStopLimit order {} is missing limit_offset",
            order.client_order_id()
        ));
    }
    Ok(())
}

Type guard

fn is_complete_trailing_stop_limit(order: &OrderAny) -> bool {
    order.order_type() != OrderType::TrailingStopLimit || order.limit_offset().is_some()
}

Prevention

When it happens

Trigger: Calling `trailing_stop_calculate` (or `update_trailing_stop_order`) with `order_type == TrailingStopLimit`, `trigger_type` of `LastPrice`/`MarkPrice`, and a `last` price present, while the order has no `limit_offset` set.

Common situations: Building a TrailingStopLimit order and setting only `trailing_offset` but not `limit_offset`; a venue adapter or strategy template that populates trailing-stop-market fields but not limit fields; deserialized orders from schema versions without `limit_offset`.

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