Nautilus Dev - Execution Testing Spec
Nautilus’s developer-guide page “Execution Testing Spec” defines a rigorous, ID-prefixed test matrix (TC-E01..TC-E101) that every
ExecutionClientadapter must pass to be considered baseline-compliant. The matrix is driven by a genericExecTesterstrategy (Python:nautilus_trader.test_kit.strategies.tester_exec; Rust:nautilus_testkit::testers) that exercises ten functional groups - market orders, limit orders, stop/conditional orders, modification, cancellation, brackets, order flags, rejection handling, lifecycle (start/stop including reconcile-from-prior-session), and options trading. Tests are skipped per documented adapter capability rather than per the framework’s surface area, so an adapter passes a subset of the matrix matching its supported order types, TIFs, actions, and flags. Cortana does NOT author a newExecutionClient- it consumes the shipped IBKR adapter (nautilus_trader[ib]) - so day-1 use of this spec is verification of IBKR-exec behaviors, not authoring a fresh test suite. The page is filed as reference for: (a) runningExecTesteragainst the IBKR paper Gateway during the spike to baseline what works; (b) authoring Cortana-specific exec tests that piggyback on the framework’sExecTesterConfigparameter surface (OCAIBOrderTags, emulated bracket TP/SL onMARK_PRICE, reconcile-on-startup with open positions); (c) future MK4+ paper-exec wrapper around UW (unlikely, but the spec applies if it ever happens).
Cortana orientation
This is a medium-relevance reference, not a build target. Cortana’s
day-1 use of the spec is reading the IBKR adapter’s capability matrix
(documented in the IBKR adapter guide, cross-referenced from
nautilus-ib.md) and confirming that the ExecTester
test cases that map to Cortana’s actual order shapes (market entry,
emulated-bracket TP/SL, OCA-tagged exits, reconcile-on-startup of an
open SPY 0DTE position) all green on paper before MK3 cutover. We
verify; we do not author a new ExecutionClient.
If MK4+ ever introduces a paper-exec wrapper around UW (the documented “data-only adapter” sketch in nautilus-adapters.md extended into an exec adapter - currently no plan), this spec becomes the authoring contract.
Reference: the test matrix shape
The spec is organized as ten groups of identified test cases. Each
group has a summary table (TC ID, name, description, skip-when
condition), then per-test “test cards” with Prerequisite, Action,
Event sequence, Pass criteria, Skip when, and (where relevant)
adapter-specific Considerations, plus Python and Rust config
snippets driving the ExecTester strategy.
Test IDs use spaced numbering (TC-E01..TC-E06 then TC-E10..TC-E19 then TC-E20..TC-E27, etc.) so new tests can be inserted into a group without renumbering downstream IDs. An adapter passes groups 1-5 to be “baseline compliant.” Groups 6-10 add capabilities that not all venues support.
The ten groups
| Group | Coverage | Baseline? |
|---|---|---|
| 1 - Market orders | TC-E01..TC-E06 - submit-and-fill BUY/SELL, IOC TIF, FOK TIF, quote-qty, close-position-on-stop. | yes |
| 2 - Limit orders | TC-E10..TC-E19 - GTC BUY/SELL, BUY+SELL pair, IOC aggressive/passive, FOK fill/no-fill, GTD accept + expiry, DAY. | yes |
| 3 - Stop and conditional | TC-E20..TC-E27 - STOP_MARKET BUY/SELL, STOP_LIMIT BUY/SELL, MIT BUY/SELL, LIT BUY/SELL. | yes |
| 4 - Order modification | TC-E30..TC-E36 - modify-price for limit + stop, cancel-replace for limit + stop, modify-rejected on adapter-no-modify-support. | yes |
| 5 - Order cancellation | TC-E40..TC-E44 - cancel single, cancel-all-on-stop, individual cancels on stop, batch cancel on stop, cancel-already-canceled (rejection). | yes |
| 6 - Bracket orders | TC-E50..TC-E53 - bracket BUY (entry+TP+SL), bracket SELL, entry-fill activates TP/SL, bracket with post-only entry. | optional |
| 7 - Order flags | TC-E60..TC-E63 - PostOnly accepted, ReduceOnly on close, display-qty / iceberg, custom adapter order_params. | optional |
| 8 - Rejection handling | TC-E70..TC-E73 - PostOnly rejection (would-cross), ReduceOnly rejection (no position), unsupported order type → OrderDenied, unsupported TIF → OrderDenied. | optional |
| 9 - Lifecycle (start/stop) | TC-E80..TC-E87 - open-position-on-start, cancel-orders-on-stop, close-positions-on-stop, unsubscribe-on-stop, reconcile open orders / filled orders / open long / open short from a prior session. | optional |
| 10 - Options trading | TC-E90..TC-E101 - limit BUY/SELL on a CryptoOption, alt-pricing via order_params (e.g., OKX px_usd / px_vol), unsupported-order-type denial, conditional-order rejection on options, FOK limit option, cancel option order, reconcile option position. | optional |
Required preconditions across all groups
The spec page enumerates these prerequisites verbatim:
- Demo / testnet account with valid API credentials (preferred, not required).
- Account funded with sufficient margin for the test instrument and quantities.
- Target instrument available and loadable via the
InstrumentProvider. - Environment variables set -
{VENUE}_API_KEY,{VENUE}_API_SECRET(or sandbox variants). - Demo / production key separation - venue demo and production
keys are typically separate and not interchangeable; using the
wrong credentials produces
HTTP 401. - Risk engine bypassed -
LiveRiskEngineConfig(bypass=True)to avoid interference with the test path. - Reconciliation enabled -
LiveExecEngineConfig(reconciliation=True)to verify state consistency on (re)connect.
Plus a basic smoke test that runs before any matrix work: open a position with a market order on start, place a buy + sell post-only limit pair, idle 30 seconds, stop (cancelling open orders, closing the position). Smoke pass = no errors, position opened + closed cleanly, limit orders acknowledged.
Reference: required exec-test categories (verbatim from the spec)
Compiled into a single list for cross-referencing into the brain. The spec demands an adapter exercise these behaviors:
- Order submission - market BUY/SELL, limit BUY/SELL, stop-market BUY/SELL, stop-limit BUY/SELL, MIT BUY/SELL, LIT BUY/SELL, trailing-stop variants (trailing-stop coverage is mentioned in the general Nautilus orders taxonomy but the dev spec page focuses on the non-trailing conditional types listed above).
- Order modification - native modify (
OrderPendingUpdate→OrderUpdated) when supported; cancel-replace fallback (OrderPendingCancel→OrderCanceled→ newOrderInitialized→OrderSubmitted→OrderAccepted) always. - Order cancellation - single, cancel-all-on-stop, individual
cancels on stop, batch cancel on stop, cancel-already-canceled
rejection (
OrderCancelRejected). - Fills - full fill, partial fill (cumulative-qty check), close via market on stop, close via reduce-only on stop.
- Rejections -
OrderRejected(venue-side) for PostOnly cross-the-spread and ReduceOnly with no position;OrderDenied(adapter-side, pre-submission) for unsupported order types and TIFs. - Reconcile-on-startup - open orders →
OrderStatusReportper order with statusACCEPTED; filled orders →FillReportper historical fill with price/qty/commission; open long position →PositionStatusReportwithLONG/qty/avg-entry; open short position →PositionStatusReportwithSHORT/qty/avg-entry. - Partial fills - implicit across all groups; the spec’s consideration on TC-E01 reads “Partial fills are valid; verify the cumulative filled quantity matches the order quantity.”
- OCO/OCA via brackets - entry + TP + SL contingent group; entry fill activates TP and SL; per-venue OCA-group activation mechanism may differ (some immediate-active, some via OCA group).
- Brackets -
enable_brackets=True,bracket_entry_order_type=OrderType.LIMIT|MARKET,bracket_offset_ticks=500default for TP/SL distance. - Emulation behavior -
emulation_trigger: TriggerType?parameter onExecTesterConfig; affects groups 2 (limit) and 3 (stop / conditional). Emulated orders run through the OrderEmulator pipeline per nautilus-orders.md. - Paper-exec equivalence - implicit in the prerequisites; the spec asserts that the test path is identical against demo/testnet, sandbox, and live. Per nautilus-execution.md: “Strategy code is identical across all three contexts.” The matrix is therefore the same for paper as for live; only credentials differ.
Reference: ExecTester strategy
Both Python and Rust ship a generic ExecTester Strategy whose
behavior is fully driven by a typed ExecTesterConfig. The Strategy
itself is not Cortana code - it is platform test infrastructure -
but its config surface is the vocabulary for spec-driven adapter
verification.
Python entry point
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)The spec note: “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.”
Rust entry point
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?;Reference example: crates/adapters/{adapter}/examples/node_exec_tester.rs.
ExecTesterConfig parameter surface
The page closes with a parameter reference - the knobs that drive
which test cards each ExecTester run exercises:
| 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 / subscribe_trades / subscribe_book | bool | True / True / False | - |
book_type, book_depth, book_interval_ms, book_levels_to_print | (book-related) | L2_MBP / None / 1000 / 10 | - |
open_position_on_start_qty | Decimal? | None | 1, 9 |
open_position_time_in_force | TimeInForce | GTC | 1 |
enable_limit_buys / enable_limit_sells | bool | True | 2, 4, 5, 6 |
enable_stop_buys / 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, log_data | bool | False / True | - |
test_reject_post_only | bool | False | 8 |
test_reject_reduce_only | bool | False | 8 |
can_unsubscribe | bool | True | 9 |
The Affects groups column is what makes this a testing spec rather
than just a config dump: each parameter is calibrated to drive a
specific subset of the TC-E* matrix. Setting enable_brackets=True
without also enabling at least one limit side is a misconfiguration;
the spec’s per-card snippets show the correct combinations.
Group-by-group reference
Group 1 - Market orders
Six tests covering single-fill market submission. The canonical event sequence the spec demands:
OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled
Considerations the spec calls out:
- “Some adapters simulate market orders as aggressive limit IOC orders (check adapter guide). The event sequence from the strategy’s perspective should be identical regardless of the venue mechanism.”
- “Fill price should be within the recent bid/ask spread.”
- “Partial fills are valid; verify the cumulative filled quantity matches the order quantity.”
For Cortana, this is the entry-leg behavior (V1 uses MARKET entries on the bracket parent per nautilus-ib.md). TC-E01
- TC-E06 are the binding subset - open and close.
Group 2 - Limit orders
Ten tests covering GTC, IOC (aggressive vs passive), FOK (fill vs no-fill), GTD (accept + expiry), and DAY. The spec’s TIF coverage map:
| TC | TIF | Expected terminal | Notes |
|---|---|---|---|
| TC-E10 | GTC BUY | ACCEPTED (open) | passive; verify in cache with OrderStatus.ACCEPTED |
| TC-E11 | GTC SELL | ACCEPTED (open) | mirror of TC-E10 |
| TC-E12 | GTC BUY+SELL | both ACCEPTED | independent sequences |
| TC-E13 | IOC aggressive | OrderFilled | crosses immediately |
| TC-E14 | IOC passive | OrderCanceled | venue cancels unfilled IOC |
| TC-E15 | FOK aggressive | OrderFilled (single fill) | full qty in one event |
| TC-E16 | FOK passive | OrderCanceled | no partial allowed |
| TC-E17 | GTD | ACCEPTED with expiry timestamp | verify expiry field |
| TC-E18 | GTD expired | OrderExpired | wait for elapse; “Some venues may report expiry as a cancel; verify the adapter maps this to OrderExpired.” |
| TC-E19 | DAY | ACCEPTED (open through session) | “DAY orders may behave differently on 24/7 crypto venues vs traditional markets.” |
For Cortana on IBKR, DAY is the primary TIF - every order must be flat by close. GTD is acceptable when the expiry is < session end. GTC is forbidden in 0DTE strategy code (an invariant violation per nautilus-orders.md and nautilus-ib.md).
Group 3 - Stop and conditional orders
Eight tests, two per stop type (BUY + SELL each for STOP_MARKET, STOP_LIMIT, MIT, LIT). The spec emphasizes that “Verifying trigger and fill requires the market to move, which may not happen during the test” - the matrix tests acceptance, not trigger. Trigger behavior is venue-side and inherently non-deterministic during a short test window.
For Cortana, V1 uses STOP_MARKET as the SL bracket leg. TC-E20 (STOP_MARKET BUY) and TC-E21 (SELL) are the relevant cards.
Group 4 - Order modification
Seven tests. Two paths:
- Native modify -
OrderPendingUpdate→OrderUpdated. Adapter declares support; ExecTester drives viamodify_orders_to_maintain_tob_offset=True(or stop variant). - Cancel-replace fallback - universal. Spec verbatim: “This is
the universal alternative when the adapter does not support
native modify. Two distinct orders in the cache: the canceled
original and the new replacement.” Driven via
cancel_replace_orders_to_maintain_tob_offset=True.
TC-E36 (Modify rejected) tests the rejection path on adapters that
don’t support modify. IBKR supports native modify, so this card is
skipped for the IBKR adapter.
Group 5 - Order cancellation
Five tests - single cancel, cancel-all-on-stop, individual cancels
on stop, batch cancel on stop, cancel-already-canceled rejection.
Cortana’s market_exit() path triggers TC-E41 (Cancel all on stop)
shape - multiple open orders, all canceled cleanly.
TC-E44 (Cancel already-canceled order) is the
OrderCancelRejected path - adapter must reject cleanly, not error
or no-op.
Group 6 - Bracket orders
Four tests. The spec’s Group 6 baseline shape:
- TC-E50 (Bracket BUY): limit-buy entry + TP-sell + SL-sell, all three orders accepted (entry below bid, TP above ask, SL below entry).
- TC-E51 (Bracket SELL): mirror of TC-E50.
- TC-E52 (Entry fill activates TP/SL): spec note - “the TP/SL
activation mechanism varies by venue (some activate immediately,
some are OCA groups).” IBKR is the OCA-group case (per
nautilus-ib.md - must explicitly set
IBOrderTags(ocaGroup=..., ocaType=1)). - TC-E53 (Bracket with post-only entry): entry + TP both post-only; SL is not post-only.
Cortana V1 uses MARKET-entry brackets, so the bracket-cards as
written (LIMIT entry default in bracket_entry_order_type) require
adjustment to OrderType.MARKET to map.
Group 7 - Order flags
Four tests - PostOnly accepted, ReduceOnly on close, display-qty
(iceberg), custom adapter order_params.
For Cortana, ReduceOnly on close (TC-E61) is the binding
behavior. SL bracket leg must be reduce_only=True per
nautilus-orders.md so a sizing or race bug
cannot flip the position. The spec verifies the close path applies
the flag.
Group 8 - Rejection handling
Four tests, split across two rejection origins:
- Venue-side rejection (
OrderRejected):- TC-E70 - PostOnly that would cross the spread.
- TC-E71 - ReduceOnly with no position.
- Adapter-side denial (
OrderDenied), pre-submission:- TC-E72 - Unsupported order type.
- TC-E73 - Unsupported TIF.
The distinction is load-bearing: OrderDenied is emitted by the
adapter (or the RiskEngine) before the order leaves Nautilus;
OrderRejected is emitted after the venue refuses. Both are typed
events with reason strings - the spec ensures adapters route
through the correct one.
Group 9 - Lifecycle (start/stop)
Eight tests. The reconciliation subset (TC-E84..TC-E87) is the core spec value for Cortana:
| TC | What’s reconciled | Report variant | Pass criteria |
|---|---|---|---|
| TC-E84 | Open orders from prior session | OrderStatusReport | order in cache with correct venue_order_id, status=ACCEPTED, price/qty/side/type |
| TC-E85 | Filled orders from prior session | FillReport | order in cache with correct venue_order_id, status=FILLED, fill price/qty/commission |
| TC-E86 | Open long position | PositionStatusReport | position in cache with correct instrument, side=LONG, qty, avg-entry |
| TC-E87 | Open short position | PositionStatusReport | position in cache with correct instrument, side=SHORT, qty, avg-entry |
Spec note for reconcile-cards: “Use external_order_claims to claim
the instrument so the adapter reconciles orders for it… Verify
that the reconciled order count matches the venue-reported count.”
This directly closes Cortana’s project_pm_ibkr_exit_invariant.md
trust class - restart-with-open-position must rehydrate cache from
broker truth (covered by nautilus-execution.md
§ Reconcile-on-startup; TC-E86/E87 are the test that the IBKR
adapter implements that promise).
Group 10 - Options trading
Eight tests against a CryptoOption instrument. The spec headlines:
“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.”
The spec uses CryptoOption (Deribit / OKX style); IBKR equity
options are documented separately on the adapter integration page.
Cortana’s options use the IBKR adapter, so Group 10’s cards are
pattern references - we’d implement Cortana-equivalents
(SPY 0DTE option order acceptance, cancellation, reconcile) using
the same shape but against IBKR’s OPT contracts.
Cortana MK3 implications - IBKR exec verification, not authoring
Day-1 use: confirm IBKR adapter passes the relevant subset
The IBKR adapter is platform code (nautilus_trader[ib]) maintained
by the Nautilus team. It already passes the developer-spec matrix
for the capabilities it declares. Cortana’s day-1 work is not
re-running the matrix - it’s running the Cortana-specific subset
that exercises the order shapes Cortana actually submits, against
the IBKR paper Gateway, before MK3 cutover.
The Cortana-specific exec test plan (to be authored as a tests/
subtree post-spike if MK3 GO):
| Cortana behavior | Maps to TC | Verify |
|---|---|---|
| Market entry (bracket parent) | TC-E01 / TC-E06 | OrderFilled within spread; close-on-stop submits opposite-side market |
| Bracket TP child (LIMIT) | TC-E10 / TC-E11 + TC-E50 | Accept with OrderStatus.ACCEPTED; activates after entry fill (TC-E52) |
| Bracket SL child (STOP_MARKET) | TC-E20 / TC-E21 + TC-E50 | Accept with correct trigger; activates after entry fill |
| OCA group on bracket | TC-E50 + IBKR-specific | TP+SL share ocaGroup; one fills, the other cancels (ocaType=1) |
Emulated TP/SL on MARK_PRICE | TC-E10/E11/E20/E21 with emulation_trigger=MARK_PRICE | Order goes through EMULATED → RELEASED states; trigger fires locally |
| Reduce-only SL | TC-E61 | SL has reduce_only=True; cannot flip the position |
market_exit() cancel-all on stop | TC-E41 | Multiple legs all canceled cleanly |
| Reconcile open SPY 0DTE position on restart | TC-E86 | PositionStatusReport with LONG/qty/avg-entry; cache rehydrates correctly |
| Reconcile open TP/SL orders on restart | TC-E84 | OrderStatusReport per leg; venue order IDs preserved |
| Cancel-already-canceled idempotency | TC-E44 | OrderCancelRejected not error |
Spike-day Saturday actions (concrete):
- After the Step 1 / Step 2 plumbing is up, run the platform’s
smoke-test config (
open_position_on_start_qty=1+ post-only limit pair, 30-sec idle, stop) against IBKR paper Gateway. This is the spec’s basic-smoke pre-test. - Run
ExecTesterwithenable_brackets=True, bracket_entry_order_type=OrderType.MARKET, emulation_trigger= TriggerType.MARK_PRICEagainst an SPY 0DTE strike - exercises TC-E50 + TC-E52 + the OCA tag path. - Restart the engine mid-trade with the bracket open - verify
TC-E86 + TC-E84 emit
reconciliation=Trueevents that rehydrate the cache.
What Cortana does NOT do day-1
- Author a new
ExecutionClient. No plan for one. UW remains data-only per nautilus-adapters.md. IBKR adapter is consumed as-is. - Run the full TC-E01..TC-E101 matrix. The platform team owns that for the IBKR adapter. We run the Cortana subset only.
- Test the TIF combinations Cortana doesn’t use. GTC, IOC, FOK are skipped for V1 strategy code - DAY is the only TIF Cortana emits.
- Test options-specific cards (Group 10). Those are
CryptoOption-shaped against Deribit/OKX. IBKR equity options go through the IBKR adapter’s own option path; the spec’s Group 10 is a pattern reference, not a literal test set.
MK4+ paper-exec wrapper around UW (hypothetical)
If MK4+ ever introduces a paper-exec wrapper around UW (extending the data-only adapter sketch to include exec), this spec becomes the authoring contract. The wrapper would need to:
- Implement the
ExecutionClientcontract per nautilus-execution.md § ExecutionClient. - Pass the baseline (groups 1-5) of TC-E01..TC-E44.
- Declare a capability matrix in the wrapper’s adapter guide saying which order types, TIFs, and flags are supported (so the test matrix knows which cards to skip).
- Emit the four reconciliation report variants
(
OrderStatusReport,FillReport,OrderWithFills,PositionStatusReport) to satisfy TC-E84..TC-E87.
There is no plan to author a paper-exec wrapper around UW. Cortana’s
existing UW pricing-source-of-truth posture per
feedback_ibkr_pricing_source.md (UW for scoring/flow only; IBKR for
pricing) explicitly excludes UW from the exec path. Filing this as a
hypothetical only because the spec page would apply to it.
Standalone wins regardless of MK3 GO/NO-GO
Even if the spike says NO-GO on Nautilus migration, this spec is a useful reference for MK2’s own exec test design. The MK2 codepath could adopt the same shape - generic exec-driver strategy + typed config + TC-prefixed test cards - to systematize the IBKR exec behaviors we currently test ad-hoc. Not a priority pre-spike, but the structure is portable.
Caveats and gotchas
ExecTesterrequiresLiveRiskEngineConfig(bypass=True). The spec is explicit. A meta-prob veto rule placed in the RiskEngine (per nautilus-execution.md § Custom RiskEngine rules) would interfere withExecTesterruns. Cortana-specific test runs that need both RiskEngine validation AND exec-spec coverage need a separate path (e.g., CortanaTester strategy that subclassesExecTesterplus a non-bypass risk config).- Demo / production credential separation. Spec calls out
HTTP 401 from cross-using keys. IBKR paper account
DUP696099uses the same login as live but routes via paper port4002; per-account auth still applies. reconciliation=Trueis mandatory for Group 9 cards. Without it, TC-E84..TC-E87 cannot pass - the engine wouldn’t sync from broker truth on (re)start. This is the same flag Cortana needs set in production.- TC-E36 (Modify rejected) only applies to adapters without
modify support. IBKR supports native modify (
OrderUpdated); this card is skipped. - Test IDs use spaced numbering (TC-E01..TC-E06, TC-E10..TC-E19, TC-E20..TC-E27, etc.) for insertion without renumbering. Cortana-specific extensions should follow the same convention if/when we author a CortanaTester subclass.
- Group 6 bracket cards default to LIMIT entry. Cortana V1
uses MARKET entry; map by setting
bracket_entry_order_type=OrderType.MARKET. - Group 10 (Options) is
CryptoOption-flavored. SPY equity options on IBKR follow a different code path; the spec’s options cards are pattern references, not literal IBKR-equity-option tests. - Some adapters simulate market as aggressive limit IOC. Spec
note on TC-E01. The strategy-side event sequence is identical
(
OrderInitialized → OrderSubmitted → OrderAccepted → OrderFilled) but the adapter guide should disclose the mechanism. - GTD expiry mapping varies by venue. Spec note on TC-E18:
“Some venues may report expiry as a cancel; verify the adapter
maps this to OrderExpired.” For IBKR, GTD expiry should produce
OrderExpired, notOrderCanceled. - DAY TIF on 24/7 venues. Spec note on TC-E19. Cortana on IBKR trades a session-bound venue, so DAY semantics are clean.
- Smoke test ≠ matrix. The basic smoke test (open position + post-only limit pair + 30-sec idle + stop) is a sanity gate, not a compliance test. An adapter that passes smoke can still fail individual matrix cards.
- Capability matrix lives in the adapter guide. The spec defers per-adapter capability declarations (which order types, TIFs, actions, flags) to each adapter’s own page - nautilus-ib.md for IBKR, future per-adapter pages for others.
When this concept applies
- Reading the IBKR adapter’s exec-test posture before MK3 cutover.
- Designing a Cortana-specific
tests/exec/subtree post-spike that exercises the TC-E* cards Cortana relies on (entries, brackets, OCA, emulation, reconcile). - Authoring a paper-exec wrapper around UW (hypothetical MK4+; no current plan).
- Validating that the IBKR adapter’s reconciliation behavior
(TC-E84..TC-E87) closes
project_pm_ibkr_exit_invariant.mdin practice, not just by design. - Sanity-checking custom
ExecTesterconfig combinations before running them against paper. - Cross-referencing per-test event sequences when reading reconciliation logs for the first time.
When it breaks / does not apply
- General concepts (kernel, message bus, cache). Those live on the Concepts pages, not the developer guide.
- Adapter authoring patterns. This spec is for exec
verification, not adapter implementation. The adapter contract
itself lives in nautilus-execution.md §
ExecutionClient and the (parallel)
nautilus-dev-adapters.mdpage being filed alongside this one. - Strategy authoring.
ExecTesteris the platform’s generic test strategy; Cortana’sCortanaStrategyis the production strategy. They overlap at the order-submission API surface but not in lifecycle posture. - Data-feed verification. That’s the sister spec -
nautilus-dev-spec-data-testing.md(parallel agent) - which defines the equivalent ID-prefixed matrix forDataClientadapters. The two specs are siblings: data first, exec second (the exec spec verbatim says “Data connectivity should be verified first using the Data Testing Spec.”). - Regression / unit testing. This is integration-level
verification against a live or paper venue; pure-Python unit
tests for strategy logic live elsewhere (see
nautilus-dev-testing.mdparallel - testing standards page). - Performance / latency benchmarks. That’s the
developer_guide/benchmarking/page (next page in the dev guide nav).
See Also
- Nautilus Dev - Adapters (parallel agent) - adapter authoring guide; the contract this spec verifies.
- Nautilus Dev - Testing (parallel agent) - broader testing standards, unit / integration / fuzz tiers; this exec spec is the live-venue tier within that taxonomy.
- Nautilus Dev - Spec Data Testing
(parallel agent - sister spec) -
DataClientmatrix; “Data connectivity should be verified first using the Data Testing Spec” per this page’s prerequisites. - Nautilus Execution -
ExecutionEngine,ExecutionClientcontract, reconciliation reports, OMS, custom RiskEngine rules; the runtime context the matrix tests against. - Nautilus Orders - order-type taxonomy,
TIFs, bracket primitive, emulation; the vocabulary
ExecTesterdrives. - Nautilus Positions - position lifecycle, NETTING vs HEDGING; what TC-E86/E87 reconcile against.
- Nautilus IB Integration - IBKR adapter
capability matrix, OCA
IBOrderTagsrequirement,fetch_all_open_orders, paper vs live differences. Cortana’s consumed exec adapter; the spec is verified against this adapter, not authored against it. - Nautilus Adapters - five-component adapter contract; UW data-only adapter sketch.
- Nautilus Live -
LiveNode.builder(...)entry point referenced in the spec’s Python setup snippet. - Nautilus Configuration -
LiveExecEngineConfig,LiveRiskEngineConfigtyped contracts. - 2026-05-09 Nautilus Spike Plan:
~/conductor/workspaces/cortanaroi-mk2/belo-horizonte/plans/2026-05-09-nautilus-spike.md ~/.claude/projects/-Users-codysmith-conductor-workspaces-cortanaroi-cortanaroi-mk2/memory/project_pm_ibkr_exit_invariant.md- exit invariant the reconciliation cards (TC-E84..TC-E87) close in practice.
~/.claude/projects/-Users-codysmith-conductor-workspaces-cortanaroi-cortanaroi-mk2/memory/feedback_dual_tp_defense_in_depth.md- emulated bracket TP/SL pattern that maps to Group 6 + Group 2
cards with
emulation_trigger=MARK_PRICE.
- emulated bracket TP/SL pattern that maps to Group 6 + Group 2
cards with
~/.claude/projects/-Users-codysmith-conductor-workspaces-cortanaroi-cortanaroi-mk2/memory/feedback_ibkr_pricing_source.md- UW remains data-only (excluded from any future exec wrapper authoring).
~/.claude/projects/-Users-codysmith-conductor-workspaces-cortanaroi-cortanaroi-mk2/memory/reference_ibkr_api.md- IBKR TWS API master reference complementary to the IBKR adapter integration page.
- Source: https://nautilustrader.io/docs/latest/developer_guide/spec_exec_testing/
Timeline
2026-05-07 | Cody - Filed during pre-spike concept mastery sweep batch 7 (developer guide).