Skip to content
All library documents

Order Expiry Events and Post-Expiry Fills in Trading Systems

Article NautilusTrader

Summary

This technical reference explains how an order-expiry event is processed in an execution pipeline. The event is applied to the order, updates the cache, and is published on the message bus. It may originate from a venue, a simulated matching engine, or reconciliation, such as when a good-till-date order reaches its expiry. The typical state change is from accepted to expired, and a corresponding event handler receives it.

Expiry does not prevent later fills from being processed: those fills continue to update order and position records. A partial fill leaves the order expired, while a fill that completes the quantity changes its state to filled. The reference also describes repeated expiry events after a later fill and restrictions on further expiry events. It lists optional venue and account identifiers and a required reconciliation flag. This is systems documentation for interpreting order lifecycle events; it does not propose a trading strategy or discuss market performance.

Key ideas

  • An expiry event is recorded, applied to the order, and published through the message bus.
  • An accepted order typically transitions to expired when an expiry event is handled.
  • Fills arriving after expiry still update the order and position.
  • A partial post-expiry fill leaves the order expired, while a complete fill changes it to filled.
  • The event can include venue and account identifiers and indicates whether reconciliation generated it.

Tags

Full text
# OrderExpired


# OrderExpired

`OrderExpired` records that an order has expired. The execution pipeline applies it to the order,
updates the `Cache`, and publishes it on the `MessageBus`. It can come from a trading venue,
simulated matching engine, or reconciliation, for example when a GTD order reaches its expiry.

Typical transition: `ACCEPTED` -> `EXPIRED`. Handler: `on_order_expired`.

Fills received after expiry still update the order and position. A partial fill keeps the order
`EXPIRED`; a fill that completes its quantity changes it to `FILLED`. If a fill arrives after the
most recent expiry and the order is still `EXPIRED` or `FILLED`, the next `OrderExpired` is recorded
and published without changing the order's status or timestamps. Further expiry events are rejected
until another fill arrives.

## Fields

Beyond the [common Python order event fields](index.md#common-python-order-event-fields),
`OrderExpired` carries:

| Field            | Python type              | Required/default | Description                                      |
| ---------------- | ------------------------ | ---------------- | ------------------------------------------------ |
| `venue_order_id` | `VenueOrderId` or `None` | `None`           | The venue-assigned order identifier, if known.   |
| `account_id`     | `AccountId` or `None`    | `None`           | The account associated with the order, if known. |
| `reconciliation` | `bool`                   | Required         | If generated during reconciliation.              |

## Example

Reading the event in a strategy handler:

```python
def on_order_expired(self, event: OrderExpired) -> None:
    self.log.info(f"Order {event.client_order_id} expired")
```

## Related guides

- [Events](index.md) - Event categories, dispatch, and the common order event fields.
- [Orders](../orders/) - Order types and the state machine.

Shown in full with attribution under the source's licence. Licence: LGPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.