{"record":{"id":"2eb51d537fa15a63","repo":"QuantConnect/Lean","slug":"orderevent-stopprice-is-not-expected-to-be-0-for-s","errorCode":null,"errorMessage":"OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder","messagePattern":"OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/OrderTicketDemoAlgorithm.py","lineNumber":402,"sourceCode":"            ticket.update(update_order_fields)\n\n\n    def on_order_event(self, order_event):\n        order = self.transactions.get_order_by_id(order_event.order_id)\n        self.log(\"{0}: {1}: {2}\".format(self.time, order.type, order_event))\n\n        if order_event.quantity == 0:\n            raise AssertionError(\"OrderEvent quantity is Not expected to be 0, it should hold the current order Quantity\")\n\n        if order_event.quantity != order.quantity:\n            raise AssertionError(\"OrderEvent quantity should hold the current order Quantity\")\n\n        if (type(order) is LimitOrder and order_event.limit_price == 0 or\n            type(order) is StopLimitOrder and order_event.limit_price == 0):\n            raise AssertionError(\"OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder\")\n\n        if type(order) is StopMarketOrder and order_event.stop_price == 0:\n            raise AssertionError(\"OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder\")\n\n        # We can access the order ticket from the order event\n        if order_event.ticket is None:\n            raise AssertionError(\"OrderEvent Ticket was not set\")\n        if order_event.order_id != order_event.ticket.order_id:\n            raise AssertionError(\"OrderEvent.ORDER_ID and order_event.ticket.order_id do not match\")\n\n    def check_pair_orders_for_fills(self, long_order, short_order):\n        if long_order.status == OrderStatus.FILLED:\n            self.log(\"{0}: Cancelling short order, long order is filled.\".format(short_order.order_type))\n            short_order.cancel(\"Long filled.\")\n            return True\n\n        if short_order.status == OrderStatus.FILLED:\n            self.log(\"{0}: Cancelling long order, short order is filled.\".format(long_order.order_type))\n            long_order.cancel(\"Short filled\")\n            return True\n","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/OrderTicketDemoAlgorithm.py#L384-L420","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["As an engine regression: locate where StopMarketOrder events are constructed and ensure order_event.StopPrice is set from order.StopPrice.","In your own algorithm: replace the `== 0` check with a nullable-aware comparison against order.stop_price.","For custom fill/brokerage models: explicitly set order_event.StopPrice = order.StopPrice before the event is dispatched.","For deserialized events: confirm the source packet includes StopPrice; otherwise re-derive it from the live order."],"exampleFix":"# before\nif type(order) is StopMarketOrder and order_event.stop_price == 0:\n    raise AssertionError(\"OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder\")\n\n# after\nif type(order) is StopMarketOrder:\n    if order_event.stop_price in (None, 0) or order_event.stop_price != order.stop_price:\n        raise AssertionError(\n            f\"OrderEvent StopPrice mismatch for StopMarketOrder: \"\n            f\"event={order_event.stop_price}, order={order.stop_price}\")","handlingStrategy":"validation","validationCode":"order = self.transactions.get_order_by_id(order_event.order_id)\nif type(order) is StopMarketOrder:\n    if order_event.stop_price in (None, 0):\n        self.debug(f\"Skipping event: stop_price unset for StopMarketOrder {order_event.order_id}\")\n        return\n    # safe to use order_event.stop_price","typeGuard":"def has_valid_stop_price(order, order_event):\n    \"\"\"True only for stop orders whose event stop price is present and non-zero.\"\"\"\n    if type(order) is not StopMarketOrder:\n        return True\n    sp = order_event.stop_price\n    return sp is not None and sp != 0","tryCatchPattern":null,"preventionTips":["Treat OrderEvent.StopPrice as nullable; check is None, not just == 0.","When writing a custom stop-order fill model, set order_event.StopPrice from order.StopPrice.","Prefer comparing the event price to the originating order's price over asserting a specific value."],"tags":["quantconnect","lean","orders","order-event","stop-order","regression-test","python"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}