{"record":{"id":"dafd8799d9808a8e","repo":"QuantConnect/Lean","slug":"expected-an-open-position-at-end-of-algorithm","errorCode":null,"errorMessage":"Expected an open position at end of algorithm","messagePattern":"Expected an open position at end of algorithm","errorType":"exception","errorClass":"RegressionTestException","httpStatus":null,"severity":"error","filePath":"Algorithm.CSharp/BinanceCryptoFutureBnfcrCollateralRegressionAlgorithm.cs","lineNumber":102,"sourceCode":"\n            var ethBuyingPower = _ethUsdc.BuyingPowerModel.GetBuyingPower(new BuyingPowerParameters(Portfolio, _ethUsdc, OrderDirection.Buy));\n            var adaBuyingPower = _adaUsdt.BuyingPowerModel.GetBuyingPower(new BuyingPowerParameters(Portfolio, _adaUsdt, OrderDirection.Buy));\n\n            // ETHUSDC must see less buying power than ADAUSDT - ADAUSDT maintenance margin\n            // is deducted from ETHUSDC's shared pool, but ADAUSDT skips itself.\n            if (ethBuyingPower.Value >= adaBuyingPower.Value)\n            {\n                throw new RegressionTestException(\n                    $\"ETHUSDC buying power ({ethBuyingPower.Value}) must be less than ADAUSDT ({adaBuyingPower.Value}) \" +\n                    $\"— shared BNFCR pool must deduct ADAUSDT maintenance margin\");\n            }\n        }\n\n        public override void OnEndOfAlgorithm()\n        {\n            if (!Portfolio.Invested)\n            {\n                throw new RegressionTestException(\"Expected an open position at end of algorithm\");\n            }\n        }\n\n        public override void OnOrderEvent(OrderEvent orderEvent)\n        {\n            Debug($\"{Time} {orderEvent}\");\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","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.CSharp/BinanceCryptoFutureBnfcrCollateralRegressionAlgorithm.cs#L84-L120","documentation":"Thrown in OnEndOfAlgorithm when Portfolio.Invested is false, meaning all positions were closed or never opened. The algorithm expects the ADAUSDT futures position (bought in OnData) to remain open at algorithm termination. If the position was liquidated, rejected, or never filled, this assertion catches it.","triggerScenarios":"The Buy order was rejected (links to error 36), the position was automatically liquidated by a margin call, the backtest ended before the order filled, or a settlement/expiry closed the position.","commonSituations":"Margin call liquidation when BNFCR collateral is insufficient, order not filled due to data feed issues, algorithm end date set before the order processes, or an expiry/settlement event closing the crypto future position.","solutions":["Check Portfolio[_adaUsdt.Symbol].Quantity to confirm whether the position was ever opened.","Review OnOrderEvent logs for margin-call or liquidation events.","Verify the backtest date range is long enough for the order to fill (single-day algo: SetStartDate/SetEndDate same day).","Inspect the order ticket status history to see if the fill occurred.","Ensure no Liquidate() call paths execute between the Buy and algorithm end."],"exampleFix":"// before\npublic override void OnEndOfAlgorithm()\n{\n    if (!Portfolio.Invested)\n    {\n        throw new RegressionTestException(\"Expected an open position at end of algorithm\");\n    }\n}\n\n// after — diagnose position state\npublic override void OnEndOfAlgorithm()\n{\n    if (!Portfolio.Invested)\n    {\n        foreach (var kvp in Securities)\n        {\n            Log($\"{kvp.Key}: qty={kvp.Value.Holdings.Quantity}, invested={kvp.Value.Invested}\");\n        }\n        throw new RegressionTestException(\"Expected an open position at end of algorithm\");\n    }\n}","handlingStrategy":"validation","validationCode":"// Validate position state before asserting\npublic override void OnEndOfAlgorithm()\n{\n    if (!Portfolio.Invested)\n    {\n        foreach (var kvp in Securities)\n        {\n            Log($\"{kvp.Key}: qty={kvp.Value.Holdings.Quantity}, invested={kvp.Value.Invested}\");\n        }\n    }\n}","typeGuard":"bool HasOpenPosition() => Portfolio.Invested &&\n    Securities.Values.Any(s => s.Holdings.Quantity != 0);","tryCatchPattern":null,"preventionTips":["Log order ticket status after Buy to confirm the fill occurred.","Check OnOrderEvent for margin-call or liquidation events.","Ensure no Liquidate() call paths execute after the Buy.","Verify the backtest window is long enough for the order to process."],"tags":["quantconnect","binance","crypto-futures","position","portfolio","regression-test"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}