{"record":{"id":"6c777468445207f7","repo":"QuantConnect/Lean","slug":"expected-no-options-holdings-after-closing-positio","errorCode":null,"errorMessage":"Expected no options holdings after closing position","messagePattern":"Expected no options holdings after closing position","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/FutureOptionShortPutOTMExpiryRegressionAlgorithm.py","lineNumber":97,"sourceCode":"\n        security = self.securities[order_event.symbol]\n        if security.symbol == self.es19m20:\n            raise AssertionError(f\"Expected no order events for underlying Symbol {security.symbol}\")\n\n        if security.symbol == self.expected_contract:\n            self.assert_future_option_contract_order(order_event, security)\n\n        else:\n            raise AssertionError(f\"Received order event for unknown Symbol: {order_event.symbol}\")\n\n        self.log(f\"{order_event}\")\n\n    def assert_future_option_contract_order(self, order_event: OrderEvent, option_contract: Security):\n        if order_event.direction == OrderDirection.SELL and option_contract.holdings.quantity != -1:\n            raise AssertionError(f\"No holdings were created for option contract {option_contract.symbol}\")\n\n        if order_event.direction == OrderDirection.BUY and option_contract.holdings.quantity != 0:\n            raise AssertionError(\"Expected no options holdings after closing position\")\n\n        if order_event.is_assignment:\n            raise AssertionError(f\"Assignment was not expected for {order_event.symbol}\")\n\n    def on_end_of_algorithm(self):\n        if self.portfolio.invested:\n            raise AssertionError(f\"Expected no holdings at end of algorithm, but are invested in: {', '.join([str(i.id) for i in self.portfolio.keys()])}\")\n","sourceCodeStart":79,"sourceCodeEnd":105,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/FutureOptionShortPutOTMExpiryRegressionAlgorithm.py#L79-L105","documentation":"In assert_future_option_contract_order, after a BUY fill (closing the short put) the option holdings must be flat (quantity == 0). A non-zero quantity means the close didn't fully flatten the position, leaving residual option exposure.","triggerScenarios":"An OrderEvent with direction == OrderDirection.BUY fills but option_contract.holdings.quantity != 0 — e.g., the buy only partially closed a -2 position, or an extra contract was opened.","commonSituations":"Closing order quantity mismatched the open position, partial fill, or a second contract was opened instead of closing the existing one.","solutions":["Ensure the closing buy order quantity equals the open short quantity (1 contract here).","Look for intermediate fills that changed the position size before the close.","Verify no auto-exercise/assignment altered holdings between open and close."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Before the close, verify the open short size and submit a matching close\nopen_qty = abs(option_contract.holdings.quantity)\nif open_qty > 0:\n    self.market_order(option_contract.symbol, open_qty)  # close","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always close with a quantity equal to the open position magnitude.","After closing, assert holdings are flat before the next step rather than only at end-of-algorithm."],"tags":["regression-test","future-options","holdings","fill"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}