microsoft/qlib · error · NotImplementedError

do not support order direction {}

Error message

do not support order direction {}

What it means

Position.update_order dispatches on order.direction: Order.BUY routes to _buy_stock, Order.SELL to _sell_stock; every other value raises NotImplementedError('do not support order direction {}'). Order directions are integers (Order.BUY=1, Order.SELL=-1 in qlib's Order class), so 0 or arbitrary ints/None are rejected.

Source

Thrown at qlib/backtest/position.py:399

        else:
            raise NotImplementedError(f"This type of input is not supported")

    def _del_stock(self, stock_id: str) -> None:
        del self.position[stock_id]

    def check_stock(self, stock_id: str) -> bool:
        return stock_id in self.position

    def update_order(self, order: Order, trade_val: float, cost: float, trade_price: float) -> None:
        # handle order, order is a order class, defined in exchange.py
        if order.direction == Order.BUY:
            # BUY
            self._buy_stock(order.stock_id, trade_val, cost, trade_price)
        elif order.direction == Order.SELL:
            # SELL
            self._sell_stock(order.stock_id, trade_val, cost, trade_price)
        else:
            raise NotImplementedError("do not support order direction {}".format(order.direction))

    def update_stock_price(self, stock_id: str, price: float) -> None:
        self.position[stock_id]["price"] = price

    def update_stock_count(self, stock_id: str, bar: str, count: float) -> None:  # TODO: check type of `bar`
        self.position[stock_id][f"count_{bar}"] = count

    def update_stock_weight(self, stock_id: str, weight: float) -> None:
        self.position[stock_id]["weight"] = weight

    def calculate_stock_value(self) -> float:
        stock_list = self.get_stock_list()
        value = 0
        for stock_id in stock_list:
            value += self.position[stock_id]["amount"] * self.position[stock_id]["price"]
        return value

    def calculate_value(self) -> float:

View on GitHub (pinned to 79633dd950)

Solutions

  1. Always set direction from Order.BUY / Order.SELL when constructing orders
  2. Filter out non-trade orders (amount_delta == 0 / 'hold') before calling update_order
  3. If you genuinely need extra directions, override update_order in a custom Position subclass

Example fix

# before
order = Order(stock_id, 0, amount, trade_info)  # direction unset

# after
from qlib.backtest.order import Order
order = Order(stock_id, Order.SELL if signal < 0 else Order.BUY, amount, trade_info)
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.backtest.order import Order
assert order.direction in (Order.BUY, Order.SELL), f"bad direction {order.direction}"

Type guard

def is_trade_direction(d) -> bool:
    return d in (Order.BUY, Order.SELL)

Try / catch

try:
    position.update_order(order, trade_val, cost, trade_price)
except NotImplementedError:
    logger.warning("skipping order with direction %s", order.direction)

Prevention

When it happens

Trigger: update_order called with an Order whose direction is not Order.BUY/Order.SELL: direction left as 0/None by a constructor default, or a custom Order subclass with an extra direction enum passed to the standard Position.

Common situations: Constructing Order objects manually with direction=0; deserializing orders from dicts where direction lost its value; subclassing OrderDir with a 'hold' direction but reusing Position as the position handler.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/6f04e8761c7d49da. Report an issue: GitHub.