microsoft/qlib · error · ValueError
Unexpected order direction: {direction}
Error message
Unexpected order direction: {direction} What it means
ValueError from `calculate_trade_value`-style PAW/baseline-bps computation in qlib/rl/order_execution/simulator_simple.py:357. The `direction` argument must equal `OrderDir.BUY` or `OrderDir.SELL`; anything else (2, -1, None, a raw string) hits the else branch.
Source
Thrown at qlib/rl/order_execution/simulator_simple.py:357
return pd.concat([df, other_df], axis=0)
def price_advantage(
exec_price: float_or_ndarray,
baseline_price: float,
direction: OrderDir | int,
) -> float_or_ndarray:
if baseline_price == 0: # something is wrong with data. Should be nan here
if isinstance(exec_price, float):
return 0.0
else:
return np.zeros_like(exec_price)
if direction == OrderDir.BUY:
res = (1 - exec_price / baseline_price) * 10000
elif direction == OrderDir.SELL:
res = (exec_price / baseline_price - 1) * 10000
else:
raise ValueError(f"Unexpected order direction: {direction}")
res_wo_nan: np.ndarray = np.nan_to_num(res, nan=0.0)
if res_wo_nan.size == 1:
return res_wo_nan.item()
else:
return cast(float_or_ndarray, res_wo_nan)
View on GitHub (pinned to 79633dd950)
Solutions
- Pass `order.direction` (an `OrderDir` member) rather than a raw int or string.
- Sanitize external direction data: map {1,'buy','B'}->OrderDir.BUY, {0/2? no, 2 is invalid}, {0,'sell','S'}->OrderDir.SELL per your data convention, and reject everything else at load time.
- If you defined a custom direction enum, convert with `OrderDir(direction)` inside a try/except ValueError to fail with a clear message.
Example fix
// before
res = calculate_trade_value(price, baseline, row["side"]) # side is 'B'/'S' string
// after
from qlib.rl.order_execution.simulator_simple import OrderDir # or qlib.utils.enum
dir_map = {"B": OrderDir.BUY, "S": OrderDir.SELL}
res = calculate_trade_value(price, baseline, dir_map[row["side"]]) Defensive patterns
Strategy: type-guard
Validate before calling
from qlib.utils.enum import OrderDir # IntEnum: BUY=0, SELL=1
assert direction in (OrderDir.BUY, OrderDir.SELL, 0, 1), f"bad direction {direction!r}" Type guard
from qlib.utils.enum import OrderDir
def is_valid_direction(d) -> bool:
return d in (OrderDir.BUY, OrderDir.SELL) Try / catch
try:
value = calculate_trade_value(p, b, direction)
except ValueError as e:
if "Unexpected order direction" in str(e):
raise ValueError(f"bad direction {direction!r} in trade record") from e
raise Prevention
- Convert direction to OrderDir at the data-loading boundary.
- Never pass strings or arbitrary ints to trade-value helpers.
- Add a schema check on order dataframes (direction values in {0,1}).
When it happens
Trigger: Passing `direction` as an unvalidated int from user code or serialized data (e.g. 2 from a mislabeled dataset), or passing None because an order object's direction field was never set. Note `OrderDir` is an IntEnum, so plain 0/1 also work but 2/-1 fail.
Common situations: Loading order lists from CSV/database where direction is stored as arbitrary ints; refactors that pass the whole `Order` object instead of `order.direction`; downstream code assuming SELL=-1.
Related errors
- Unexpected order direction: {direction}
- Order direction cannot be none when deal_price_type is not c
- Sample must be a dict with same length as space.
- Execution volume is invalid: {exec_vol} (position = {self.po
- Seed iterator for validation is not available.
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/87717f6f2a325f17.
Report an issue: GitHub.