QuantConnect/Lean · error · RegressionTestException

Index is not tradable.

Error message

Index is not tradable.

What it means

Thrown in OnEndOfAlgorithm when Portfolio[Spx].TotalSaleVolume is greater than zero, meaning the Lean engine filled at least one order directly on the SPX index symbol. Index securities are non-tradable by design — they serve as price references and option underlyings only. A fill on the index itself indicates the engine incorrectly treated the index as a tradable security.

Source

Thrown at Algorithm.CSharp/BasicTemplateIndexAlgorithm.cs:112

        }

        /// <summary>
        /// Asserts indicators are ready
        /// </summary>
        /// <exception cref="RegressionTestException"></exception>
        protected void AssertIndicators()
        {
            if (!_emaSlow.IsReady || !_emaFast.IsReady)
            {
                throw new RegressionTestException("Indicators are not ready!");
            }
        }

        public override void OnEndOfAlgorithm()
        {
            if (Portfolio[Spx].TotalSaleVolume > 0)
            {
                throw new RegressionTestException("Index is not tradable.");
            }
            AssertIndicators();
        }

        /// <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 virtual bool CanRunLocally { get; } = true;

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

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

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Ensure all order calls use SpxOption (or another tradable derivative), never Spx directly.
  2. Verify Securities[Spx].IsTradable is false after Initialize — add a debug log to confirm.
  3. Check IndexSecurity constructor and SecurityService for changes that may have reset IsTradable to true.
  4. Inspect the algorithm's OnData logic to confirm no Liquidate(Spx) or MarketOrder(Spx) call paths exist.

Example fix

// before — accidentally trading the index
MarketOrder(Spx, 1);

// after — trade the option on the index
MarketOrder(SpxOption, 1);
Defensive patterns

Strategy: validation

Validate before calling

// Before running, verify index is non-tradable
if (Securities[Spx].IsTradable)
{
    Log($"WARNING: {Spx} is marked tradable — index should not be tradable");
}

Type guard

bool IsIndexNonTradable(Symbol sym) =>
    Securities[sym].Type == SecurityType.Index && !Securities[sym].IsTradable;

Try / catch

try
{
    if (Portfolio[Spx].TotalSaleVolume > 0)
        throw new RegressionTestException("Index is not tradable.");
}
catch (RegressionTestException ex)
{
    Log($"Index fill detected: volume={Portfolio[Spx].TotalSaleVolume}");
    throw;
}

Prevention

When it happens

Trigger: Code calls MarketOrder(Spx, qty) or SetHoldings(Spx, target) on the raw index symbol, the engine's security initialization fails to set IsTradable=false for index types, or a brokerage model change inadvertently allows index order fills.

Common situations: Accidentally passing the index Symbol instead of an option Symbol to an order method, a regression introduced in SecurityService or BrokerageModel that changes the default tradability of Index securities, or modifying the algorithm to trade the index directly without using SetIsTradable(true) first.

Related errors


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