QuantConnect/Lean · error · Exception

IRiskManagementModel.{attribute_names[1]} must be implemente

Error message

IRiskManagementModel.{attribute_names[1]} must be implemented. Please implement this missing method on {model.__class__.__name__}

What it means

CompositeRiskManagementModel.__init__ validates that every model passed to it implements the IRiskManagementModel contract. It checks, for each model, both the PascalCase and snake_case spellings of two required methods: ManageRisk/manage_risk and OnSecuritiesChanged/on_securities_changed. If a model has neither spelling of a given method, it raises an Exception naming the model class. This is a contract-enforcement check at composition time, before the algorithm runs.

Source

Thrown at Algorithm/Risk/CompositeRiskManagementModel.py:27

# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *

class CompositeRiskManagementModel(RiskManagementModel):
    '''Provides an implementation of IRiskManagementModel that combines multiple risk models
    into a single risk management model and properly sets each insights 'SourceModel' property.'''

    def __init__(self, *risk_management_models):
        '''Initializes a new instance of the CompositeRiskManagementModel class
        Args:
            risk_management_models: The individual risk management models defining this composite model.'''
        for model in risk_management_models:
            for attribute_names in [('ManageRisk', 'manage_risk'), ('OnSecuritiesChanged', 'on_securities_changed')]:
                if not hasattr(model, attribute_names[0]) and not hasattr(model, attribute_names[1]):
                    raise Exception(f'IRiskManagementModel.{attribute_names[1]} must be implemented. Please implement this missing method on {model.__class__.__name__}')

        self.risk_management_models = risk_management_models

    def manage_risk(self, algorithm, targets):
        '''Manages the algorithm's risk at each time step
        Args:
            algorithm: The algorithm instance
            targets: The current portfolio targets to be assessed for risk'''
        for model in self.risk_management_models:
            # take into account the possibility of ManageRisk returning nothing
            risk_adjusted = model.manage_risk(algorithm, targets)

            # produce a distinct set of new targets giving preference to newer targets
            symbols = [x.symbol for x in risk_adjusted]
            for target in targets:
                if target.symbol not in symbols:
                    risk_adjusted.append(target)

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Ensure each passed model subclasses RiskManagementModel (which supplies both methods) OR explicitly defines both manage_risk and on_securities_changed.
  2. If you wrote a duck-typed model, add the missing method — e.g. def on_securities_changed(self, algorithm, changes): pass.
  3. Check the contract up front: for each model verify hasattr(model,'manage_risk') and hasattr(model,'on_securities_changed') before constructing the composite.
  4. After a Lean upgrade, confirm the required-method names (snake_case) did not change.

Example fix

# before — model only defines one method
class MyRiskModel:
    def manage_risk(self, algorithm, targets):
        return []
# ...
self.set_risk_management(CompositeRiskManagementModel(MyRiskModel()))  # raises

# after — implement the full contract (or subclass RiskManagementModel)
class MyRiskModel(RiskManagementModel):
    def manage_risk(self, algorithm, targets):
        return []
    def on_securities_changed(self, algorithm, changes):
        pass
self.set_risk_management(CompositeRiskManagementModel(MyRiskModel()))
Defensive patterns

Strategy: validation

Validate before calling

# Validate each model implements the contract before composing
def is_valid_risk_model(model):
    return ((hasattr(model,'manage_risk') or hasattr(model,'ManageRisk'))
            and (hasattr(model,'on_securities_changed') or hasattr(model,'OnSecuritiesChanged')))
for m in models:
    if not is_valid_risk_model(m):
        raise ValueError(f"{type(m).__name__} does not implement the risk model contract")
composite = CompositeRiskManagementModel(*models)

Type guard

def implements_risk_contract(model):
    """True when model exposes both required methods (either spelling)."""
    has_manage = hasattr(model, 'manage_risk') or hasattr(model, 'ManageRisk')
    has_changed = hasattr(model, 'on_securities_changed') or hasattr(model, 'OnSecuritiesChanged')
    return has_manage and has_changed

Prevention

When it happens

Trigger: You construct CompositeRiskManagementModel(model_a, model_b, ...) where at least one model is missing both manage_risk and ManageRisk, or both on_securities_changed and OnSecuritiesChanged. Concretely: passing a plain object or a half-implemented subclass (e.g. one that defines manage_risk but forgets the securities-changed hook) triggers it. Note the check uses `and not hasattr` for both spellings, so defining either spelling satisfies it.

Common situations: A user subclasses RiskManagementModel but only overrides manage_risk, forgetting on_securities_changed (the base provides defaults, but if the object is not a proper subclass it lacks both). Passing a lambda/duck-typed object that does not implement the full interface. A refactor renamed a method and broke the contract.

Related errors


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