microsoft/qlib · error · ValueError
`factor` and (`stock_id`, `start_time`, `end_time`) can't bo
Error message
`factor` and (`stock_id`, `start_time`, `end_time`) can't both be None
What it means
Exchange._get_factor_or_raise_error resolves the adjustment factor either directly from the `factor` argument or by looking it up via (stock_id, start_time, end_time). If factor is None and any of the three lookup keys is missing, there is no way to obtain a factor, so ValueError is raised. It backs get_amount_of_trade_unit and round_amount_by_trade_unit when rounding order amounts to board lots.
Source
Thrown at qlib/backtest/exchange.py:724
direction=direction,
)
* amount_dict[stock_id]
)
return value
def _get_factor_or_raise_error(
self,
factor: float | None = None,
stock_id: str | None = None,
start_time: pd.Timestamp = None,
end_time: pd.Timestamp = None,
) -> float:
"""Please refer to the docs of get_amount_of_trade_unit"""
if factor is None:
if stock_id is not None and start_time is not None and end_time is not None:
factor = self.get_factor(stock_id=stock_id, start_time=start_time, end_time=end_time)
else:
raise ValueError(f"`factor` and (`stock_id`, `start_time`, `end_time`) can't both be None")
assert factor is not None
return factor
def get_amount_of_trade_unit(
self,
factor: float | None = None,
stock_id: str | None = None,
start_time: pd.Timestamp = None,
end_time: pd.Timestamp = None,
) -> Optional[float]:
"""
get the trade unit of amount based on **factor**
the factor can be given directly or calculated in given time range and stock id.
`factor` has higher priority than `stock_id`, `start_time` and `end_time`
Parameters
----------
factor : float
the adjusted factorView on GitHub (pinned to 79633dd950)
Solutions
- Pass a complete lookup triple: exch.get_amount_of_trade_unit(stock_id=sid, start_time=t0, end_time=t1)
- Or supply the factor directly: exch.get_amount_of_trade_unit(factor=1.0) (1.0 means unadjusted prices)
- When calling from order-processing code, forward order.stock_id/order.start_time/order.end_time together
Example fix
# before unit_amt = exch.get_amount_of_trade_unit(stock_id=sid, start_time=t0) # end_time missing # after unit_amt = exch.get_amount_of_trade_unit(stock_id=sid, start_time=t0, end_time=t1)
Defensive patterns
Strategy: validation
Validate before calling
if factor is None:
assert stock_id is not None and start_time is not None and end_time is not None, \
'provide factor or all of (stock_id, start_time, end_time)'
unit = exch.get_amount_of_trade_unit(factor=factor, stock_id=stock_id, start_time=start_time, end_time=end_time) Type guard
def factor_args_complete(factor, stock_id, start_time, end_time) -> bool:
return factor is not None or all(x is not None for x in (stock_id, start_time, end_time)) Prevention
- Forward order.stock_id/start_time/end_time as a complete triple
- Pass factor=1.0 explicitly when working with unadjusted prices
When it happens
Trigger: Calling get_amount_of_trade_unit / round_amount_by_trade_unit with factor=None and only a partial key set (e.g. stock_id without start_time/end_time).
Common situations: Custom strategies calling the trade-unit API with just a stock id; optional-argument chains where timestamps default to None and are forwarded silently.
Related errors
- Get Unexpected arguments {kwargs}
- This type of input is not supported
- $close is necessray in extra_quote
- This type of `limit_threshold` is not supported
- direction {direction} is not supported!
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/4c7d0229bd764aff.
Report an issue: GitHub.