nautechsystems/nautilus_trader · error

Missing `TrailingOffsetType` for trailing stop calculation

Error message

Missing `TrailingOffsetType` for trailing stop calculation

What it means

`trailing_stop_calculate` requires the order to carry a trailing offset type (`TrailingOffsetType`) to know how to interpret the trailing offset (absolute price, basis points, or ticks). `OrderAny::trailing_offset_type()` returned `None`, meaning the order was built without this field, so the calculator cannot compute the offset and aborts with an anyhow error. It guards against silently computing a trailing price with an undefined offset semantics.

Source

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

    // Seed from the current trigger only (never the activation price): when the trigger has
    // not yet materialized it stays `None` here so the offset candidate below becomes the
    // initial trigger on the first update (matches v1 `TrailingStopCalculator`).
    let mut trigger_price = trigger_px.or(order.trigger_price());

    let mut limit_price = if order_type == OrderType::TrailingStopLimit {
        order.price()
    } else {
        None
    };

    let trigger_type = order
        .trigger_type()
        .ok_or_else(|| anyhow::anyhow!("Missing `TriggerType` for trailing stop calculation"))?;
    let trailing_offset = order.trailing_offset().ok_or_else(|| {
        anyhow::anyhow!("Missing `trailing_offset` for trailing stop calculation")
    })?;
    let trailing_offset_type = order.trailing_offset_type().ok_or_else(|| {
        anyhow::anyhow!("Missing `TrailingOffsetType` for trailing stop calculation")
    })?;
    let mut new_trigger_price: Option<Price>;
    let mut new_limit_price: Option<Price> = None;

    let maybe_move = |current: &mut Option<Price>,
                      candidate: Price,
                      better: fn(Price, Price) -> bool|
     -> Option<Price> {
        match current {
            Some(p) if better(candidate, *p) => {
                *current = Some(candidate);
                Some(candidate)
            }
            None => {
                *current = Some(candidate);
                Some(candidate)
            }
            _ => None,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set `trailing_offset_type` when constructing the trailing stop order (e.g. `TrailingOffsetType::Price`, `BasisPoints`, or `Ticks`) so it matches the unit of `trailing_offset`.
  2. Before calling the calculator, check `order.trailing_offset_type().is_some()` and reject/repair the order otherwise.
  3. If the order came from deserialization or persisted state, migrate/upgrade the stored data to include the offset type.

Example fix

// before
let order = OrderAny::builder()
    .order_type(OrderType::TrailingStopMarket)
    .trailing_offset(Decimal::from(100))
    .build()?;
// after
let order = OrderAny::builder()
    .order_type(OrderType::TrailingStopMarket)
    .trailing_offset(Decimal::from(100))
    .trailing_offset_type(TrailingOffsetType::Price)
    .build()?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_trailing_offset_type(order: &OrderAny) -> Result<(), String> {
    if order.trailing_offset_type().is_none() {
        return Err(format!(
            "order {} of type {} is missing trailing_offset_type",
            order.client_order_id(), order.order_type()
        ));
    }
    Ok(())
}

Type guard

fn has_trailing_offset_type(order: &OrderAny) -> bool {
    order.trailing_offset_type().is_some()
}

Prevention

When it happens

Trigger: Calling `trailing_stop_calculate` (directly or via `update_trailing_stop_order`) with an `OrderAny` whose `trailing_offset_type` is `None` — typically a TrailingStopMarket/TrailingStopLimit order constructed without setting `trailing_offset_type`.

Common situations: Hand-building a trailing stop order and forgetting the `trailing_offset_type` field (e.g. copying a factory that only sets `trailing_offset`); deserializing an order from a venue payload or older persisted state that lacked the field; custom order factories that initialize optional fields to `None`.

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