QuantConnect/Lean · error · RegressionTestException

Expected an open position at end of algorithm

Error message

Expected an open position at end of algorithm

What it means

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.

Source

Thrown at Algorithm.CSharp/BinanceCryptoFutureBnfcrCollateralRegressionAlgorithm.cs:102

            var ethBuyingPower = _ethUsdc.BuyingPowerModel.GetBuyingPower(new BuyingPowerParameters(Portfolio, _ethUsdc, OrderDirection.Buy));
            var adaBuyingPower = _adaUsdt.BuyingPowerModel.GetBuyingPower(new BuyingPowerParameters(Portfolio, _adaUsdt, OrderDirection.Buy));

            // ETHUSDC must see less buying power than ADAUSDT - ADAUSDT maintenance margin
            // is deducted from ETHUSDC's shared pool, but ADAUSDT skips itself.
            if (ethBuyingPower.Value >= adaBuyingPower.Value)
            {
                throw new RegressionTestException(
                    $"ETHUSDC buying power ({ethBuyingPower.Value}) must be less than ADAUSDT ({adaBuyingPower.Value}) " +
                    $"— shared BNFCR pool must deduct ADAUSDT maintenance margin");
            }
        }

        public override void OnEndOfAlgorithm()
        {
            if (!Portfolio.Invested)
            {
                throw new RegressionTestException("Expected an open position at end of algorithm");
            }
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            Debug($"{Time} {orderEvent}");
        }

        /// <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 };

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Check Portfolio[_adaUsdt.Symbol].Quantity to confirm whether the position was ever opened.
  2. Review OnOrderEvent logs for margin-call or liquidation events.
  3. Verify the backtest date range is long enough for the order to fill (single-day algo: SetStartDate/SetEndDate same day).
  4. Inspect the order ticket status history to see if the fill occurred.
  5. Ensure no Liquidate() call paths execute between the Buy and algorithm end.

Example fix

// before
public override void OnEndOfAlgorithm()
{
    if (!Portfolio.Invested)
    {
        throw new RegressionTestException("Expected an open position at end of algorithm");
    }
}

// after — diagnose position state
public override void OnEndOfAlgorithm()
{
    if (!Portfolio.Invested)
    {
        foreach (var kvp in Securities)
        {
            Log($"{kvp.Key}: qty={kvp.Value.Holdings.Quantity}, invested={kvp.Value.Invested}");
        }
        throw new RegressionTestException("Expected an open position at end of algorithm");
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate position state before asserting
public override void OnEndOfAlgorithm()
{
    if (!Portfolio.Invested)
    {
        foreach (var kvp in Securities)
        {
            Log($"{kvp.Key}: qty={kvp.Value.Holdings.Quantity}, invested={kvp.Value.Invested}");
        }
    }
}

Type guard

bool HasOpenPosition() => Portfolio.Invested &&
    Securities.Values.Any(s => s.Holdings.Quantity != 0);

Prevention

When it happens

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

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

Related errors


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