3. 核心架构总览
从回测迁移到实盘,最容易踩的坑不是策略逻辑本身,而是对框架运行机制的理解偏差。NautilusTrader 采用事件驱动架构,回测与实盘共享同一套核心组件,差异只在于数据来源和时钟推进方式。理解这套架构,是保证“回测能跑、实盘也能跑”的前提。
一、核心原理:一切皆事件,组件靠总线解耦
NautilusTrader 的中枢是 消息总线(MessageBus)。所有组件之间不直接互相调用,而是通过总线发布和订阅消息。数据引擎收到行情后发布 QuoteTick、TradeTick、Bar 等事件;策略订阅这些事件并产生订单命令;执行引擎接收命令后与交易场所交互,再把成交回报发布回总线;投资组合订阅成交事件更新持仓与盈亏。这种解耦让回测和实盘可以复用同一份策略代码。
围绕总线,几个核心组件各司其职:
- NautilusKernel:系统内核,负责按配置装配所有组件、管理生命周期(启动、运行、停止)。
- DataEngine:数据引擎,负责行情数据的接入、解析、缓存与分发,是策略的“输入口”。
- ExecutionEngine:执行引擎,负责订单管理、路由到交易场所适配器、处理成交与拒单。
- Portfolio:投资组合,跟踪账户、持仓、未实现与已实现盈亏,是风控和绩效的基础。
- Cache:缓存,保存订单、持仓、账户、合约等状态,供各组件快速查询。
- Clock:时钟,回测时由数据时间戳驱动,实盘时使用真实时间,是回测与实盘的关键差异点。
关键认知:回测与实盘的组件拓扑几乎一致,唯一显著区别是
Clock 与数据/执行适配器的实现。策略代码不应感知自己运行在哪种模式。
二、方法流程:一次行情到一次成交的完整链路
下面用一条行情驱动一次下单的链路,串起各组件协作流程:
- 数据适配器(回测为数据目录,实盘为交易所 WebSocket)产生原始行情。
DataEngine解析并标准化为内部事件,写入Cache,再发布到MessageBus。- 策略的
on_bar/on_quote_tick被触发,计算信号后调用self.buy(...)或self.submit_order(...)。 - 订单命令经总线进入
ExecutionEngine,生成Order并写入缓存,再交给执行适配器。 - 适配器返回
OrderAccepted、OrderFilled等事件,执行引擎更新订单状态并发布事件。 Portfolio订阅成交事件,更新持仓、现金与盈亏;策略的on_order_filled同步被调用。
这条链路在回测和实盘中完全一致,区别仅在于第 1 步和第 5 步的适配器实现。因此迁移时,重点检查的是适配器配置与时钟行为,而不是重写策略。
三、案例/场景:从回测配置迁移到实盘配置
回测时通常使用 BacktestEngine 并加载本地数据;实盘时改用 TradingNode 并接入交易所适配器。两者共享策略类,但配置结构不同。下面是一个对比清单:
| 维度 | 回测(BacktestEngine) | 实盘(TradingNode) |
|---|---|---|
| 时钟 | 由数据时间戳推进 | 真实系统时间 |
| 数据来源 | 本地 Parquet/CSV 数据目录 | 交易所 WebSocket / REST |
| 执行适配器 | 模拟撮合(含滑点、手续费模型) | 真实交易所下单接口 |
| 账户状态 | 初始资金虚拟账户 | 真实账户,需处理余额与保证金 |
| 网络与重连 | 无 | 需处理断线、限频、部分成交 |
| 策略代码 | 完全复用,不因模式而改写 | |
一个典型的实盘节点配置片段如下:
from nautilus_trader.live.node import TradingNode
from nautilus_trader.config import TradingNodeConfig
config = TradingNodeConfig(
trader_id="TRADER-001",
data_clients={"BINANCE": BinanceDataClientConfig()},
exec_clients={"BINANCE": BinanceExecClientConfig()},
)
node = TradingNode(config=config)
node.trader.add_strategy(MyStrategy(config=MyStrategyConfig()))
node.build()
node.run()
迁移时,策略类 MyStrategy 与回测中完全相同,变化集中在 config 的客户端与账户配置上。
四、误区与复盘:迁移中最常见的三个错误
误区一:把回测中的“即时成交”当成实盘常态。回测撮合往往假设订单立即全部成交,而实盘存在延迟、部分成交和拒单。迁移后必须让策略能处理
OrderPartiallyFilled 和 OrderRejected。
误区二:忽略时钟差异导致定时逻辑失效。回测中
Clock 由数据驱动,若策略依赖 on_timer 做定时任务,实盘中会按真实时间触发,频率和顺序可能与回测不同。
误区三:直接复用回测缓存状态。实盘启动时
Cache 为空,持仓和订单需从账户同步或重建,不能假设缓存中已有历史状态。
复盘建议:迁移前先在实盘环境用最小仓位跑通“行情接入—下单—成交回报—持仓更新”全链路,确认各组件事件顺序与回测一致,再逐步放大仓位。理解引擎、总线、数据引擎、执行引擎、投资组合与缓存之间的协作关系,能让迁移从“试错”变成“可控验证”。