microsoft/qlib · error · NotImplementedError

_update_model is not implemented!

Error message

_update_model is not implemented!

What it means

ModelSignal (qlib/backtest/signal.py) is created from a (model, dataset) tuple and is supposed to lazily produce prediction scores. Updating the model with freshly arriving online data each bar (online/mobile backtest mode) is planned but not implemented — the docstring explicitly says the online update path is a TODO. Calling _update_model raises NotImplementedError by design.

Source

Thrown at qlib/backtest/signal.py:85

class ModelSignal(SignalWCache):
    def __init__(self, model: BaseModel, dataset: Dataset) -> None:
        self.model = model
        self.dataset = dataset
        pred_scores = self.model.predict(dataset)
        if isinstance(pred_scores, pd.DataFrame):
            pred_scores = pred_scores.iloc[:, 0]
        super().__init__(pred_scores)

    def _update_model(self) -> None:
        """
        When using online data, update model in each bar as the following steps:
            - update dataset with online data, the dataset should support online update
            - make the latest prediction scores of the new bar
            - update the pred score into the latest prediction
        """
        # TODO: this method is not included in the framework and could be refactor later
        raise NotImplementedError("_update_model is not implemented!")


def create_signal_from(
    obj: Union[Signal, Tuple[BaseModel, Dataset], List, Dict, Text, pd.Series, pd.DataFrame],
) -> Signal:
    """
    create signal from diverse information
    This method will choose the right method to create a signal based on `obj`
    Please refer to the code below.
    """
    if isinstance(obj, Signal):
        return obj
    elif isinstance(obj, (tuple, list)):
        return ModelSignal(*obj)
    elif isinstance(obj, (dict, str)):
        return init_instance_by_config(obj)
    elif isinstance(obj, (pd.DataFrame, pd.Series)):
        return SignalWCache(signal=obj)

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use precomputed prediction scores: call model.predict(dataset) first and pass the resulting Series/DataFrame to create_signal_from, which yields SignalWCache instead of ModelSignal.
  2. Save predictions to a file and create the signal from a dict config pointing at that file (SignalWCache from a pickle path).
  3. If per-bar model updates are genuinely needed, subclass ModelSignal and implement _update_model yourself (update dataset with online data, re-predict, refresh scores).
  4. Check whether your executor/strategy config sets an online-update flag you can disable.

Example fix

# before
signal = create_signal_from((model, dataset))  # ModelSignal -> NotImplementedError on update
# after
pred = model.predict(dataset)
signal = create_signal_from(pred)  # SignalWCache, safe in online loops
Defensive patterns

Strategy: validation

Validate before calling

from qlib.backtest.signal import SignalWCache, ModelSignal
# before starting an online/looped simulation, reject ModelSignal
assert not isinstance(signal, ModelSignal) or not online_mode, 'ModelSignal cannot update online; precompute scores'

Type guard

from qlib.backtest.signal import SignalWCache

def is_precomputed_signal(s) -> bool:
    return isinstance(s, SignalWCache)

Try / catch

try:
    signal.update(...)  # online loop
except NotImplementedError as e:
    if '_update_model' in str(e):
        raise RuntimeError('Precompute model.predict() and use SignalWCache for online simulation') from e
    raise

Prevention

When it happens

Trigger: Running an online/incremental simulation where the executor loop calls signal update hooks each bar (e.g. nested execution with online data via signal.update_score/update paths), while the signal was built from a (model, dataset) tuple via create_signal_from.

Common situations: Users run qlib's online serving / mobile backtest examples that expect SignalWCache (precomputed scores) but pass a model+dataset tuple instead; or they upgrade to a qlib version where the online loop now invokes _update_model unconditionally.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/b4accdba31c2a388. Report an issue: GitHub.