microsoft/qlib · error · NotImplementedError
This type of input is not supported
Error message
This type of input is not supported
What it means
Exchange normalizes deal_price into $-prefixed column names: a str becomes both buy and sell price (e.g. 'close' -> '$close'), and a tuple/list of two strings becomes (buy_price, sell_price). Any other Python type (int, float, dict, None mishandled, pd.Series) cannot name a quote column, so __init__ raises NotImplementedError.
Source
Thrown at qlib/backtest/exchange.py:164
# TODO: the quote, trade_dates, codes are not necessary.
# It is just for performance consideration.
self.limit_type = self._get_limit_type(limit_threshold)
if limit_threshold is None:
if C.region in [REG_CN, REG_TW]:
self.logger.warning(f"limit_threshold not set. The stocks hit the limit may be bought/sold")
elif self.limit_type == self.LT_FLT and abs(cast(float, limit_threshold)) > 0.1:
if C.region in [REG_CN, REG_TW]:
self.logger.warning(f"limit_threshold may not be set to a reasonable value")
if isinstance(deal_price, str):
if deal_price[0] != "$":
deal_price = "$" + deal_price
self.buy_price = self.sell_price = deal_price
elif isinstance(deal_price, (tuple, list)):
self.buy_price, self.sell_price = cast(Tuple[str, str], deal_price)
else:
raise NotImplementedError(f"This type of input is not supported")
if isinstance(codes, str):
codes = D.instruments(codes)
self.codes = codes
# Necessary fields
# $close is for calculating the total value at end of each day.
# - if $close is None, the stock on that day is regarded as suspended.
# $factor is for rounding to the trading unit
# $change is for calculating the limit of the stock
# get volume limit from kwargs
self.buy_vol_limit, self.sell_vol_limit, vol_lt_fields = self._get_vol_limit(volume_threshold)
necessary_fields = {self.buy_price, self.sell_price, "$close", "$change", "$factor", "$volume"}
if self.limit_type == self.LT_TP_EXP:
assert isinstance(limit_threshold, tuple)
for exp in limit_threshold:
necessary_fields.add(exp)View on GitHub (pinned to 79633dd950)
Solutions
- Pass a single column name string: Exchange(deal_price='close') -> uses $close for both sides
- Or pass a 2-tuple of strings: Exchange(deal_price=('buy_vwap', 'sell_vwap'))
- Validate config-loaded values before constructing: assert isinstance(deal_price, (str, tuple, list))
Example fix
# before
exch = Exchange(deal_price=('close', 'vwap', 'open')) # wrong arity/type combos
# after
exch = Exchange(deal_price=('close', 'vwap')) Defensive patterns
Strategy: type-guard
Validate before calling
assert isinstance(deal_price, (str, tuple, list)), 'deal_price must be str or (buy, sell) strings'
if isinstance(deal_price, (tuple, list)):
assert len(deal_price) == 2 and all(isinstance(p, str) for p in deal_price)
exch = Exchange(deal_price=deal_price) Type guard
def is_valid_deal_price(p) -> bool:
if isinstance(p, str):
return True
return isinstance(p, (tuple, list)) and len(p) == 2 and all(isinstance(x, str) for x in p) Prevention
- Remember deal_price names a quote column ('close', 'vwap'), not a number
- Assert the type when deal_price comes from config files
When it happens
Trigger: Exchange(deal_price=0.98), Exchange(deal_price=('close',)), or passing a DataFrame/Series of prices instead of a column name; also deal_price loaded from YAML as a non-string scalar.
Common situations: Confusing deal_price (a quote field name like 'close' or 'vwap') with an actual numeric price; configs where deal_price ends up as None after a lookup fails; tuples with the wrong arity.
Related errors
- This type of `limit_threshold` is not supported
- order direction {} error
- 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
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/de1ab8e5e986f1ea.
Report an issue: GitHub.