docs/developer_guide/spec_exec_testing.md
This section defines a rigorous test matrix for validating adapter execution
functionality using the ExecTester strategy. Both Python
(nautilus_trader.test_kit.strategies.tester_exec) and Rust
(nautilus_testkit::testers) provide the ExecTester. Each test case is
identified by a prefixed ID (e.g. TC-E01) and grouped by functionality.
Each adapter must pass the subset of tests matching its supported capabilities.
Tests progress from simple (single market order) to complex (brackets, modification chains, rejection handling). An adapter that passes groups 1–5 is considered baseline compliant. Data connectivity should be verified first using the Data Testing Spec.
Document adapter-specific behavior (how a venue simulates market orders, handles TIF options, etc.) in the adapter's own guide, not here. Each adapter guide should include a capability matrix showing which order types, time-in-force options, actions, and flags it supports.
Before running execution tests:
{VENUE}_API_KEY, {VENUE}_API_SECRET (or sandbox variants).is_demo=True), use credentials created
for that environment. Demo and production API keys are typically separate and not
interchangeable; using the wrong credentials produces authentication errors (e.g. HTTP 401).LiveRiskEngineConfig(bypass=True)) to avoid interference.Python node setup:
Legacy examples still use nautilus_trader.live.node.TradingNode, but new Rust-backed
PyO3 adapters should prefer nautilus_trader.live.LiveNode. Use LiveNode.builder(...)
when you need to register adapter client factories before the node is built.
from nautilus_trader.common import Environment
from nautilus_trader.live import LiveExecEngineConfig, LiveNode, LiveRiskEngineConfig
from nautilus_trader.model import TraderId
node = (
LiveNode.builder("TESTER-001", TraderId("TESTER-001"), Environment.SANDBOX)
.with_risk_engine_config(LiveRiskEngineConfig(bypass=True))
.with_exec_engine_config(LiveExecEngineConfig(reconciliation=True))
.add_exec_client(None, adapter_exec_client_factory, exec_client_config)
.build()
)
node.add_strategy_from_config(importable_strategy_config)
# Register remaining components, then start or run
Rust node setup (reference: crates/adapters/{adapter}/examples/node_exec_tester.rs):
use nautilus_testkit::testers::{ExecTester, ExecTesterConfig};
let tester_config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, order_qty);
let tester = ExecTester::new(tester_config);
node.add_strategy(tester)?;
node.run().await?;
A quick sanity check that can run at any time, for example after adapter changes or between development iterations. The tester opens a position with a market order on start, places a buy and sell post-only limit order, waits 30 seconds, then stops (cancelling open orders and closing the position).
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.001"),
open_position_on_start_qty=Decimal("0.001"),
enable_limit_buys=True,
enable_limit_sells=True,
use_post_only=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, dec!(0.001))
.with_open_position_on_start_qty(Some(dec!(0.001)))
.with_enable_limit_buys(true)
.with_enable_limit_sells(true)
.with_use_post_only(true)
Expected behavior:
tob_offset_ticks away from best bid/ask (default 500 ticks).Pass criteria: No errors in logs, position opened and closed cleanly, limit orders acknowledged by the venue.
Each group below begins with a summary table, followed by detailed test cards. Test IDs use spaced numbering to allow insertion without renumbering.
Test market order submission and fills. Market orders should execute immediately.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E01 | Market BUY - submit and fill | Open long position via market buy. | No market orders. |
| TC-E02 | Market SELL - submit and fill | Open short position via market sell. | No market orders. |
| TC-E03 | Market order with IOC TIF | Market order explicitly using IOC time in force. | No IOC. |
| TC-E04 | Market order with FOK TIF | Market order explicitly using FOK time in force. | No FOK. |
| TC-E05 | Market order with quote qty | Market order using quote currency quantity. | No quote quantity. |
| TC-E06 | Close position via market | Close an open position with a market order on stop. | No market orders. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, market data flowing, no open position. |
| Action | ExecTester opens a long position via open_position_on_start_qty. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Position opened with side=LONG, quantity matches config, fill price within market range, AccountState updated. |
| Skip when | Adapter does not support market orders. |
Considerations:
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, market data flowing, no open position. |
| Action | ExecTester opens a short position via negative open_position_on_start_qty. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Position opened with side=SHORT, quantity matches config, fill price within market range. |
| Skip when | Adapter does not support market orders or short selling. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("-0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(-1, 2)))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, market data flowing. |
| Action | Open position with open_position_time_in_force=IOC. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Same as TC-E01; the IOC TIF is explicitly set on the order. |
| Skip when | No IOC support. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
open_position_time_in_force=TimeInForce.IOC,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false);
config.open_position_time_in_force = TimeInForce::Ioc;
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, market data flowing. |
| Action | Open position with open_position_time_in_force=FOK. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Same as TC-E01; the FOK TIF is explicitly set on the order. |
| Skip when | No FOK support. |
Considerations:
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
open_position_time_in_force=TimeInForce.FOK,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false);
config.open_position_time_in_force = TimeInForce::Fok;
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, adapter supports quote quantity. |
| Action | Open position with use_quote_quantity=True, quantity in quote currency. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Order submitted with quote currency quantity; fill quantity is in base currency. |
| Skip when | Adapter does not support quote quantity orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("100.0"), # Quote currency amount
open_position_on_start_qty=Decimal("100.0"),
use_quote_quantity=True,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("100"))
.with_open_position_on_start(Some(Decimal::from(100)))
.with_use_quote_quantity(true)
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Open position from TC-E01 or TC-E02. |
| Action | Stop the strategy; ExecTester closes position via market order. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled (closing order). |
| Pass criteria | Position closed (net quantity = 0), no open orders remaining. |
| Skip when | Adapter does not support market orders. |
Considerations:
close_positions_on_stop=True is the default.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
close_positions_on_stop=True,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_close_positions_on_stop(true)
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
Test limit order submission, acceptance, and behavior across time-in-force options.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E10 | Limit BUY GTC | Place GTC limit buy below TOB, verify accepted. | Never. |
| TC-E11 | Limit SELL GTC | Place GTC limit sell above TOB, verify accepted. | Never. |
| TC-E12 | Limit BUY and SELL pair | Both sides simultaneously, verify both accepted. | Never. |
| TC-E13 | Limit IOC aggressive fill | Limit IOC at aggressive price, expect fill. | No IOC. |
| TC-E14 | Limit IOC passive no fill | Limit IOC away from market, expect cancel. | No IOC. |
| TC-E15 | Limit FOK fill | Limit FOK at aggressive price, expect fill. | No FOK. |
| TC-E16 | Limit FOK no fill | Limit FOK away from market, expect cancel. | No FOK. |
| TC-E17 | Limit GTD | Limit with expiry time, verify accepted. | No GTD. |
| TC-E18 | Limit GTD expiry | Wait for GTD expiry, verify OrderExpired. | No GTD. |
| TC-E19 | Limit DAY | Limit with DAY TIF, verify accepted. | No DAY. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a limit buy at best_bid - tob_offset_ticks. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order is open on the venue with correct price, quantity, side=BUY, TIF=GTC. |
| Skip when | Never. |
Considerations:
tob_offset_ticks (default 500) places the order well away from the market to avoid accidental fills.OrderStatus.ACCEPTED.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a limit sell at best_ask + tob_offset_ticks. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order is open on the venue with correct price, quantity, side=SELL, TIF=GTC. |
| Skip when | Never. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(true)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places both a limit buy and limit sell. |
| Event sequence | Two independent sequences: each OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Both orders open on venue, buy below bid, sell above ask. |
| Skip when | Never. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(true)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Submit a limit buy IOC at or above the best ask (aggressive price). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Order fills immediately; position opened. |
| Skip when | Adapter does not support IOC TIF. |
Considerations:
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Submit a limit buy IOC well below the market (passive price). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderCanceled. |
| Pass criteria | Order is immediately canceled by venue with no fill. |
| Skip when | Adapter does not support IOC TIF. |
Considerations:
OrderCanceled event (not OrderExpired).| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing, sufficient book depth. |
| Action | Submit a limit buy FOK at aggressive price with quantity within top‑of‑book depth. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Order fills completely in a single fill event. |
| Skip when | Adapter does not support FOK TIF. |
Considerations:
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Submit a limit buy FOK at passive price (well below market). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderCanceled. |
| Pass criteria | Order is immediately canceled by venue with no fill. |
| Skip when | Adapter does not support FOK TIF. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Place limit buy with order_expire_time_delta_mins set (e.g., 60 minutes). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted with GTD TIF and correct expiry timestamp. |
| Skip when | Adapter does not support GTD TIF. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
order_expire_time_delta_mins=60,
enable_limit_buys=True,
enable_limit_sells=False,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false);
config.order_expire_time_delta_mins = Some(60);
| Field | Value |
|---|---|
| Prerequisite | Open GTD limit order from TC-E17 (or use a very short expiry). |
| Action | Wait for the GTD expiry time to elapse. |
| Event sequence | OrderExpired. |
| Pass criteria | Order transitions to expired status; OrderExpired event received. |
| Skip when | Adapter does not support GTD TIF. |
Considerations:
order_expire_time_delta_mins (e.g., 1–2 minutes) to avoid long waits.OrderExpired.| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, market is in trading hours. |
| Action | Submit limit buy with DAY TIF. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted with DAY TIF; will be automatically canceled at end of trading day. |
| Skip when | Adapter does not support DAY TIF. |
Considerations:
Test stop and conditional order types. These orders rest on the venue until a trigger condition is met.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E20 | StopMarket BUY | Stop buy above ask, verify accepted. | No STOP_MARKET. |
| TC-E21 | StopMarket SELL | Stop sell below bid, verify accepted. | No STOP_MARKET. |
| TC-E22 | StopLimit BUY | Stop‑limit buy with trigger + limit price. | No STOP_LIMIT. |
| TC-E23 | StopLimit SELL | Stop‑limit sell with trigger + limit price. | No STOP_LIMIT. |
| TC-E24 | MarketIfTouched BUY | MIT buy below bid. | No MIT. |
| TC-E25 | MarketIfTouched SELL | MIT sell above ask. | No MIT. |
| TC-E26 | LimitIfTouched BUY | LIT buy with trigger + limit price. | No LIT. |
| TC-E27 | LimitIfTouched SELL | LIT sell with trigger + limit price. | No LIT. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a stop‑market buy above the current ask. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Stop order accepted on venue with correct trigger price and side=BUY. |
| Skip when | Adapter does not support StopMarket orders. |
Considerations:
stop_offset_ticks.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
enable_stop_buys=True,
enable_stop_sells=False,
stop_order_type=OrderType.STOP_MARKET,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
.with_enable_stop_buys(true)
.with_enable_stop_sells(false)
.with_stop_order_type(OrderType::StopMarket)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a stop‑market sell below the current bid. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Stop order accepted on venue with correct trigger price and side=SELL. |
| Skip when | Adapter does not support StopMarket orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
enable_stop_buys=False,
enable_stop_sells=True,
stop_order_type=OrderType.STOP_MARKET,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
.with_enable_stop_buys(false)
.with_enable_stop_sells(true)
.with_stop_order_type(OrderType::StopMarket)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a stop‑limit buy with trigger price above ask and limit offset. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Stop‑limit order accepted with correct trigger price, limit price, and side=BUY. |
| Skip when | Adapter does not support StopLimit orders. |
Considerations:
stop_limit_offset_ticks to be set for the limit price offset from the trigger price.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
enable_stop_buys=True,
enable_stop_sells=False,
stop_order_type=OrderType.STOP_LIMIT,
stop_limit_offset_ticks=50,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
.with_enable_stop_buys(true)
.with_enable_stop_sells(false)
.with_stop_order_type(OrderType::StopLimit);
config.stop_limit_offset_ticks = Some(50);
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places a stop‑limit sell with trigger price below bid. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Stop‑limit order accepted with correct trigger price, limit price, and side=SELL. |
| Skip when | Adapter does not support StopLimit orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=False,
enable_stop_buys=False,
enable_stop_sells=True,
stop_order_type=OrderType.STOP_LIMIT,
stop_limit_offset_ticks=50,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
.with_enable_stop_buys(false)
.with_enable_stop_sells(true)
.with_stop_order_type(OrderType::StopLimit);
config.stop_limit_offset_ticks = Some(50);
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Place MIT buy with trigger below current bid (buy on dip). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | MIT order accepted on venue with correct trigger price. |
| Skip when | Adapter does not support MarketIfTouched orders. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Place MIT sell with trigger above current ask (sell on rally). |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | MIT order accepted on venue with correct trigger price. |
| Skip when | Adapter does not support MarketIfTouched orders. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Place LIT buy with trigger below bid and limit price offset. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | LIT order accepted with correct trigger price and limit price. |
| Skip when | Adapter does not support LimitIfTouched orders. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | Place LIT sell with trigger above ask and limit price offset. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | LIT order accepted with correct trigger price and limit price. |
| Skip when | Adapter does not support LimitIfTouched orders. |
Test order modification (amend) and cancel-replace workflows.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E30 | Modify limit BUY price | Amend open limit buy to new price. | No modify support. |
| TC-E31 | Modify limit SELL price | Amend open limit sell to new price. | No modify support. |
| TC-E32 | Cancel‑replace limit BUY | Cancel and resubmit limit buy at new price. | Never. |
| TC-E33 | Cancel‑replace limit SELL | Cancel and resubmit limit sell at new price. | Never. |
| TC-E34 | Modify stop trigger price | Amend stop order trigger price. | No modify or no stop. |
| TC-E35 | Cancel‑replace stop order | Cancel and resubmit stop at new trigger price. | No stop orders. |
| TC-E36 | Modify rejected | Modify on unsupported adapter. | Adapter supports modify. |
| Field | Value |
|---|---|
| Prerequisite | Open GTC limit buy from TC-E10. |
| Action | ExecTester modifies limit buy to a new price as market moves (modify_orders_to_maintain_tob_offset=True). |
| Event sequence | OrderPendingUpdate → OrderUpdated. |
| Pass criteria | OrderUpdated event logged with the new price; order exits PendingUpdate. |
| Skip when | Adapter does not support order modification. |
Considerations:
OrderUpdated log shows the expected price. If the event never
arrives, the order stays in PendingUpdate and the tester stops modifying it.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
modify_orders_to_maintain_tob_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false);
config.modify_orders_to_maintain_tob_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open GTC limit sell from TC-E11. |
| Action | ExecTester modifies limit sell to new price as market moves. |
| Event sequence | OrderPendingUpdate → OrderUpdated. |
| Pass criteria | OrderUpdated event logged with the new price; order exits PendingUpdate. |
| Skip when | Adapter does not support order modification. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=True,
modify_orders_to_maintain_tob_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(true);
config.modify_orders_to_maintain_tob_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open GTC limit buy. |
| Action | ExecTester cancels and resubmits limit buy at new price as market moves. |
| Event sequence | OrderPendingCancel → OrderCanceled → OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Original order canceled, new order accepted at updated price. |
| Skip when | Never (cancel‑replace is always available). |
Considerations:
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
cancel_replace_orders_to_maintain_tob_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false);
config.cancel_replace_orders_to_maintain_tob_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open GTC limit sell. |
| Action | ExecTester cancels and resubmits limit sell at new price. |
| Event sequence | OrderPendingCancel → OrderCanceled → OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Original order canceled, new order accepted at updated price. |
| Skip when | Never. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=False,
enable_limit_sells=True,
cancel_replace_orders_to_maintain_tob_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(false)
.with_enable_limit_sells(true);
config.cancel_replace_orders_to_maintain_tob_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open stop order from TC-E20 or TC-E22. |
| Action | ExecTester modifies stop trigger price as market moves (modify_stop_orders_to_maintain_offset=True). |
| Event sequence | OrderPendingUpdate → OrderUpdated. |
| Pass criteria | OrderUpdated event logged with the new trigger price; order exits PendingUpdate. |
| Skip when | Adapter does not support modify, or no stop order support. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_stop_buys=True,
modify_stop_orders_to_maintain_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_stop_buys(true);
config.modify_stop_orders_to_maintain_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open stop order. |
| Action | ExecTester cancels and resubmits stop at new trigger price. |
| Event sequence | OrderPendingCancel → OrderCanceled → OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Original stop canceled, new stop accepted at updated trigger price. |
| Skip when | No stop order support. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_stop_buys=True,
cancel_replace_stop_orders_to_maintain_offset=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_stop_buys(true);
config.cancel_replace_stop_orders_to_maintain_offset = true;
| Field | Value |
|---|---|
| Prerequisite | Open limit order, adapter does NOT support modify. |
| Action | Attempt to modify the order (programmatically, not via ExecTester auto‑maintain). |
| Event sequence | OrderModifyRejected. |
| Pass criteria | Modify attempt results in OrderModifyRejected event with reason; original order remains unchanged. |
| Skip when | Adapter supports order modification. |
Considerations:
Test order cancellation workflows.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E40 | Cancel single limit order | Cancel an open limit order. | Never. |
| TC-E41 | Cancel all on stop | Strategy stop cancels all open orders (default). | Never. |
| TC-E42 | Individual cancels on stop | Cancel orders one‑by‑one on stop. | Never. |
| TC-E43 | Batch cancel on stop | Cancel orders via batch API on stop. | No batch cancel. |
| TC-E44 | Cancel already‑canceled | Cancel a non‑open order. | Never. |
| Field | Value |
|---|---|
| Prerequisite | Open GTC limit order from TC-E10 or TC-E11. |
| Action | Stop the strategy; ExecTester cancels the open limit order. |
| Event sequence | OrderPendingCancel → OrderCanceled. |
| Pass criteria | Order status transitions to CANCELED; no open orders remaining. |
| Skip when | Never. |
Considerations:
cancel_orders_on_stop=True (default) triggers cancellation when the strategy stops.OrderCanceled event contains the correct venue_order_id.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
cancel_orders_on_stop=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false)
.with_cancel_orders_on_stop(true)
| Field | Value |
|---|---|
| Prerequisite | Multiple open orders (limit buy + limit sell from TC-E12). |
| Action | Stop the strategy with cancel_orders_on_stop=True (default). |
| Event sequence | For each order: OrderPendingCancel → OrderCanceled. |
| Pass criteria | All open orders canceled; no open orders remaining. |
| Skip when | Never. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=True,
cancel_orders_on_stop=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(true)
.with_cancel_orders_on_stop(true)
| Field | Value |
|---|---|
| Prerequisite | Multiple open orders. |
| Action | Stop with use_individual_cancels_on_stop=True. |
| Event sequence | Individual OrderPendingCancel → OrderCanceled for each order. |
| Pass criteria | Each order canceled individually; all orders reach CANCELED status. |
| Skip when | Never. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=True,
use_individual_cancels_on_stop=True,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(true);
config.use_individual_cancels_on_stop = true;
| Field | Value |
|---|---|
| Prerequisite | Multiple open orders, adapter supports batch cancel. |
| Action | Stop with use_batch_cancel_on_stop=True. |
| Event sequence | Batch OrderPendingCancel → OrderCanceled for all orders. |
| Pass criteria | All orders canceled via single batch request; all reach CANCELED status. |
| Skip when | Adapter does not support batch cancel. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=True,
use_batch_cancel_on_stop=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(true)
.with_use_batch_cancel_on_stop(true)
| Field | Value |
|---|---|
| Prerequisite | A previously canceled order (from TC-E40). |
| Action | Attempt to cancel the same order again. |
| Event sequence | OrderCancelRejected. |
| Pass criteria | Cancel attempt is rejected; OrderCancelRejected event received with reason. |
| Skip when | Never. |
Considerations:
Test bracket order submission (entry + take-profit + stop-loss).
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E50 | Bracket BUY | Entry limit buy + TP limit sell + SL stop sell. | No bracket support. |
| TC-E51 | Bracket SELL | Entry limit sell + TP limit buy + SL stop buy. | No bracket support. |
| TC-E52 | Bracket entry fill activates | Verify TP/SL become active after entry fill. | No bracket support. |
| TC-E53 | Bracket with post‑only entry | Entry order uses post‑only flag. | No bracket or PO. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester submits a bracket order: limit buy entry + take‑profit sell + stop‑loss sell. |
| Event sequence | Entry: OrderInitialized → OrderSubmitted → OrderAccepted; TP and SL: OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Three orders created and accepted: entry below bid, TP above ask, SL below entry. |
| Skip when | Adapter does not support bracket orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_brackets=True,
bracket_entry_order_type=OrderType.LIMIT,
bracket_offset_ticks=500,
enable_limit_buys=True,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_brackets(true)
.with_bracket_entry_order_type(OrderType::Limit)
.with_bracket_offset_ticks(500)
.with_enable_limit_buys(true)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester submits bracket: limit sell entry + TP buy + SL buy. |
| Event sequence | Same pattern as TC-E50 but for sell side. |
| Pass criteria | Three orders created and accepted on sell side. |
| Skip when | Adapter does not support bracket orders. |
| Field | Value |
|---|---|
| Prerequisite | Bracket order from TC-E50 where entry order fills. |
| Action | Entry order fills; verify contingent TP and SL orders activate. |
| Event sequence | Entry: OrderFilled; TP and SL transition from contingent to active. |
| Pass criteria | After entry fill, TP and SL orders are live on the venue. |
| Skip when | Adapter does not support bracket orders. |
Considerations:
| Field | Value |
|---|---|
| Prerequisite | Adapter supports brackets and post‑only. |
| Action | Submit bracket with use_post_only=True (applied to entry and TP). |
| Event sequence | Same as TC-E50 with post‑only flag on entry. |
| Pass criteria | Entry and TP orders accepted as post‑only (maker); SL is not post‑only. |
| Skip when | No bracket support or no post‑only support. |
Test order-level flags and special parameters.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E60 | PostOnly accepted | Limit with post‑only, placed away from TOB. | No post‑only. |
| TC-E61 | ReduceOnly on close | Close position with reduce‑only flag. | No reduce‑only. |
| TC-E62 | Display quantity | Iceberg order with visible quantity < total. | No display quantity. |
| TC-E63 | Custom order params | Adapter‑specific params via order_params. | N/A. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places limit buy with use_post_only=True at passive price. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted as a maker order; post‑only flag acknowledged by venue. |
| Skip when | Adapter does not support post‑only flag. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
use_post_only=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false)
.with_use_post_only(true)
| Field | Value |
|---|---|
| Prerequisite | Open position (from TC-E01). |
| Action | Stop strategy with reduce_only_on_stop=True; closing order uses reduce‑only flag. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled (with reduce‑only). |
| Pass criteria | Closing order has reduce‑only flag; position fully closed. |
| Skip when | Adapter does not support reduce‑only flag. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
reduce_only_on_stop=True,
close_positions_on_stop=True,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_reduce_only_on_stop(true)
.with_close_positions_on_stop(true)
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, adapter supports display quantity. |
| Action | Place limit order with order_display_qty < order_qty. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted with display quantity set; only display qty visible on the book. |
| Skip when | Adapter does not support display quantity / iceberg orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("1.0"),
order_display_qty=Decimal("0.1"),
enable_limit_buys=True,
enable_limit_sells=False,
)
Rust config:
let mut config = ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("1.0"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false);
config.order_display_qty = Some(Quantity::from("0.1"));
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, adapter accepts additional parameters. |
| Action | Place order with order_params dict containing adapter‑specific parameters. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted; adapter‑specific parameters passed through to venue. |
| Skip when | N/A (adapter‑specific). |
Considerations:
order_params dict is opaque to the ExecTester and passed through to the adapter.Test that the adapter correctly handles and reports order rejections.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E70 | PostOnly rejection | Post‑only order that would cross the spread. | No post‑only. |
| TC-E71 | ReduceOnly rejection | Reduce‑only order with no position to reduce. | No reduce‑only. |
| TC-E72 | Unsupported order type | Submit order type not supported by adapter. | Never. |
| TC-E73 | Unsupported TIF | Submit order with unsupported time in force. | Never. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, quotes flowing. |
| Action | ExecTester places post‑only order on the wrong side of the book (test_reject_post_only=True), causing it to cross the spread. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderRejected. |
| Pass criteria | Order rejected by venue; OrderRejected event received with reason indicating post‑only violation. |
| Skip when | Adapter does not support post‑only flag. |
Considerations:
test_reject_post_only mode intentionally prices the order to cross.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
enable_limit_buys=True,
enable_limit_sells=False,
use_post_only=True,
test_reject_post_only=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_enable_limit_buys(true)
.with_enable_limit_sells(false)
.with_use_post_only(true)
.with_test_reject_post_only(true)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, no open position for the instrument. |
| Action | ExecTester opens a market position with reduce_only=True via test_reject_reduce_only=True and open_position_on_start_qty, when no position exists to reduce. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderRejected. |
| Pass criteria | Order rejected; OrderRejected event with reason indicating reduce‑only violation. |
| Skip when | Adapter does not support reduce‑only flag. |
Considerations:
test_reject_reduce_only flag only applies to the opening market order submitted via
open_position_on_start_qty.Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
test_reject_reduce_only=True,
enable_limit_buys=False,
enable_limit_sells=False,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
.with_test_reject_reduce_only(true)
.with_enable_limit_buys(false)
.with_enable_limit_sells(false)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, order type not in adapter's supported set. |
| Action | Submit an order type the adapter does not support. |
| Event sequence | OrderDenied (pre‑submission rejection by adapter). |
| Pass criteria | Order denied before reaching venue; OrderDenied event with reason. |
| Skip when | Never (every adapter has unsupported order types to test). |
Considerations:
OrderDenied occurs at the adapter level before the order reaches the venue.OrderRejected which comes from the venue.| Field | Value |
|---|---|
| Prerequisite | Adapter connected, TIF not in adapter's supported set. |
| Action | Submit an order with a TIF the adapter does not support. |
| Event sequence | OrderDenied (pre‑submission rejection by adapter). |
| Pass criteria | Order denied before reaching venue; OrderDenied event with reason. |
| Skip when | Never (every adapter has unsupported TIF options to test). |
Considerations:
Test strategy lifecycle behavior and state management on start and stop.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E80 | Open position on start | Open a position immediately when strategy starts. | No market orders. |
| TC-E81 | Cancel orders on stop | Cancel all open orders when strategy stops. | Never. |
| TC-E82 | Close positions on stop | Close open positions when strategy stops. | No market orders. |
| TC-E83 | Unsubscribe on stop | Unsubscribe from data feeds on strategy stop. | No unsub support. |
| TC-E84 | Reconcile open orders | Reconcile existing open orders from a prior session. | Never. |
| TC-E85 | Reconcile filled orders | Reconcile previously filled orders from a prior session. | Never. |
| TC-E86 | Reconcile open long | Reconcile existing open long position. | Never. |
| TC-E87 | Reconcile open short | Reconcile existing open short position. | Never. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, instrument loaded, no existing position. |
| Action | Strategy starts with open_position_on_start_qty set. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | Position opened on start; market order submitted and filled before limit order maintenance begins. |
| Skip when | Adapter does not support market orders. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
open_position_on_start_qty=Decimal("0.01"),
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_open_position_on_start(Some(Decimal::new(1, 2)))
| Field | Value |
|---|---|
| Prerequisite | Open limit orders from the strategy session. |
| Action | Stop the strategy with cancel_orders_on_stop=True (default). |
| Event sequence | For each open order: OrderPendingCancel → OrderCanceled. |
| Pass criteria | All strategy‑owned open orders canceled on stop. |
| Skip when | Never. |
| Field | Value |
|---|---|
| Prerequisite | Open position from the strategy session. |
| Action | Stop the strategy with close_positions_on_stop=True (default). |
| Event sequence | Closing order: OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled. |
| Pass criteria | All strategy‑owned positions closed; net position = 0. |
| Skip when | Adapter does not support market orders. |
| Field | Value |
|---|---|
| Prerequisite | Active data subscriptions (quotes, trades, book). |
| Action | Stop the strategy with can_unsubscribe=True (default). |
| Event sequence | Data subscriptions removed. |
| Pass criteria | No further data events received after stop; clean disconnection. |
| Skip when | Adapter does not support unsubscribe. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id,
order_qty=Decimal("0.01"),
can_unsubscribe=True,
)
Rust config:
ExecTesterConfig::new(strategy_id, instrument_id, client_id, Quantity::from("0.01"))
.with_can_unsubscribe(true)
| Field | Value |
|---|---|
| Prerequisite | One or more open limit orders on the venue from a prior session. |
| Action | Start the node with reconciliation=True. |
| Event sequence | OrderStatusReport generated for each open order. |
| Pass criteria | Each open order is loaded into the cache with correct venue_order_id, status=ACCEPTED, price, quantity, side, and order type. |
| Skip when | Never. |
Considerations:
external_order_claims to claim the instrument so the adapter reconciles orders for it.| Field | Value |
|---|---|
| Prerequisite | One or more filled orders on the venue from a prior session. |
| Action | Start the node with reconciliation=True. |
| Event sequence | FillReport generated for each historical fill. |
| Pass criteria | Each filled order is loaded into the cache with correct venue_order_id, status=FILLED, fill price, fill quantity, and commission. |
| Skip when | Never. |
Considerations:
| Field | Value |
|---|---|
| Prerequisite | An open long position on the venue from a prior session. |
| Action | Start the node with reconciliation=True. |
| Event sequence | PositionStatusReport generated for the long position. |
| Pass criteria | Position loaded into cache with correct instrument, side=LONG, quantity, and entry price matching the venue. |
| Skip when | Never. |
Considerations:
close_positions_on_stop=False).| Field | Value |
|---|---|
| Prerequisite | An open short position on the venue from a prior session. |
| Action | Start the node with reconciliation=True. |
| Event sequence | PositionStatusReport generated for the short position. |
| Pass criteria | Position loaded into cache with correct instrument, side=SHORT, quantity, and entry price matching the venue. |
| Skip when | Never. |
Considerations:
close_positions_on_stop=False).Test options-specific execution behavior. Options instruments typically have different constraints from linear derivatives: venues may restrict order types, support alternative pricing modes, or disallow conditional orders. Exact restrictions vary by venue; consult the adapter guide.
These tests require a CryptoOption instrument. Use an OTM option with
reasonable liquidity for fills.
| TC | Name | Description | Skip when |
|---|---|---|---|
| TC-E90 | Limit BUY option | Place a limit buy on an option instrument. | No options support. |
| TC-E91 | Limit SELL option | Place a limit sell on an option instrument. | No options support. |
| TC-E92 | Limit with alt pricing | Place a limit order with adapter‑specific pricing via order_params. | No alt pricing. |
| TC-E94 | Unsupported order type denied | Submit an order type the adapter rejects for options. | No options support. |
| TC-E96 | Conditional order rejected | Submit a stop/conditional order on an option; expect rejection. | No options support. |
| TC-E99 | FOK limit option | Place a FOK limit order on an option instrument. | No FOK options. |
| TC-E100 | Cancel option order | Cancel an open limit order on an option instrument. | No options support. |
| TC-E101 | Reconcile option position | Reconcile an open option position from a prior session. | No options support. |
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded, quotes flowing. |
| Action | ExecTester places a limit buy on the option at a passive price. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted by venue with correct instrument, side, price, and quantity. |
| Skip when | Adapter does not support options trading. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id, # CryptoOption instrument
order_qty=Decimal("1"),
enable_limit_buys=True,
enable_limit_sells=False,
tob_offset_ticks=500,
)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded, quotes flowing. |
| Action | ExecTester places a limit sell on the option at a passive price. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted by venue with correct instrument, side, price, and quantity. |
| Skip when | Adapter does not support options trading. |
Python config:
ExecTesterConfig(
instrument_id=instrument_id, # CryptoOption instrument
order_qty=Decimal("1"),
enable_limit_buys=False,
enable_limit_sells=True,
tob_offset_ticks=500,
)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded. |
| Action | Place limit order with adapter‑specific pricing via order_params. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted. |
| Pass criteria | Order accepted; venue acknowledges the alternative pricing mode. |
| Skip when | Adapter does not support alternative pricing modes for options. |
Considerations:
price field on the order object may be a placeholder when alternative pricing
is active. Consult the adapter guide for supported parameter keys.px_usd (USD price) and px_vol (implied volatility).Python config:
ExecTesterConfig(
instrument_id=instrument_id, # CryptoOption instrument
order_qty=Decimal("1"),
enable_limit_buys=True,
enable_limit_sells=False,
order_params={"px_usd": "100.5"}, # Adapter-specific pricing key
)
| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded. |
| Action | Submit an order type the venue does not support for options (e.g. market order). |
| Event sequence | Adapter‑dependent: OrderDenied (pre‑submission) or OrderSubmitted → OrderRejected (post‑submission). |
| Pass criteria | Order does not fill. Denial or rejection reason references the unsupported order type. |
| Skip when | Adapter does not support options. |
Considerations:
open_position_on_start_qty on an
option instrument. Some unsupported types (e.g. MarketToLimit) require
manual or programmatic submission.| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded. |
| Action | Submit a conditional order on an option instrument. |
| Event sequence | Adapter‑dependent: OrderDenied (pre‑submission) or OrderSubmitted → OrderRejected (post‑submission). |
| Pass criteria | Order does not fill. Reason references unsupported conditional order type. |
| Skip when | Adapter does not support options, or adapter supports conditionals for options. |
Considerations:
STOP_MARKET, STOP_LIMIT, MARKET_IF_TOUCHED, LIMIT_IF_TOUCHED,
TRAILING_STOP_MARKET).enable_stop_buys/enable_stop_sells
with stop_order_type on an option instrument.| Field | Value |
|---|---|
| Prerequisite | Adapter connected, option instrument loaded, sufficient book depth. |
| Action | Place a limit order with TimeInForce::Fok on an option instrument. |
| Event sequence | OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled or OrderCanceled. |
| Pass criteria | Order fills completely or is canceled. No partial fills. |
| Skip when | Adapter does not support FOK for options. |
Considerations:
op_fok). The adapter handles this mapping transparently.| Field | Value |
|---|---|
| Prerequisite | Open limit order from TC-E90 or TC-E91. |
| Action | Cancel the open limit order. |
| Event sequence | OrderPendingCancel → OrderCanceled. |
| Pass criteria | Order canceled; no longer appears in open orders on the venue. |
| Skip when | Adapter does not support options. |
| Field | Value |
|---|---|
| Prerequisite | Open option position from a prior session. |
| Action | Start the node with reconciliation=True. |
| Event sequence | PositionStatusReport generated for the option position. |
| Pass criteria | Position loaded into cache with correct instrument, side, quantity, and entry price. |
| Skip when | Adapter does not support options. |
Considerations:
close_positions_on_stop=False).Quick reference for all ExecTesterConfig parameters. Defaults shown are for the Python config;
the Rust builder uses equivalent defaults.
| Parameter | Type | Default | Affects groups |
|---|---|---|---|
instrument_id | InstrumentId | required | All |
order_qty | Decimal | required | All |
order_display_qty | Decimal? | None | 2, 7 |
order_expire_time_delta_mins | PositiveInt? | None | 2 |
order_params | dict? | None | 7, 10 |
client_id | ClientId? | None | All |
subscribe_quotes | bool | True | — |
subscribe_trades | bool | True | — |
subscribe_book | bool | False | — |
book_type | BookType | L2_MBP | — |
book_depth | PositiveInt? | None | — |
book_interval_ms | PositiveInt | 1000 | — |
book_levels_to_print | PositiveInt | 10 | — |
open_position_on_start_qty | Decimal? | None | 1, 9 |
open_position_time_in_force | TimeInForce | GTC | 1 |
enable_limit_buys | bool | True | 2, 4, 5, 6 |
enable_limit_sells | bool | True | 2, 4, 5, 6 |
enable_stop_buys | bool | False | 3, 4 |
enable_stop_sells | bool | False | 3, 4 |
limit_time_in_force | TimeInForce? | None | 2, 6 |
tob_offset_ticks | PositiveInt | 500 | 2, 4 |
stop_order_type | OrderType | STOP_MARKET | 3 |
stop_offset_ticks | PositiveInt | 100 | 3 |
stop_limit_offset_ticks | PositiveInt? | None | 3 |
stop_time_in_force | TimeInForce? | None | 3 |
stop_trigger_type | TriggerType? | None | 3 |
enable_brackets | bool | False | 6 |
bracket_entry_order_type | OrderType | LIMIT | 6 |
bracket_offset_ticks | PositiveInt | 500 | 6 |
modify_orders_to_maintain_tob_offset | bool | False | 4 |
modify_stop_orders_to_maintain_offset | bool | False | 4 |
cancel_replace_orders_to_maintain_tob_offset | bool | False | 4 |
cancel_replace_stop_orders_to_maintain_offset | bool | False | 4 |
use_post_only | bool | False | 2, 6, 7, 8 |
use_quote_quantity | bool | False | 1, 7 |
emulation_trigger | TriggerType? | None | 2, 3 |
cancel_orders_on_stop | bool | True | 5, 9 |
close_positions_on_stop | bool | True | 9 |
close_positions_time_in_force | TimeInForce? | None | 9 |
reduce_only_on_stop | bool | True | 7, 9 |
use_individual_cancels_on_stop | bool | False | 5 |
use_batch_cancel_on_stop | bool | False | 5 |
dry_run | bool | False | — |
log_data | bool | True | — |
test_reject_post_only | bool | False | 8 |
test_reject_reduce_only | bool | False | 8 |
can_unsubscribe | bool | True | 9 |