{"record":{"id":"c480280b735dc251","repo":"microsoft/qlib","slug":"unexpected-order-direction-direction-c48028","errorCode":null,"errorMessage":"Unexpected order direction: {direction}","messagePattern":"Unexpected order direction: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/rl/order_execution/utils.py","lineNumber":40,"sourceCode":"    return res\n\n\ndef price_advantage(\n    exec_price: float_or_ndarray,\n    baseline_price: float,\n    direction: OrderDir | int,\n) -> float_or_ndarray:\n    if baseline_price == 0:  # something is wrong with data. Should be nan here\n        if isinstance(exec_price, float):\n            return 0.0\n        else:\n            return np.zeros_like(exec_price)\n    if direction == OrderDir.BUY:\n        res = (1 - exec_price / baseline_price) * 10000\n    elif direction == OrderDir.SELL:\n        res = (exec_price / baseline_price - 1) * 10000\n    else:\n        raise ValueError(f\"Unexpected order direction: {direction}\")\n    res_wo_nan: np.ndarray = np.nan_to_num(res, nan=0.0)\n    if res_wo_nan.size == 1:\n        return res_wo_nan.item()\n    else:\n        return cast(float_or_ndarray, res_wo_nan)\n\n\ndef get_simulator_executor(executor: BaseExecutor) -> SimulatorExecutor:\n    while isinstance(executor, NestedExecutor):\n        executor = executor.inner_executor\n    assert isinstance(executor, SimulatorExecutor)\n    return executor\n","sourceCodeStart":22,"sourceCodeEnd":53,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/rl/order_execution/utils.py#L22-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvalue = calculate_trade_value(p, b, d)  # d loaded from CSV, sometimes 'buy'\n// after\nfrom qlib.rl.utils.enum import OrderDir\nd = OrderDir.BUY if str(d).upper().startswith(\"B\") else OrderDir.SELL\nvalue = calculate_trade_value(p, b, d)","handlingStrategy":"type-guard","validationCode":"from qlib.utils.enum import OrderDir\nvalid = {0, 1, OrderDir.BUY, OrderDir.SELL}\nassert direction in valid, f\"direction {direction!r} not in {valid}\"","typeGuard":"def is_order_direction(d) -> bool:\n    return d in (0, 1) or str(d) in (\"OrderDir.BUY\", \"OrderDir.SELL\")","tryCatchPattern":"try:\n    res = calculate_trade_value(exec_price, baseline, direction)\nexcept ValueError as e:\n    if \"Unexpected order direction\" in str(e):\n        direction = int(direction)\n        if direction not in (0, 1):\n            raise\n        res = calculate_trade_value(exec_price, baseline, direction)\n    else:\n        raise","preventionTips":["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."],"tags":["rl","order-execution","enum","validation","utils"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}