microsoft/qlib · error · NotImplementedError
This type of `limit_threshold` is not supported
Error message
This type of `limit_threshold` is not supported
What it means
Exchange._get_limit_type classifies limit_threshold into three regimes: tuple -> explicit limit up/down expressions (LT_TP_EXP), float -> |$change| < threshold (LT_FLT), None -> no limit (LT_NONE). Any other type raises NotImplementedError. Note the isinstance check is strictly float, so a Python int (e.g. 0 from config) is rejected even though it looks numeric.
Source
Thrown at qlib/backtest/exchange.py:271
self.extra_quote["limit_buy"] = False
self.logger.warning("No limit_buy set for extra_quote. All stock will be able to be bought.")
assert set(self.extra_quote.columns) == set(self.quote_df.columns) - {"$change"}
self.quote_df = pd.concat([self.quote_df, self.extra_quote], sort=False, axis=0)
LT_TP_EXP = "(exp)" # Tuple[str, str]: the limitation is calculated by a Qlib expression.
LT_FLT = "float" # float: the trading limitation is based on `abs($change) < limit_threshold`
LT_NONE = "none" # none: there is no trading limitation
def _get_limit_type(self, limit_threshold: Union[tuple, float, None]) -> str:
"""get limit type"""
if isinstance(limit_threshold, tuple):
return self.LT_TP_EXP
elif isinstance(limit_threshold, float):
return self.LT_FLT
elif limit_threshold is None:
return self.LT_NONE
else:
raise NotImplementedError(f"This type of `limit_threshold` is not supported")
def _update_limit(self, limit_threshold: Union[Tuple, float, None]) -> None:
# $close may contain NaN, the nan indicates that the stock is not tradable at that timestamp
suspended = self.quote_df["$close"].isna()
# check limit_threshold
limit_type = self._get_limit_type(limit_threshold)
if limit_type == self.LT_NONE:
self.quote_df["limit_buy"] = suspended
self.quote_df["limit_sell"] = suspended
elif limit_type == self.LT_TP_EXP:
# set limit
limit_threshold = cast(tuple, limit_threshold)
# astype bool is necessary, because quote_df is an expression and could be float
self.quote_df["limit_buy"] = self.quote_df[limit_threshold[0]].astype("bool") | suspended
self.quote_df["limit_sell"] = self.quote_df[limit_threshold[1]].astype("bool") | suspended
elif limit_type == self.LT_FLT:
limit_threshold = cast(float, limit_threshold)
self.quote_df["limit_buy"] = self.quote_df["$change"].ge(limit_threshold) | suspendedView on GitHub (pinned to 79633dd950)
Solutions
- Cast to float: Exchange(limit_threshold=float(threshold))
- For asymmetric CN-style limits, pass a tuple of (limit_up_expression, limit_down_expression)
- Pass None explicitly when you want no limit check
Example fix
# before exch = Exchange(limit_threshold=cfg['limit_threshold']) # int 0 -> NotImplementedError # after exch = Exchange(limit_threshold=float(cfg['limit_threshold']))
Defensive patterns
Strategy: type-guard
Validate before calling
if limit_threshold is not None and not isinstance(limit_threshold, tuple):
limit_threshold = float(limit_threshold) # int/str -> float
exch = Exchange(limit_threshold=limit_threshold) Type guard
def is_valid_limit_threshold(lt) -> bool:
return lt is None or isinstance(lt, (tuple, float)) Prevention
- Wrap config-loaded thresholds in float()
- int is rejected: 0 and 1 must be written 0.0 / 1.0 or cast
When it happens
Trigger: Exchange(limit_threshold=0) or limit_threshold=1 (int); limit_threshold='0.1' (string from YAML/env); passing a pandas/numpy scalar that is not a float instance.
Common situations: Config files where the threshold is parsed as int or str; CLI/env-passed values that keep string types; code that computed the threshold with integer arithmetic.
Related errors
- This type of input 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/daa34d2d450c308e.
Report an issue: GitHub.