How Emulated Orders Trigger, Release, and Re-enter Risk Checks
Summary
This guide explains how a local order emulator provides stop, touched, trailing, and limit order behavior when a venue does not support those order types. Traders select quotes or trades as the trigger data; when the condition is met, the emulator converts the order to a market or limit order and sends it through the usual risk and execution path. The guide lists which order types can be emulated and what each becomes on release.
It also describes the order lifecycle, cache queries, modifications and cancellations, and restoration of emulated orders after startup. Initial and release-time risk checks can both deny an order. Practical caveats include unsupported trigger types causing cancellation, market orders changing GTD time in force to GTC, and trailing stop limits potentially remaining held until the needed price calculation succeeds. The material documents system behavior rather than providing performance evidence or advice on when to use these orders.
Key ideas
- Emulation monitors selected quote or trade data and releases an order when its trigger condition is met.
- The emulator transforms supported orders into market or limit orders, which pass through risk checks again.
- Strategies can modify or cancel held orders, and cancel-all requests include them.
- Use cache queries because the order object transforms on release.
- A trailing stop limit may remain held if its limit price cannot yet be calculated.
Tags
Full text
# Emulated orders # Emulated orders Emulation lets you use order types even when your trading venue does not natively support them. The `OrderEmulator` monitors the market data selected by `emulation_trigger`. When the local order matches its release condition, the emulator transforms it into a `MARKET` or `LIMIT` order and sends that order through the normal risk and execution path. For example, an emulated `STOP_LIMIT` becomes a `LIMIT` order after its stop price triggers. ## Submitting an order for emulation Set `emulation_trigger` on an order constructor or `OrderFactory` method. The local emulator accepts these values: | Trigger type | Market data used | | ------------ | -------------------------------------------------- | | `DEFAULT` | Quotes, with the same local behavior as `BID_ASK`. | | `BID_ASK` | Best bid and ask quotes. | | `LAST_PRICE` | Trades. | Leave `emulation_trigger` as `None` to disable local emulation and submit through the normal pathway. Other `TriggerType` values describe trigger methods that some venues support, but the local `OrderEmulator` does not accept them as `emulation_trigger` values. :::warning The emulator cancels an order submitted with any other `emulation_trigger` value, and logs the unsupported trigger type as an error. ::: The choice of trigger type determines how emulation behaves: - For stop orders, the emulator compares the trigger price with the selected market data. - For trailing-stop orders, it updates the trailing trigger from that market data. - For emulated `LIMIT` orders, it compares the limit price with that market data and releases a `MARKET` order when matched. ## Technical details The same `OrderEmulator` component manages supported emulated order types in all [environment contexts](../architecture.md#environment-contexts). :::note NautilusTrader does not configure a fixed count limit for emulated orders. Available memory and the cost of market data processing provide practical limits. ::: ## Lifecycle An emulated order progresses through these stages: 1. A `Strategy` submits it through `submit_order`. 1. The `RiskEngine` applies pre-trade checks and may deny it. 1. The `OrderEmulator` holds and monitors it locally. 1. A matching market update transforms it into a `MARKET` or `LIMIT` order and releases it once the required prices are available. 1. The `RiskEngine` checks the released order again before venue submission. :::note Emulated orders pass through the normal risk controls. A strategy can modify or cancel them, and a cancel-all request includes them. ::: :::info An emulated order retains its client order ID when transformed, so cache queries continue to use the same ID. ::: ### Held emulated orders While the `OrderEmulator` holds an order: - It caches the original `SubmitOrder` command. - It processes the order in a local matching core. - It subscribes to the required quotes or trades if no matching subscription exists. - It accepts strategy modifications and market-driven updates until release or cancellation. ### Released emulated orders When market data matches an emulated order, release performs these actions: - It transforms the order into a `MARKET` or `LIMIT` order through another `OrderInitialized` event. - It sets the order's `emulation_trigger` to `None` so components no longer treat it as emulated. - It sends the transformed order and original `SubmitOrder` command back through the `RiskEngine`. - If the risk engine does not deny it, the `ExecutionEngine` routes it to an `ExecutionClient`. ## Order types that can be emulated The released type depends on the original emulated order type: | Order type for emulation | Can emulate | Released type | | ------------------------ | ----------- | ------------- | | `MARKET` | - | N/A | | `MARKET_TO_LIMIT` | - | N/A | | `LIMIT` | ✓ | `MARKET` | | `STOP_MARKET` | ✓ | `MARKET` | | `STOP_LIMIT` | ✓ | `LIMIT` | | `MARKET_IF_TOUCHED` | ✓ | `MARKET` | | `LIMIT_IF_TOUCHED` | ✓ | `LIMIT` | | `TRAILING_STOP_MARKET` | ✓ | `MARKET` | | `TRAILING_STOP_LIMIT` | ✓ | `LIMIT` | A `MARKET` release keeps the original time in force, except that `GTD` becomes `GTC` because market orders do not support `GTD`. :::warning An emulated `TRAILING_STOP_LIMIT` submitted without a limit price gets one from the trailing calculation. If the order triggers before that calculation succeeds, the emulator logs a warning and keeps the order emulated. Once a market update lets the calculation produce a limit price, the next matching update releases the order. For example, the `LAST_OR_BID_ASK` trigger type needs a last trade price. A `BID_ASK` emulation trigger subscribes the emulator to quotes only, so the order stays held until trade data reaches the cache, such as from a strategy's trade subscription. ::: ## Querying Use the cache or the order object to query emulation status. ### Through the cache The `Cache` provides these methods: - `self.cache.orders_emulated(...)` returns all emulated orders that match its filters. - `self.cache.is_order_emulated(...)` checks one client order ID. - `self.cache.orders_emulated_count(...)` returns the number of matching emulated orders. See the full [API reference](/docs/python-api-latest/cache.html) for additional details. ### Direct order queries Use `order.is_emulated` to query an order object directly. A `False` value means the order was released or was never emulated. :::warning Do not hold a local reference to an emulated order. The order object transforms when the emulated order is *released*. Use the `Cache` instead. ::: ## Persistence and recovery On startup, the `OrderEmulator` reactivates emulated orders that the configured cache database restored into the cache. This preserves their state across restarts. ## Best practices When working with emulated orders: 1. Query the `Cache` instead of storing local order references. 1. Account for the order type changing on release. 1. Handle a denial at either the initial or release-time risk check. ## Related guides - [Orders](index.md) - Order concepts, execution instructions, and the order factory. - [Advanced orders](advanced.md) - Order lists, contingency types, and bracket orders. - [Strategies](../strategies.md) - Order management from strategies.
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.