nautechsystems/nautilus_trader · error

Missing `TriggerType` for trailing stop calculation

Error message

Missing `TriggerType` for trailing stop calculation

What it means

trailing_stop_calculate requires the order to expose a TriggerType, but `order.trigger_type()` returned None. A trailing stop (TrailingStopMarket or TrailingStopLimit) must carry a trigger type (e.g. LastPrice, BidAsk) to determine which market price drives the trailing offset calculation.

Source

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

        OrderType::TrailingStopMarket | OrderType::TrailingStopLimit
    ) {
        anyhow::bail!("Invalid `OrderType` {order_type} for trailing stop calculation");
    }

    // 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)
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set trigger_type (e.g. TriggerType.LastPrice or BidAsk) when creating the TrailingStopMarket/TrailingStopLimit order
  2. Check the order factory/config used to build the order and ensure trigger_type is populated
  3. If deserializing, migrate the order payload to include trigger_type
  4. If testing, use a valid trailing stop order fixture with trigger_type set

Example fix

// before
order = order_factory.trailing_stop_market(
    side=OrderSide.SELL, trailing_offset=Decimal("0.01"),
)
// after
order = order_factory.trailing_stop_market(
    side=OrderSide.SELL, trailing_offset=Decimal("0.01"),
    trigger_type=TriggerType.LAST_PRICE,
)
Defensive patterns

Strategy: validation

Validate before calling

if order.trigger_type() is None:
    raise ValueError("Trailing stop order requires trigger_type")

Type guard

fn has_trigger_type(order: &OrderAny) -> bool {
    order.trigger_type().is_some()
}

Try / catch

match trailing_stop_calculate(order_type, trigger_px, &order, bid, ask, last) {
    Ok(prices) => apply(prices),
    Err(e) => { log::error!("trailing calc failed: {e}"); leave_trigger_unchanged() }
}

Prevention

When it happens

Trigger: Calling trailing_stop_calculate (directly or via update_trailing_stop_order) with an OrderAny whose trigger_type() is None — typically a trailing stop order built without specifying trigger_type, or a custom/order-generic order wrapper that omits it.

Common situations: Constructing trailing stop orders from templates/config where trigger_type was omitted; deserializing orders from an older schema without trigger_type; passing a non-trailing order cast generically into the calculator in tests.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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