Exclusive 22% OFF All Quantra by QuantInsti Courses for IBridgePy Users Master algorithmic trading from beginner to advanced — Python for trading, machine learning strategies, options trading, and more.
HUI22 Use HUI22 for 22% off
HUI7 Stack HUI7 for an additional 7% off
Browse Courses →
← Back to Blog

How to Get Fill Price After Order Execution in IBridgePy

June 15, 2026 · Tutorials

The Common Mistake: Polling get_open_orders() for Filled Orders

One of the most frequently asked questions by IBridgePy users is: "Why can't I find my filled order when polling get_open_orders()?" Many traders write a loop like this after placing a market order:

# This will NEVER work for filled orders
for i in range(10):
    orders = get_open_orders()
    # check for filled status...
    time.sleep(1)

This approach always times out because get_open_orders() is designed to return only pending orders. The moment an order transitions to "Filled" status, it is excluded from the result set. No amount of waiting or polling frequency adjustment will change this behavior.

Understanding IBridgePy's Order Lifecycle

get_open_orders() filters orders to only those with status: APIPENDING, PENDINGSUBMIT, PENDINGCANCEL, PRESUBMITTED, or SUBMITTED. Once Interactive Brokers confirms a fill, the order status changes to "Filled" and it disappears from this function's output.

The internal order dictionary, however, retains all orders for the entire session regardless of status. This is where get_order() comes in.

The Correct Approach: order_status_monitor + get_order

IBridgePy provides a built-in function specifically designed for waiting on order status changes. Here is the correct pattern for retrieving the fill price:

def handle_data(context, data):
    # Place a market order
    ibpyOrderId = order(symbol('AAPL'), 100)

    # Wait for fill confirmation (pumps IB messages internally)
    order_status_monitor(ibpyOrderId, 'Filled', waitingTimeInSeconds=30)

    # Retrieve the fill price
    filled_order = get_order(ibpyOrderId)
    fill_price = filled_order.avgFillPrice
    shares_filled = filled_order.filled

    print(f'Filled {shares_filled} shares at ${fill_price}')

Why order_status_monitor Works and time.sleep Does Not

The critical difference is that order_status_monitor() calls processMessagesWrapper() internally on every iteration (every 0.1 seconds). This function pumps incoming callbacks from the IB server, including the orderStatus callback that carries the fill price.

A bare time.sleep() loop does not pump messages. The IB server may have sent the fill confirmation, but your script never processes it because the message queue is not being read during the sleep.

Available Properties on the Order Object

After calling get_order(ibpyOrderId), you have access to these properties:

PropertyDescription
.statusCurrent order status (e.g., 'Filled')
.avgFillPriceVolume-weighted average fill price
.lastFillPricePrice of the most recent partial fill
.filledNumber of shares/contracts filled

Practical Example: Place Order and Set Stop Loss at Fill Price

def handle_data(context, data):
    contract = symbol('AAPL')
    quantity = 100

    # Enter position
    entry_order_id = order(contract, quantity)
    order_status_monitor(entry_order_id, 'Filled', waitingTimeInSeconds=30)

    # Get actual fill price
    fill_price = get_order(entry_order_id).avgFillPrice

    # Place stop loss 2% below fill price
    stop_price = round(fill_price * 0.98, 2)
    order(contract, -quantity, style=StopOrder(stop_price))
    print(f'Entry at {fill_price}, stop at {stop_price}')

Summary

To reliably retrieve fill prices in IBridgePy:

  1. Never poll get_open_orders() for filled orders — they are excluded by design.
  2. Use order_status_monitor(ibpyOrderId, 'Filled') to wait for the fill.
  3. Use get_order(ibpyOrderId).avgFillPrice to retrieve the actual price.

This pattern works for all asset classes: stocks, options, futures, and forex. For more details, see the IBridgePy documentation.