docs/how_to/configure_live_trading.md
Set up a TradingNode for live market connectivity. For background on live
trading architecture and reconciliation, see the
Live trading concept guide.
:::danger[Jupyter notebooks not recommended for live trading] Do not run live trading nodes in Jupyter notebooks. Event loop conflicts and operational risks make them unsuitable:
TradingNode's event loop.nest_asyncio are not production-grade.Use Jupyter for backtesting, analysis, and experimentation. For live trading, run nodes as standalone Python scripts or services. :::
:::warning[One TradingNode per process]
Running multiple TradingNode instances concurrently in the same process is not supported due to global singleton state.
Add multiple strategies to a single node, or run additional nodes in separate processes for parallel execution.
See Processes and threads for details. :::
:::warning[Do not block the event loop]
User code on the event loop thread (strategy callbacks, actor handlers, on_event methods)
must return quickly. This applies to both Python and Rust. Blocking operations like model
inference, heavy calculations, or synchronous I/O cause missed fills, stale data, and
delayed order submissions. Offload long-running work to an executor or a separate thread/process.
:::
:::info[Platform differences] Windows signal handling differs from Unix-like systems. If you are running on Windows, please read the note on Windows signal handling for guidance on graceful shutdown behavior and Ctrl+C (SIGINT) support. :::
TradingNodeConfig inherits from NautilusKernelConfig and adds live-specific options.
For background on how config structs handle defaults and Option<T> semantics, see
the Configuration concept guide.
from nautilus_trader.config import TradingNodeConfig
config = TradingNodeConfig(
trader_id="MyTrader-001",
# Component configurations
cache=CacheConfig(),
message_bus=MessageBusConfig(),
data_engine=LiveDataEngineConfig(),
risk_engine=LiveRiskEngineConfig(),
exec_engine=LiveExecEngineConfig(),
portfolio=PortfolioConfig(),
# Client configurations
data_clients={
"BINANCE": BinanceDataClientConfig(),
},
exec_clients={
"BINANCE": BinanceExecClientConfig(),
},
)
| Setting | Default | Description |
|---|---|---|
trader_id | "TRADER-001" | Unique trader identifier (name‑tag format). |
instance_id | None | Optional unique instance identifier. |
timeout_connection | 60.0 | Connection timeout in seconds. |
timeout_reconciliation | 10.0 | Reconciliation timeout in seconds. |
timeout_portfolio | 10.0 | Portfolio initialization timeout. |
timeout_disconnection | 10.0 | Disconnection timeout. |
timeout_post_stop | 5.0 | Post‑stop cleanup timeout. |
from nautilus_trader.config import CacheConfig
from nautilus_trader.config import DatabaseConfig
cache_config = CacheConfig(
database=DatabaseConfig(
host="localhost",
port=6379,
username="nautilus",
password="pass",
connection_timeout=2,
response_timeout=2,
),
encoding="msgpack", # or "json"
timestamps_as_iso8601=True,
buffer_interval_ms=100,
flush_on_start=False,
)
from nautilus_trader.config import MessageBusConfig
from nautilus_trader.config import DatabaseConfig
message_bus_config = MessageBusConfig(
database=DatabaseConfig(
connection_timeout=2,
response_timeout=2,
),
timestamps_as_iso8601=True,
use_instance_id=False,
types_filter=[QuoteTick, TradeTick], # Filter specific message types
stream_per_topic=False,
autotrim_mins=30, # Automatic message trimming
heartbeat_interval_secs=1,
)
A node can connect to multiple venues. This example configures both spot and futures markets for Binance:
config = TradingNodeConfig(
trader_id="MultiVenue-001",
# Multiple data clients for different market types
data_clients={
"BINANCE_SPOT": BinanceDataClientConfig(
account_type=BinanceAccountType.SPOT,
environment=BinanceEnvironment.LIVE,
),
"BINANCE_FUTURES": BinanceDataClientConfig(
account_type=BinanceAccountType.USDT_FUTURES,
environment=BinanceEnvironment.LIVE,
),
},
# Corresponding execution clients
exec_clients={
"BINANCE_SPOT": BinanceExecClientConfig(
account_type=BinanceAccountType.SPOT,
environment=BinanceEnvironment.LIVE,
),
"BINANCE_FUTURES": BinanceExecClientConfig(
account_type=BinanceAccountType.USDT_FUTURES,
environment=BinanceEnvironment.LIVE,
),
},
)
LiveExecEngineConfig controls order processing, execution events, and
venue reconciliation. For full details see the
API Reference.
Recovers missed order and position events to keep system state consistent with the venue.
| Setting | Default | Description |
|---|---|---|
reconciliation | True | Activate reconciliation at startup to align internal state with the venue. |
reconciliation_lookback_mins | None | How far back (minutes) to request past events for reconciling uncached state. |
reconciliation_instrument_ids | None | Include list of instrument IDs to reconcile. |
filtered_client_order_ids | None | Client order IDs to skip during reconciliation (for venue‑side duplicates). |
See Execution reconciliation for details.
Controls which order events and reports the system processes, preventing conflicts across trading nodes.
| Setting | Default | Description |
|---|---|---|
filter_unclaimed_external_orders | False | Drop unclaimed external orders so they do not affect the strategy. |
filter_position_reports | False | Drop position status reports. Useful when multiple nodes trade one account. |
:::note[Order tagging behavior] Reconciliation tags orders by origin:
VENUE tag: external orders discovered at the venue (placed outside this system).RECONCILIATION tag: synthetic orders generated to align position discrepancies.When filter_unclaimed_external_orders is enabled, only VENUE-tagged orders are filtered.
RECONCILIATION-tagged orders are never filtered, so position alignment always succeeds.
:::
Continuous reconciliation keeps runtime order state aligned after startup by checking in‑flight orders, polling open orders, and auditing own order books. Configure the loop with these settings. For runtime state‑transition rules, retry coordination, and caveats, see Runtime checks.
| Setting | Default | Description |
|---|---|---|
inflight_check_interval_ms | 2,000 ms | How often to check in‑flight order status. Set to 0 to disable. |
inflight_check_threshold_ms | 5,000 ms | Time before an in‑flight order triggers a venue status check. Lower if colocated. |
inflight_check_retries | 5 retries | Retry attempts to verify an in‑flight order with the venue. |
open_check_interval_secs | None | How often (seconds) to check open orders at the venue. None or 0.0 disables. Recommended: 5-10s. |
open_check_open_only | True | When true, query only open orders; when false, fetch full history (resource‑intensive). |
open_check_lookback_mins | 60 min | Lookback window (minutes) for order status polling. Only orders modified within this window. |
open_check_threshold_ms | 5,000 ms | Minimum time since last cached event before acting on venue discrepancies. |
open_check_missing_retries | 5 retries | Max retries before targeted not‑found resolution for eligible orders. |
max_single_order_queries_per_cycle | 10 | Cap on single‑order queries per cycle. Prevents rate‑limit exhaustion. |
single_order_query_delay_ms | 100 ms | Delay (ms) between single‑order queries to avoid rate limits. |
reconciliation_startup_delay_secs | 10.0 s | Delay (seconds) after startup reconciliation before continuous checks begin. |
own_books_audit_interval_secs | None | Interval (seconds) between auditing own order books against public books. |
position_check_interval_secs | None | Interval (seconds) between position consistency checks. On discrepancy, queries for missing fills. None disables. Recommended: 30-60s. |
position_check_lookback_mins | 60 min | Lookback window (minutes) for querying fill reports on position discrepancy. |
position_check_threshold_ms | 5,000 ms | Minimum time since last local activity before acting on position discrepancies. |
position_check_retries | 3 retries | Max attempts per instrument before the engine stops retrying that discrepancy. Once exceeded, an error is logged and the discrepancy is no longer actively reconciled until it clears. |
:::warning
open_check_lookback_mins: do not reduce below 60 minutes. A short window
triggers false "missing order" resolutions because orders fall outside the query range.open_check_threshold_ms: increase if venue timestamps lag the local clock, so
recently updated orders are not marked missing prematurely.reconciliation_startup_delay_secs: do not reduce below 10 seconds in production.
The delay lets the system stabilize after startup reconciliation before continuous
checks begin.:::
| Setting | Default | Description |
|---|---|---|
allow_overfills | False | Allow fills exceeding order quantity (logs warning). Useful when reconciliation races fills. |
generate_missing_orders | True | Generate LIMIT orders during reconciliation to align position discrepancies (strategy EXTERNAL, tag RECONCILIATION). |
snapshot_orders | False | Take order snapshots on order events. |
snapshot_positions | False | Take position snapshots on position events. |
snapshot_positions_interval_secs | None | Interval (seconds) between position snapshots. |
debug | False | Enable debug logging for execution. |
Periodically purges closed orders, closed positions, and account events from the in-memory cache, keeping memory bounded during long-running or HFT sessions.
| Setting | Default | Description |
|---|---|---|
purge_closed_orders_interval_mins | None | How often (minutes) to purge closed orders from memory. Recommended: 10-15 min. |
purge_closed_orders_buffer_mins | None | How long (minutes) an order must be closed before purging. Recommended: 60 min. |
purge_closed_positions_interval_mins | None | How often (minutes) to purge closed positions from memory. Recommended: 10-15 min. |
purge_closed_positions_buffer_mins | None | How long (minutes) a position must be closed before purging. Recommended: 60 min. |
purge_account_events_interval_mins | None | How often (minutes) to purge account events from memory. Recommended: 10-15 min. |
purge_account_events_lookback_mins | None | How old (minutes) an account event must be before purging. Recommended: 60 min. |
purge_from_database | False | Also delete from the backing database (Redis/PostgreSQL). Use with caution. |
Setting an interval enables the purge loop; leaving it unset disables scheduling and
deletion. Database records are unaffected unless purge_from_database is true. Each
loop delegates to the cache APIs described in
Cache.
| Setting | Default | Description |
|---|---|---|
qsize | 100,000 | Size of internal queue buffers. |
graceful_shutdown_on_exception | False | Gracefully shut down on unexpected queue processing exceptions (not user code). |
For a complete parameter list see the StrategyConfig
API Reference.
| Setting | Default | Description |
|---|---|---|
strategy_id | None | Unique strategy identifier. |
order_id_tag | None | Unique tag appended to this strategy's order IDs. |
| Setting | Default | Description |
|---|---|---|
oms_type | None | OMS type for position ID and order processing. |
use_uuid_client_order_ids | False | Use UUID4 values for client order IDs. |
external_order_claims | None | Instrument IDs whose external orders and reconciliation activity this strategy claims. |
manage_contingent_orders | False | Automatically manage OTO, OCO, and OUO contingent orders. |
manage_gtd_expiry | False | Manage GTD expirations for orders. |
:::warning
Windows: asyncio event loops do not implement loop.add_signal_handler. As a result,
TradingNode does not receive OS signals via asyncio on Windows. Use Ctrl+C (SIGINT) handling or
programmatic shutdown; SIGTERM parity is not expected on Windows.
:::
On Windows, asyncio event loops do not implement loop.add_signal_handler, so Unix-style
signal integration is unavailable. TradingNode does not receive OS signals via asyncio
on Windows and will not stop gracefully unless you intervene.
Recommended approaches:
run with try/except KeyboardInterrupt and call node.stop() then node.dispose().
Ctrl+C raises KeyboardInterrupt in the main thread, giving you a clean teardown path.ShutdownSystem command programmatically (or call shutdown_system(...) from
an actor/component) to trigger the same shutdown path.The "inflight check loop task still pending" message appears because the normal graceful shutdown path is not triggered. This is tracked as #2785.
The v2 LiveNode already handles Ctrl+C via tokio::signal::ctrl_c() and a Python SIGINT
bridge, so runner and tasks shut down cleanly.
Example pattern for Windows:
try:
node.run()
except KeyboardInterrupt:
pass
finally:
try:
node.stop()
finally:
node.dispose()