{"record":{"id":"46f0d5db262f85c7","repo":"QuantConnect/Lean","slug":"we-shouldn-t-be-invested-anymore","errorCode":null,"errorMessage":"We shouldn't be invested anymore","messagePattern":"We shouldn't be invested anymore","errorType":"exception","errorClass":"RegressionTestException","httpStatus":null,"severity":"error","filePath":"Algorithm.CSharp/DelistingFutureOptionRegressionAlgorithm.cs","lineNumber":91,"sourceCode":"            foreach (var chain in slice.OptionChains.Values)\n            {\n                foreach (var contractsValue in chain.Contracts.Values)\n                {\n                    MarketOrder(contractsValue.Symbol, 1);\n                    _traded = true;\n                }\n            }\n        }\n\n        public override void OnEndOfAlgorithm()\n        {\n            if (!_traded)\n            {\n                throw new RegressionTestException(\"We expected some FOP trading to happen\");\n            }\n            if (Portfolio.Invested)\n            {\n                throw new RegressionTestException(\"We shouldn't be invested anymore\");\n            }\n        }\n\n        /// <summary>\n        /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.\n        /// </summary>\n        public bool CanRunLocally { get; } = true;\n\n        /// <summary>\n        /// This is used by the regression test system to indicate which languages this algorithm is written in.\n        /// </summary>\n        public List<Language> Languages { get; } = new() { Language.CSharp };\n\n        /// <summary>\n        /// Data Points count of all timeslices of algorithm\n        /// </summary>\n        public virtual long DataPoints => 462641;\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.CSharp/DelistingFutureOptionRegressionAlgorithm.cs#L73-L109","documentation":"OnEndOfAlgorithm asserts Portfolio.Invested is false. The algorithm enters future-option positions each month but expects them all to be closed by expiry/delisting before the algorithm ends. A remaining investment means a position was not liquidated at contract expiry.","triggerScenarios":"A FOP or future position survives past its expiry because Lean's automatic delisting liquidation did not fire, or because the contract was not yet delisted by the algorithm end date (2020-03-23).","commonSituations":"The end date falls before the last held contract's expiry, a delisting liquidation bug, or the algorithm re-enters a position late in the final month that does not expire before end.","solutions":["Check which symbol is still invested at OnEndOfAlgorithm via Portfolio.Holdings or Securities.Values.Where(s => s.Invested).","Verify the held contract's expiry date is on or before SetEndDate (2020-03-23).","Ensure Lean delisting liquidation processes future options correctly (this regression guards issue #5160).","If the end date genuinely leaves an open position, either liquidate manually before end or adjust the date."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"public override void OnEndOfAlgorithm()\n{\n    if (Portfolio.Invested)\n    {\n        var held = Securities.Values.Where(s => s.Invested).Select(s => s.Symbol);\n        throw new InvalidOperationException($\"Still invested in: {string.Join(\",\", held)}\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure all entered positions expire before SetEndDate or liquidate manually.","Log held symbols and their expiry dates near the end of the algorithm.","Verify delisting liquidation fires for future options."],"tags":["quantconnect","future-options","portfolio","delisting","regression-test"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}