def on_filled_order

The lifecycle callback method is called after LumiBot observes that an order has been fully filled by the broker. Use it as the fast path for fill-dependent work.

The callback already supplies the filled order. A required hedge should not wait for another broker-backed self.get_order(order.identifier) call. Route the callback order directly to an idempotent hedge helper keyed by the entry order identifier. The same helper may be called by cancel-exception or restart/reconciliation paths without submitting a duplicate hedge.

If hedge sizing depends on partial fills, use on_partially_filled_order to process only the newly filled quantity and share the same cumulative idempotency state with this full-fill callback.

Parameters:

position (Position): The updated position object related to the order symbol. If the strategy already holds 200 shares of SPY and 300 has just been filled, then position.quantity will be 500 shares otherwise if it is a new position, a new position object will be created and passed to this method. order (Order): The corresponding order object that has been filled price (float): The filled price quantity (int): The filled quantity multiplier (int): Options multiplier

quantity is the fill quantity applied by this callback. If no partial-fill callback preceded it, that is normally the full order quantity. If partial callbacks already applied quantity, this callback carries the remaining delta. It is not a new cumulative total. Live reconnect/reconciliation paths can repeat observations, so external side effects such as hedges must be idempotent.

class MyStrategy(Strategy):
    def on_filled_order(self, position, order, price, quantity, multiplier):
        if order.identifier in self.processed_entry_order_ids:
            return
        self.processed_entry_order_ids.add(order.identifier)

        if order.side == "sell":
            self.log_message(f"{quantity} shares of {order.symbol} has been sold at {price}$")
        elif order.side == "buy":
            self.log_message(f"{quantity} shares of {order.symbol} has been bought at {price}$")

        self.log_message(f"Currently holding {position.quantity} of {position.symbol}")

Reference

lumibot.strategies.strategy.Strategy.on_filled_order(self, position: Position, order: Order, price: float, quantity: float | int, multiplier: float)

Use this lifecycle event to execute code when an order has been filled by the broker.

Parameters:
  • position (Position object) – The position that is being filled.

  • order (Order object) – The order that is being filled.

  • price (float) – The price of the fill.

  • quantity (float or int) – The quantity of the fill.

  • multiplier (float) – The multiplier of the fill.

Return type:

None

Example

>>> def on_filled_order(self, position, order, price, quantity, multiplier):
>>>     if order.asset == "AAPL":
>>>         self.log_message("Order for AAPL filled")
>>>         self.log_message(f"Price: {price}")
>>> # Update dictionary with new position
>>> def on_filled_order(self, position, order, price, quantity, multiplier):
>>>     if order.asset == "AAPL":
>>>         self.log_message("Order for AAPL filled")
>>>         self.log_message(f"Price: {price}")
>>>         self.positions["AAPL"] = position