QuantConnect/Lean · error · AssertionError

OrderEvent StopPrice is Not expected to be 0 for StopMarketO

Error message

OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder

What it means

Self-test assertion in OrderTicketDemoAlgorithm.on_order_event verifying that an OrderEvent for a StopMarketOrder carries a non-zero StopPrice. OrderEvent.StopPrice is a nullable decimal (decimal?) that the engine is expected to populate from the stop order's trigger price. The check `order_event.stop_price == 0` triggers when the field reads as exactly numeric zero for a stop-market order.

Source

Thrown at Algorithm.Python/OrderTicketDemoAlgorithm.py:402

            ticket.update(update_order_fields)


    def on_order_event(self, order_event):
        order = self.transactions.get_order_by_id(order_event.order_id)
        self.log("{0}: {1}: {2}".format(self.time, order.type, order_event))

        if order_event.quantity == 0:
            raise AssertionError("OrderEvent quantity is Not expected to be 0, it should hold the current order Quantity")

        if order_event.quantity != order.quantity:
            raise AssertionError("OrderEvent quantity should hold the current order Quantity")

        if (type(order) is LimitOrder and order_event.limit_price == 0 or
            type(order) is StopLimitOrder and order_event.limit_price == 0):
            raise AssertionError("OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder")

        if type(order) is StopMarketOrder and order_event.stop_price == 0:
            raise AssertionError("OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder")

        # We can access the order ticket from the order event
        if order_event.ticket is None:
            raise AssertionError("OrderEvent Ticket was not set")
        if order_event.order_id != order_event.ticket.order_id:
            raise AssertionError("OrderEvent.ORDER_ID and order_event.ticket.order_id do not match")

    def check_pair_orders_for_fills(self, long_order, short_order):
        if long_order.status == OrderStatus.FILLED:
            self.log("{0}: Cancelling short order, long order is filled.".format(short_order.order_type))
            short_order.cancel("Long filled.")
            return True

        if short_order.status == OrderStatus.FILLED:
            self.log("{0}: Cancelling long order, short order is filled.".format(long_order.order_type))
            long_order.cancel("Short filled")
            return True

View on GitHub (pinned to d2c3659f87)

Solutions

  1. As an engine regression: locate where StopMarketOrder events are constructed and ensure order_event.StopPrice is set from order.StopPrice.
  2. In your own algorithm: replace the `== 0` check with a nullable-aware comparison against order.stop_price.
  3. For custom fill/brokerage models: explicitly set order_event.StopPrice = order.StopPrice before the event is dispatched.
  4. For deserialized events: confirm the source packet includes StopPrice; otherwise re-derive it from the live order.

Example fix

# before
if type(order) is StopMarketOrder and order_event.stop_price == 0:
    raise AssertionError("OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder")

# after
if type(order) is StopMarketOrder:
    if order_event.stop_price in (None, 0) or order_event.stop_price != order.stop_price:
        raise AssertionError(
            f"OrderEvent StopPrice mismatch for StopMarketOrder: "
            f"event={order_event.stop_price}, order={order.stop_price}")
Defensive patterns

Strategy: validation

Validate before calling

order = self.transactions.get_order_by_id(order_event.order_id)
if type(order) is StopMarketOrder:
    if order_event.stop_price in (None, 0):
        self.debug(f"Skipping event: stop_price unset for StopMarketOrder {order_event.order_id}")
        return
    # safe to use order_event.stop_price

Type guard

def has_valid_stop_price(order, order_event):
    """True only for stop orders whose event stop price is present and non-zero."""
    if type(order) is not StopMarketOrder:
        return True
    sp = order_event.stop_price
    return sp is not None and sp != 0

Prevention

When it happens

Trigger: An OrderEvent for a StopMarketOrder arrives with order_event.stop_price == 0. This means the earlier quantity checks passed, but the stop price was not propagated from the order to the event. It occurs when a fill model, transaction handler, or deserialization path (e.g. OrderEvent.FromSerialized) builds the event without copying order.StopPrice into StopPrice.

Common situations: Lean contributors hit this in the regression suite after edits to stop-order handling, the fill pipeline, or OrderEvent serialization. Users hit it when a custom stop-order type or brokerage integration emits events without setting StopPrice, or after upgrading Lean if the stop-price propagation contract changed.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/2eb51d537fa15a63. Report an issue: GitHub.