microsoft/qlib · error · ValueError
trade_info is necessary in atomic executor
Error message
trade_info is necessary in atomic executor
What it means
DatasetCache.update (qlib/data/cache.py:464) is the abstract method that extends dataset cache files to the latest calendar, returning 0 (updated) / 1 (no update needed) / 2 (failure). The base class has no implementation, so calling it raises NotImplementedError (the message text about 'expression cache' is a copy-paste from ExpressionCache but the intent is dataset cache refresh).
Source
Thrown at qlib/backtest/account.py:381
- else, aggregate indicators with inner indicators
outer_trade_decision: BaseTradeDecision
external trade decision
trade_info : List[(Order, float, float, float)], optional
trading information, by default None
- necessary if atomic is True
- list of tuple(order, trade_val, trade_cost, trade_price)
inner_order_indicators : Indicator, optional
indicators of inner executor, by default None
- necessary if atomic is False
- used to aggregate outer indicators
decision_list: List[Tuple[BaseTradeDecision, pd.Timestamp, pd.Timestamp]] = None,
The decision list of the inner level: List[Tuple[<decision>, <start_time>, <end_time>]]
The inner level
indicator_config : dict, optional
config of calculating indicators, by default {}
"""
if atomic is True and trade_info is None:
raise ValueError("trade_info is necessary in atomic executor")
elif atomic is False and inner_order_indicators is None:
raise ValueError("inner_order_indicators is necessary in un-atomic executor")
# update current position and hold bar count in each bar end
self.update_current_position(trade_start_time, trade_end_time, trade_exchange)
if self.is_port_metr_enabled():
# portfolio_metrics is portfolio related analysis
self.update_portfolio_metrics(trade_start_time, trade_end_time)
self.update_hist_positions(trade_start_time)
# update indicator in each bar end
self.update_indicator(
trade_start_time=trade_start_time,
trade_exchange=trade_exchange,
atomic=atomic,
outer_trade_decision=outer_trade_decision,
trade_info=trade_info,View on GitHub (pinned to 79633dd950)
Solutions
- Use DiskDatasetCache.update(cache_uri, freq), which is implemented for the disk format
- Override update(self, cache_uri: Union[str, Path], freq: str = 'day') -> int in your subclass
- If incremental update is unsupported by your backend, delete and regenerate the dataset cache instead
Example fix
# before DatasetCache(provider).update(cache_uri, "day") # NotImplementedError # after from qlib.data.cache import DiskDatasetCache DiskDatasetCache.update(cache_uri, "day") # classmethod-friendly in shipped impl
Defensive patterns
Strategy: try-catch
Validate before calling
from qlib.data.cache import DatasetCache assert MyDSCache.update is not DatasetCache.update, "update() not implemented"
Try / catch
try:
status = cache.update(cache_uri, freq)
except NotImplementedError:
shutil.rmtree(cache_dir, ignore_errors=True)
regenerate_dataset_cache(insts, fields, freq) Prevention
- Automate daily cache refresh with a fallback-to-rebuild policy
- Only use cache classes whose update() is implemented (DiskDatasetCache)
- Treat status code 2 (failure) the same as needing a rebuild
When it happens
Trigger: Invoking dataset-cache refresh (directly or via scripts that call DatasetCache.update after new trading data is dumped) on the base DatasetCache or a subclass that does not override update.
Common situations: Daily incremental pipeline: dump new bar data, then refresh dataset caches; custom cache backend where only read paths were implemented.
Related errors
- nfs-common is not found, please install it by execute: sudo
- Mount failed: requires sudo or permission denied
- mount {provider_uri} on {mount_path} error! Command error
- Mount failed: {e.stderr}
- We can't find the project path
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/e861c3928178b4b9.
Report an issue: GitHub.