{"record":{"id":"bb36b442727611d5","repo":"QuantConnect/Lean","slug":"expected-self-expected-orders-count-orders-to","errorCode":null,"errorMessage":"Expected {self.expected_orders_count()} orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation. Actual {orders_count}","messagePattern":"Expected (.+?) orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation\\. Actual (.+?)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/OptionStrategyFactoryMethodsBaseAlgorithm.py","lineNumber":62,"sourceCode":"            if not isinstance(buying_power_model, OptionStrategyPositionGroupBuyingPowerModel):\n                raise AssertionError(\"Expected position group buying power model type: OptionStrategyPositionGroupBuyingPowerModel. \"\n                                f\"Actual: {type(position_group.buying_power_model).__name__}\")\n\n            self.assert_strategy_position_group(position_group, self._option_symbol)\n\n            # Now we should be able to close the position\n            self.liquidate_strategy()\n\n            # We can quit now, no more testing required\n            self.quit()\n\n    def on_end_of_algorithm(self):\n        if self.portfolio.invested:\n            raise AssertionError(\"Expected no holdings at end of algorithm\")\n\n        orders_count = len(list(self.transactions.get_orders(lambda order: order.status == OrderStatus.FILLED)))\n        if orders_count != self.expected_orders_count():\n            raise AssertionError(f\"Expected {self.expected_orders_count()} orders to have been submitted and filled, \"\n                            f\"half for buying the strategy and the other half for the liquidation. Actual {orders_count}\")\n\n    def expected_orders_count(self) -> int:\n        raise NotImplementedError(\"ExpectedOrdersCount method is not implemented\")\n\n    def trade_strategy(self, chain: OptionChain, option_symbol: Symbol) -> None:\n        raise NotImplementedError(\"TradeStrategy method is not implemented\")\n\n    def assert_strategy_position_group(self, position_group: IPositionGroup, option_symbol: Symbol) -> None:\n        raise NotImplementedError(\"AssertStrategyPositionGroup method is not implemented\")\n\n    def liquidate_strategy(self) -> None:\n        raise NotImplementedError(\"LiquidateStrategy method is not implemented\")\n","sourceCodeStart":44,"sourceCodeEnd":76,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/OptionStrategyFactoryMethodsBaseAlgorithm.py#L44-L76","documentation":"This assertion compares the number of FILLED orders against expected_orders_count(), which a subclass defines as twice the number of strategy legs (one set to open, one set to liquidate). A mismatch means some legs were not filled, were filled twice, or the subclass's expected count constant is wrong relative to the strategy it trades. It runs in on_end_of_algorithm after the no-holdings check.","triggerScenarios":"len(list(self.transactions.get_orders(lambda o: o.status == OrderStatus.FILLED))) != self.expected_orders_count(). Triggered by a leg order not reaching FILLED (rejected/canceled/partial), an extra order being submitted, or a subclass reporting the wrong expected count for its strategy's leg count.","commonSituations":"Subclassing for a strategy with a different number of legs but forgetting to override expected_orders_count(); a liquidation order that split into partial fills counted differently; a combo order that the engine expanded into a different number of child orders than expected.","solutions":["Override expected_orders_count() in the subclass to return 2 * (number of legs in the traded strategy).","Inspect self.transactions.get_orders(...) statuses to find non-FILLED (canceled/rejected/invalid) orders causing the shortfall.","Confirm the strategy factory method produces the expected number of leg orders on both open and close.","If a partial fill occurred, account for it in the expected count or ensure full fills before counting."],"exampleFix":"# before: subclass uses base NotImplementedError or wrong count\n# after: override for a 2-leg strategy\ndef expected_orders_count(self) -> int:\n    return 4  # 2 legs open + 2 legs liquidate","handlingStrategy":"validation","validationCode":"# Count filled orders and compare to expected only after all fills settle\nfilled = list(self.transactions.get_orders(lambda o: o.status == OrderStatus.FILLED))\nexpected = self.expected_orders_count()\nif len(filled) != expected:\n    non_filled = [o for o in self.transactions.get_orders() if o.status != OrderStatus.FILLED]\n    raise AssertionError(f'filled={len(filled)} expected={expected} non_filled={non_filled}')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Override expected_orders_count() as 2 * leg_count in every subclass.","Inspect non-FILLED orders before asserting to find rejections.","Confirm the strategy factory produces the expected number of leg orders.","Account for partial fills in the expected count."],"tags":["options","orders","regression-test","quantconnect","option-strategy","not-implemented"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}