microsoft/qlib · error · QlibException
MultiPassPortAnaRecord require the passed in strategy to hav
Error message
MultiPassPortAnaRecord require the passed in strategy to have signal as a parameter
What it means
The companion check in MultiPassPortAnaRecord.__init__: after verifying the copied strategy is a dict, it requires 'signal' to be present under strategy['kwargs']. Between the N backtest passes the record replaces the signal's prediction scores (random_init shuffles the first backtest date's scores), which is only possible if the strategy reads its prediction through the kwargs['signal'] slot. A dict strategy without that key raises QlibException at construction.
Source
Thrown at qlib/workflow/record_temp.py:615
----------
recorder : Recorder
The recorder used to save the backtest results.
pass_num : int
The number of backtest passes.
shuffle_init_score : bool
Whether to shuffle the prediction score of the first backtest date.
"""
self.pass_num = pass_num
self.shuffle_init_score = shuffle_init_score
super().__init__(recorder, **kwargs)
# Save original strategy so that pred df can be replaced in next generate
self.original_strategy = deepcopy_basic_type(self.strategy_config)
if not isinstance(self.original_strategy, dict):
raise QlibException("MultiPassPortAnaRecord require the passed in strategy to be a dict")
if "signal" not in self.original_strategy.get("kwargs", {}):
raise QlibException("MultiPassPortAnaRecord require the passed in strategy to have signal as a parameter")
def random_init(self):
pred_df = self.load("pred.pkl")
all_pred_dates = pred_df.index.get_level_values("datetime")
bt_start_date = pd.to_datetime(self.backtest_config.get("start_time"))
if bt_start_date is None:
first_bt_pred_date = all_pred_dates.min()
else:
first_bt_pred_date = all_pred_dates[all_pred_dates >= bt_start_date].min()
# Shuffle the first backtest date's pred score
first_date_score = pred_df.loc[first_bt_pred_date]["score"]
np.random.shuffle(first_date_score.values)
# Use shuffled signal as the strategy signal
self.strategy_config = deepcopy_basic_type(self.original_strategy)
self.strategy_config["kwargs"]["signal"] = pred_dfView on GitHub (pinned to 79633dd950)
Solutions
- Add 'signal' to the strategy kwargs, typically the <PRED> placeholder or a prediction object: kwargs: {signal: <PRED>, topk: 50, n_drop: 5}
- Copy a known-good MultiPassPortAnaRecord example config from qlib's examples directory and diff your yaml against it
- If your strategy has no signal slot, multi-pass shuffling is meaningless — use PortAnaRecord instead
Example fix
# before
strategy = {
'class': 'TopkDropoutStrategy',
'module_path': 'qlib.contrib.strategy.signal_strategy',
'kwargs': {'topk': 50, 'n_drop': 5}, # no 'signal' -> QlibException
}
# after
strategy = {
'class': 'TopkDropoutStrategy',
'module_path': 'qlib.contrib.strategy.signal_strategy',
'kwargs': {'signal': '<PRED>', 'topk': 50, 'n_drop': 5},
} Defensive patterns
Strategy: validation
Validate before calling
def validate_strategy_signal(config: dict):
strategy = config.get('strategy')
assert isinstance(strategy, dict), 'strategy must be a dict'
kwargs = strategy.get('kwargs', {})
if 'signal' not in kwargs:
raise KeyError("strategy['kwargs'] must include 'signal' (use '<PRED>' placeholder)")
return config Type guard
def has_signal_kwarg(strategy) -> bool:
return isinstance(strategy, dict) and 'signal' in strategy.get('kwargs', {}) Try / catch
try:
MultiPassPortAnaRecord(recorder=rec, config=config)
except QlibException as e:
if 'signal as a parameter' in str(e):
config['strategy']['kwargs']['signal'] = '<PRED>'
MultiPassPortAnaRecord(recorder=rec, config=config)
else:
raise Prevention
- Use the <PRED> placeholder in strategy kwargs in workflow yaml
- Diff against a known-good MultiPassPortAnaRecord example before running
- If the strategy has no signal input, use plain PortAnaRecord instead
When it happens
Trigger: Passing a strategy dict whose 'kwargs' omits 'signal' (e.g. only topk/n_drop for TopkDropoutStrategy); a config that names a non-signal-based strategy class; yaml where the signal entry was commented out or mis-indented out of kwargs.
Common situations: Adapting a PortAnaRecord config (where signal may be injected automatically from the task) to MultiPassPortAnaRecord, which resolves it eagerly; renaming the key (e.g. 'model' or 'pred') instead of 'signal'; trimming kwargs while tuning.
Related errors
- MultiPassPortAnaRecord require the passed in strategy to be
- method {method} is not supported!
- This type of input {rtype} is not supported
- Can't find the BASE_CONFIG file: {base_config_path}
- Invalid Qlib configuration (note: the global config has alre
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/ddb8e7a568b9aa6e.
Report an issue: GitHub.