{"record":{"id":"5d118270adacc065","repo":"QuantConnect/Lean","slug":"orderevent-limitprice-is-not-expected-to-be-0-for","errorCode":null,"errorMessage":"OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder","messagePattern":"OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/OrderTicketDemoAlgorithm.py","lineNumber":399,"sourceCode":"            update_order_fields = UpdateOrderFields()\n            update_order_fields.quantity = quantity\n            update_order_fields.tag = \"Update #{0}\".format(len(ticket.update_requests) + 1)\n            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))","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/OrderTicketDemoAlgorithm.py#L381-L417","documentation":"This is a self-test assertion inside OrderTicketDemoAlgorithm.on_order_event. It verifies that when Lean emits an OrderEvent for a LimitOrder or StopLimitOrder, the OrderEvent.LimitPrice field carries the order's real limit price rather than 0. OrderEvent.LimitPrice is a nullable decimal (decimal?) populated by the transaction/fill pipeline from the originating order. The assertion fires only when the field reads as exactly numeric zero for one of these two order types.","triggerScenarios":"An OrderEvent arrives whose order is a LimitOrder or StopLimitOrder and order_event.limit_price == 0. Concretely: order_event.quantity is non-zero and matches order.quantity (the earlier checks passed), but the limit price was never copied from the order onto the event. This happens if the engine/serializer drops the LimitPrice, if a custom order type or fill model constructs the event without setting LimitPrice, or if the event was deserialized (e.g. via OrderEvent.FromSerialized) and the source lacked the limit price.","commonSituations":"Lean engine contributors run the OrderTicketDemo regression algorithm after changing order serialization, the fill model, or OrderEvent construction and the limit price stops being propagated. A user who copies this assertion pattern into their own algorithm hits it when their brokerage/custom fill model emits an event without setting LimitPrice. It can also surface after a Lean version upgrade if the OrderEvent contract for limit prices changed.","solutions":["If you are running Lean's own regression test: treat this as an engine regression — find where the OrderEvent for LimitOrder/StopLimitOrder is built and ensure LimitPrice is copied from order.LimitPrice (see the OrderEvent(Order,...) constructor path and fill models).","If you copied the assertion into your own algorithm: replace the equality-with-zero check with a nullable-aware guard that compares against the order's actual limit price, since LimitPrice is decimal? and can be None rather than 0.","If the event came from a custom/brokerage fill model, set order_event.LimitPrice = order.LimitPrice before emitting the event.","If the event is deserialized from a stored/live packet, confirm the source sets LimitPrice; otherwise re-attach it from the live order in OnOrderEvent."],"exampleFix":"# before\nif (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# after (nullable-aware, compares to the originating order's limit price)\nif type(order) in (LimitOrder, StopLimitOrder):\n    if order_event.limit_price in (None, 0) or order_event.limit_price != order.limit_price:\n        raise AssertionError(\n            f\"OrderEvent LimitPrice mismatch for {type(order).__name__}: \"\n            f\"event={order_event.limit_price}, order={order.limit_price}\")","handlingStrategy":"validation","validationCode":"# Before relying on order_event.limit_price for a limit-type order, validate it is set and matches the order\norder = self.transactions.get_order_by_id(order_event.order_id)\nif type(order) in (LimitOrder, StopLimitOrder):\n    if order_event.limit_price in (None, 0):\n        self.debug(f\"Skipping event: limit_price unset for {type(order).__name__}\")\n        return\n    # safe to use order_event.limit_price","typeGuard":"def has_valid_limit_price(order, order_event):\n    \"\"\"True only for limit-type orders whose event limit price is present and non-zero.\"\"\"\n    if type(order) not in (LimitOrder, StopLimitOrder):\n        return True\n    lp = order_event.limit_price\n    return lp is not None and lp != 0","tryCatchPattern":null,"preventionTips":["Treat OrderEvent.LimitPrice as nullable (decimal?); compare with is None and against order.limit_price, never assume it is 0.","Do not copy regression-algorithm assertions verbatim into production algorithms; relax them to warnings.","If you build OrderEvents in a custom fill/brokerage model, always copy LimitPrice from the originating order."],"tags":["quantconnect","lean","orders","order-event","limit-order","regression-test","python"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}