QuantConnect/Lean · error · Exception

MaximumSectorExposureRiskManagementModel.on_securities_chang

Error message

MaximumSectorExposureRiskManagementModel.on_securities_changed: Please select a portfolio selection model that selects securities with fundamental data.

What it means

MaximumSectorExposureRiskManagementModel.on_securities_changed requires every managed security to carry fundamental data (specifically sector) so it can group positions by sector. If no security in algorithm.active_securities has fundamentals.has_fundamental_data, it cannot attribute exposure by sector and raises a generic Exception.

Source

Thrown at Algorithm.Framework/Risk/MaximumSectorExposureRiskManagementModel.py:89

            if ratio > 1:
                for symbol, quantity in quantities.items():
                    if quantity != 0:
                        risk_targets.append(PortfolioTarget(symbol, float(quantity) / ratio))

        return risk_targets

    def on_securities_changed(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
        any_fundamental_data = any([
            kvp.value.fundamentals is not None and
            kvp.value.fundamentals.has_fundamental_data for kvp in algorithm.active_securities
            ])

        if not any_fundamental_data:
            raise Exception("MaximumSectorExposureRiskManagementModel.on_securities_changed: Please select a portfolio selection model that selects securities with fundamental data.")

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Use a portfolio/universe selection model that yields securities with fundamentals — e.g., FineFundamentalUniverseSelectionModel or FundamentalUniverseSelectionModel.
  2. If using manual AddEquity, ensure the securities are fundamental-eligible (US equities) and that fine data is enabled.
  3. Avoid attaching this risk model to option/future/crypto-only algorithms; pick a risk model that doesn't need sector data.

Example fix

# before
self.set_universe_selection(CoarseFundamentalUniverseSelectionModel(self.coarse))
self.add_risk_management(MaximumSectorExposureRiskManagementModel(0.20))  # no fundamentals -> raises

# after
self.set_universe_selection(FineFundamentalUniverseSelectionModel(self.fine))
self.add_risk_management(MaximumSectorExposureRiskManagementModel(0.20))
Defensive patterns

Strategy: validation

Validate before calling

# Only attach this risk model when the universe yields fundamental data
has_fundamentals = any(
    s.fundamentals is not None and s.fundamentals.has_fundamental_data
    for s in algorithm.active_securities.Values
)
if has_fundamentals:
    self.add_risk_management(MaximumSectorExposureRiskManagementModel(0.20))

Type guard

def universe_has_fundamentals(algorithm) -> bool:
    return any(
        kvp.value.fundamentals is not None and kvp.value.fundamentals.has_fundamental_data
        for kvp in algorithm.active_securities
    )

Prevention

When it happens

Trigger: The algorithm's universe/portfolio selection picked securities without fundamental data (e.g., a coarse-only universe, an options/futures universe, or custom data), so the any(...) check over active_securities is false when securities change.

Common situations: Using CoarseFundamentalUniverseSelectionModel or a manual AddSecurity set without fine fundamentals; selecting options/crypto/forex; or a fine universe whose filter stripped out all fundamental-bearing symbols.

Related errors


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