QuantConnect/Lean · error · RegressionTestException

We shouldn't be invested anymore

Error message

We shouldn't be invested anymore

What it means

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.

Source

Thrown at Algorithm.CSharp/DelistingFutureOptionRegressionAlgorithm.cs:91

            foreach (var chain in slice.OptionChains.Values)
            {
                foreach (var contractsValue in chain.Contracts.Values)
                {
                    MarketOrder(contractsValue.Symbol, 1);
                    _traded = true;
                }
            }
        }

        public override void OnEndOfAlgorithm()
        {
            if (!_traded)
            {
                throw new RegressionTestException("We expected some FOP trading to happen");
            }
            if (Portfolio.Invested)
            {
                throw new RegressionTestException("We shouldn't be invested anymore");
            }
        }

        /// <summary>
        /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
        /// </summary>
        public bool CanRunLocally { get; } = true;

        /// <summary>
        /// This is used by the regression test system to indicate which languages this algorithm is written in.
        /// </summary>
        public List<Language> Languages { get; } = new() { Language.CSharp };

        /// <summary>
        /// Data Points count of all timeslices of algorithm
        /// </summary>
        public virtual long DataPoints => 462641;

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Check which symbol is still invested at OnEndOfAlgorithm via Portfolio.Holdings or Securities.Values.Where(s => s.Invested).
  2. Verify the held contract's expiry date is on or before SetEndDate (2020-03-23).
  3. Ensure Lean delisting liquidation processes future options correctly (this regression guards issue #5160).
  4. If the end date genuinely leaves an open position, either liquidate manually before end or adjust the date.
Defensive patterns

Strategy: validation

Validate before calling

public override void OnEndOfAlgorithm()
{
    if (Portfolio.Invested)
    {
        var held = Securities.Values.Where(s => s.Invested).Select(s => s.Symbol);
        throw new InvalidOperationException($"Still invested in: {string.Join(",", held)}");
    }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/46f0d5db262f85c7. Report an issue: GitHub.