QuantConnect/Lean · error · ValueError

optionChainSymbolSelector must return option, index options,

Error message

optionChainSymbolSelector must return option, index options, or futures options symbols.

What it means

OptionUniverseSelectionModel.create_universes() iterates the user-supplied option_chain_symbol_selector and builds an option chain per underlying. Every returned symbol must be an option type — Extensions.is_option() accepts equity options, index options, and futures options; anything else (equity, future, forex) raises ValueError.

Source

Thrown at Algorithm.Framework/Selection/OptionUniverseSelectionModel.py:49

        self.option_chain_symbol_selector = optionChainSymbolSelector
        self.universe_settings = universeSettings

    def get_next_refresh_time_utc(self):
        '''Gets the next time the framework should invoke the `CreateUniverses` method to refresh the set of universes.'''
        return self.next_refresh_time_utc

    def create_universes(self, algorithm: QCAlgorithm) -> list[Universe]:
        '''Creates a new fundamental universe using this class's selection functions
        Args:
            algorithm: The algorithm instance to create universes for
        Returns:
            The universe defined by this model'''
        self.next_refresh_time_utc = (algorithm.utc_time + self.refresh_interval).date()

        uniqueUnderlyingSymbols = set()
        for option_symbol in self.option_chain_symbol_selector(algorithm.utc_time):
            if not Extensions.is_option(option_symbol.security_type):
                raise ValueError("optionChainSymbolSelector must return option, index options, or futures options symbols.")

            # prevent creating duplicate option chains -- one per underlying
            if option_symbol.underlying not in uniqueUnderlyingSymbols:
                uniqueUnderlyingSymbols.add(option_symbol.underlying)
                selection = self.filter
                if hasattr(self, "Filter") and callable(self.Filter):
                    selection = self.Filter
                yield Extensions.create_option_chain(algorithm, option_symbol, selection, self.universe_settings)

    def filter(self, filter):
        '''Defines the option chain universe filter'''
        # NOP
        return filter

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Return option canonical symbols only, e.g. Symbol.Create('SPX', SecurityType.IndexOption, Market.USA) or an equity Option canonical.
  2. Confirm the security_type passed to Symbol.Create is one of Option, IndexOption, or FutureOption.
  3. If you only have the underlying, use the appropriate option-canonical helper rather than returning the underlying directly.

Example fix

# before
def selector(utc):
    return [Symbol.Create('SPY', SecurityType.Equity, Market.USA)]  # underlying, not option -> raises

# after
def selector(utc):
    return [Symbol.Create('SPX', SecurityType.IndexOption, Market.USA)]
Defensive patterns

Strategy: validation

Validate before calling

def option_selector(utc):
    syms = my_selector(utc)
    bad = [s for s in syms if not Extensions.is_option(s.security_type)]
    if bad:
        raise ValueError(f'Non-option symbols returned: {bad}')
    return syms

Type guard

def all_are_options(symbols) -> bool:
    return all(Extensions.is_option(s.security_type) for s in symbols)

Prevention

When it happens

Trigger: The option_chain_symbol_selector returns a Symbol whose security_type is not an option variant (e.g., the underlying equity, a raw future, or forex).

Common situations: Returning the underlying symbol instead of the option canonical, using Symbol.Create with the wrong SecurityType, or mixing option subtypes incorrectly.

Related errors


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