4. 数据模型与数据类型
在 NautilusTrader 中,数据模型不是简单的“行情格式”,而是回测与实盘共用的一套语义契约。策略读取的每一个对象,都携带时间戳、价格、数量、交易方向以及聚合方式等元信息。理解这些类型的边界,才能避免“回测能跑、实盘报错”或“信号频率与数据频率错配”的典型问题。
核心原理:从市场事件到类型化对象
真实市场只产生两类原始事件:订单簿变化与成交。NautilusTrader 将其抽象为若干不可变(immutable)数据类型,策略通过 on_bar、on_quote_tick、on_trade_tick、on_order_book_delta 等回调接收。核心区别在于:Bar 是时间聚合后的派生数据,Tick 是逐笔事件,OrderBookDelta 是订单簿的增量更新。
- Bar:按固定时间窗口(如 1 分钟)聚合的 OHLCV,适合中低频趋势与形态策略。
- QuoteTick:最优买卖报价(bid/ask)及其挂单量,反映流动性,适合做市与价差策略。
- TradeTick:实际成交价、成交量与主动方向(aggressor side),适合成交驱动与微观结构策略。
- OrderBookDelta:订单簿某一价位的挂单量变化,适合订单簿失衡与高频策略。
- Tick:泛称,实际使用时必须明确是 QuoteTick 还是 TradeTick,否则回测与实盘语义不一致。
bar_type 必须显式声明聚合方式与价格类型,例如 EUR/USD.IBKR-1-MINUTE-LAST-EXTERNAL。回测与实盘使用同一字符串,才能保证数据源一致。方法流程:如何选择与接入数据类型
选择数据类型应遵循“策略信号频率 → 数据粒度 → 回调实现”的顺序,而不是先写策略再找数据。流程如下:
- 确定策略决策频率:日频、分钟频还是逐笔。
- 选择对应数据类型:分钟频用 Bar,逐笔用 TradeTick,做市用 QuoteTick,订单簿策略用 OrderBookDelta。
- 在配置中订阅数据,并确保回测数据目录与实盘数据源类型一致。
- 实现对应回调,并在回调内只处理该类型对象,避免跨类型混用。
from nautilus_trader.config import BacktestDataConfig
data_config = BacktestDataConfig(
catalog_path="./catalog",
data_cls=QuoteTick,
instrument_id=InstrumentId.from_str("EUR/USD.IBKR"),
)
# 策略中订阅
self.subscribe_quote_ticks(instrument_id)
self.subscribe_trade_ticks(instrument_id)
self.subscribe_bars(bar_type)
回测时,NautilusTrader 会按时间戳顺序将数据推送给策略;实盘时,适配器将交易所推送转换为相同类型。因此,只要类型一致,策略逻辑无需修改,这正是迁移实战的关键。
案例/场景:不同策略的数据选择
| 策略类型 | 推荐数据类型 | 原因 | 常见误区 |
|---|---|---|---|
| 日频趋势 | Bar(1D) | 噪声低,计算量小 | 用 Tick 聚合日线,回测过慢 |
| 分钟均值回归 | Bar(1M) | 信号频率匹配 | 忽略 bar 内价格路径 |
| 做市/价差 | QuoteTick | 需要 bid/ask 与挂单量 | 只用 TradeTick 无法看到报价 |
| 成交驱动 | TradeTick | 需要主动买卖方向 | 把 QuoteTick 当成交用 |
| 订单簿失衡 | OrderBookDelta | 需要深度变化 | 回测无 L2 数据却订阅 delta |
例如,一个基于买卖价差收敛的做市策略,若只订阅 TradeTick,就无法知道当前最优报价,回测中会频繁以错误价格成交。正确做法是同时订阅 QuoteTick 与 TradeTick,并在 on_quote_tick 中更新报价,在 on_trade_tick 中确认成交。
误区/复盘:迁移中最容易踩的坑
误区一:Bar 与 Tick 混用。回测用 Bar 生成信号,实盘却用 Tick 触发,导致信号频率与成交逻辑不一致。迁移时应保持数据类型与聚合方式完全一致。
误区二:忽略时间戳语义。QuoteTick 的 ts_event 与 ts_init 不同,前者是交易所事件时间,后者是本地初始化时间。回测排序应使用 ts_event,否则会出现“未来数据”。
误区三:OrderBookDelta 数据缺失。许多免费数据源只有 L1 报价,没有 L2 增量。若策略依赖 delta,回测必须准备对应订单簿数据,否则回测结果不可信。
误区四:把 Tick 当“更细的 Bar”。Tick 没有 OHLC,只有单点价格与数量。策略若按 Bar 逻辑处理 Tick,会得到错误的高开低收。
复盘建议:在迁移前,用同一份数据分别以 Bar 和 Tick 运行一次策略,对比成交次数与盈亏曲线。若差异巨大,说明策略对数据粒度敏感,需要重新审视信号定义,而不是简单替换数据类型。
# 检查数据目录中实际存在的数据类型
from nautilus_trader.persistence.catalog import ParquetDataCatalog
catalog = ParquetDataCatalog("./catalog")
print(catalog.instruments())
print(catalog.quote_ticks(instrument_id)[:2])
print(catalog.trade_ticks(instrument_id)[:2])
print(catalog.bars(bar_type)[:2])
只有确认回测目录与实盘适配器输出的类型、字段、时间戳语义一致,才能进入下一阶段的策略迁移。数据类型选错,后续所有回测结论都会失去参考价值。