QuantConnect/Lean · error · RegressionTestException
Trade volume should be greater than zero by the end of this
Error message
Trade volume should be greater than zero by the end of this algorithm
What it means
Thrown in OnEndOfAlgorithm when Portfolio.TotalSaleVolume equals zero, meaning no option orders were filled during the entire algorithm run. This assertion verifies that the EMA-cross trading logic actually generated and filled option orders on SPX contracts.
Source
Thrown at Algorithm.CSharp/BasicTemplateIndexOptionsAlgorithm.cs:110
}
else if (_emaFast < _emaSlow && contract.Right == OptionRight.Put)
{
Liquidate(InvertOption(contract.Symbol));
MarketOrder(contract.Symbol, 1);
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (Portfolio[_spx].TotalSaleVolume > 0)
{
throw new RegressionTestException("Index is not tradable.");
}
if (Portfolio.TotalSaleVolume == 0)
{
throw new RegressionTestException("Trade volume should be greater than zero by the end of this algorithm");
}
AssertIndicators();
}
public Symbol InvertOption(Symbol symbol)
{
return QuantConnect.Symbol.CreateOption(
symbol.Underlying,
symbol.ID.Market,
symbol.ID.OptionStyle,
symbol.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call,
symbol.ID.StrikePrice,
symbol.ID.Date);
}
/// <summary>
/// Asserts indicators are ready
/// </summary>View on GitHub (pinned to d2c3659f87)
Solutions
- Verify SPX option data exists for the full date range (2021-01-04 to 2021-02-01).
- Check that slice.OptionChains is populated in OnData — log chain count per slice.
- Ensure EMA crossover occurs: log _emaFast and _emaSlow values to confirm the condition triggers.
- Relax or verify the CallsOnly filter does not exclude all available contracts.
- Inspect order tickets for rejection messages via ticket.Status and ticket.CancelMessage.
Example fix
// before — no log visibility into why no trades
if (Portfolio.TotalSaleVolume == 0)
{
throw new RegressionTestException("Trade volume should be greater than zero");
}
// after — diagnose before asserting
if (Portfolio.TotalSaleVolume == 0)
{
Log($"EMA Fast Ready: {_emaFast.IsReady}, Slow Ready: {_emaSlow.IsReady}");
Log($"Cross current: fast={_emaFast} slow={_emaSlow}");
throw new RegressionTestException("Trade volume should be greater than zero");
} Defensive patterns
Strategy: validation
Validate before calling
// Before asserting volume, log diagnostic state
if (Portfolio.TotalSaleVolume == 0)
{
Log($"EMA fast ready={_emaFast.IsReady}, slow ready={_emaSlow.IsReady}");
Log($"Cross state: fast={_emaFast}, slow={_emaSlow}, fast>slow={_emaFast > _emaSlow}");
Log($"Option chains received: check OnData logs");
} Prevention
- Log option chain availability in OnData to confirm data flows.
- Verify the option filter (CallsOnly) returns contracts for the date range.
- Ensure EMA crossover condition triggers within the backtest window.
- Check order tickets for rejections via OnOrderEvent logging.
When it happens
Trigger: The EMA fast/slow cross condition never triggers because indicators are not ready, the option chain filter (CallsOnly) returns no contracts, slice.OptionChains is always empty, or MarketOrder calls are rejected/invalid before filling.
Common situations: Option data files missing for the date range, option filter too restrictive, EMA indicators never reaching the crossover state within the backtest window, or a brokerage model change rejecting option orders.
Related errors
- Index is not tradable.
- Indicators are not ready!
- Expiry event was not at the correct time, {orderEvent.UtcTim
- Algorithm did not process the option expiration like expecte
- Unexpected order event symbol!
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/d9727421796d5cfc.
Report an issue: GitHub.