microsoft/qlib · error · ValueError
Unexpected order direction: {direction}
Error message
Unexpected order direction: {direction} What it means
ValueError from `calculate_trade_value` in qlib/rl/order_execution/utils.py:40 (the shared util version of the same function also present in simulator_simple.py). `direction` must be `OrderDir.BUY` or `OrderDir.SELL` (or their int values 0/1); any other value falls into the final else and raises.
Source
Thrown at qlib/rl/order_execution/utils.py:40
return res
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)
def get_simulator_executor(executor: BaseExecutor) -> SimulatorExecutor:
while isinstance(executor, NestedExecutor):
executor = executor.inner_executor
assert isinstance(executor, SimulatorExecutor)
return executor
View on GitHub (pinned to 79633dd950)
Solutions
- Convert direction at the boundary: `direction = OrderDir(int(direction))` and catch ValueError to reject bad data immediately.
- Audit the data source producing direction values; fix the encoding so only 0/1 ever appear.
- Prefer importing and using the enum members directly instead of numeric literals in your code.
Example fix
// before
value = calculate_trade_value(p, b, d) # d loaded from CSV, sometimes 'buy'
// after
from qlib.rl.utils.enum import OrderDir
d = OrderDir.BUY if str(d).upper().startswith("B") else OrderDir.SELL
value = calculate_trade_value(p, b, d) Defensive patterns
Strategy: type-guard
Validate before calling
from qlib.utils.enum import OrderDir
valid = {0, 1, OrderDir.BUY, OrderDir.SELL}
assert direction in valid, f"direction {direction!r} not in {valid}" Type guard
def is_order_direction(d) -> bool:
return d in (0, 1) or str(d) in ("OrderDir.BUY", "OrderDir.SELL") Try / catch
try:
res = calculate_trade_value(exec_price, baseline, direction)
except ValueError as e:
if "Unexpected order direction" in str(e):
direction = int(direction)
if direction not in (0, 1):
raise
res = calculate_trade_value(exec_price, baseline, direction)
else:
raise Prevention
- Normalize direction to OrderDir members as soon as data enters the program.
- Reject unknown direction values at ingestion with a clear error.
- Use the enum members instead of magic numbers in all call sites.
When it happens
Trigger: Calling `calculate_trade_value(..., direction=dir_val)` with `dir_val` outside {0, 1, OrderDir.BUY, OrderDir.SELL}: e.g. 2, -1, None, or a string like 'buy' that was never converted to the enum.
Common situations: Reward/metric code iterating over trade records from a dataframe where direction came back as a generic int or object dtype; custom executors that store direction as a string; pickle-roundtrips that lose the IntEnum type and leave a plain int outside the valid range.
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/c480280b735dc251.
Report an issue: GitHub.