NautilusTrader:25.7k stars 的 Rust 原生量化交易引擎,把 "回测赚钱实盘亏钱" 的坑彻底填了

最近在 GitHub trending 看到 NautilusTrader 的时候我愣了一下 —— 这是我当年还在交易团队里最想要、但又最不可能自己写出来的东西:把量化研究的 Python 灵活性和生产级交易系统的 Rust 性能、确定性、类型安全,真正塞进同一个二进制里。

讲真,过去十年我在交易团队见到的最经典灾难,不是策略不行,而是回测赚钱实盘亏钱。同一个想法,研究员用 pandas 在 notebook 里跑出一张漂亮的 equity curve,部署到生产后却被滑点、撮合顺序、时钟漂移、订单状态不一致这些” 小问题” 反复摩擦,最后净收益砍半,运气不好直接爆仓。根因不是策略,是研究环境与生产环境不是同一套代码、不是同一套时间模型、不是同一套撮合语义

Nautech Systems 团队从 2018 年开始写 NautilusTrader(GitHub),目标就一句话:用 Rust 原生的事件驱动引擎做底层,把 Python 当控制面,让一份策略代码从研究、模拟到实盘零修改地跑过去。现在它已经是 25.7k stars、3.4k forks、v1.231.0 Beta 的成熟开源项目,并且从 8 月 2 日的 1.231.0 开始,v1 正式进入” 最后维护期”,v2 Rust + PyO3 runtime 已经升到 release-candidate—— 简单说,就是这个项目要把底层彻底翻新一遍。

今天这篇文章,我就想带着” 全栈 + 大模型 + 数字游民” 三重背景聊一聊,为什么我会把 NautilusTrader 列入” 近期最值得拆解的开源项目” 之一,以及为什么它和我之前拆过的 vibe-trading、ai-berkshire 完全不是一个物种。


一、项目背景:为什么需要一个 Rust + Python 混合的交易引擎

量化交易系统有两个世界。

一个是研究世界。研究员习惯 Python、pandas、polars、jupyter notebook、matplotlib,回测逻辑可能是这样:

1
2
3
4
5
6
df = pd.read_csv("btc_1m.csv")
df["ma_fast"] = df["close"].rolling(20).mean()
df["ma_slow"] = df["close"].rolling(100).mean()
df["signal"] = (df["ma_fast"] > df["ma_slow"]).astype(int).shift(1)
df["ret"] = df["close"].pct_change() * df["signal"]
print(df["ret"].sum())

这种向量化回测写起来很快、调试也方便,但它和真实的撮合差距巨大 —— 没有撮合、没有订单状态、没有延迟、没有时钟漂移、没有滑点、没有拒单、没有部分成交、没有 margin call。很多新手量化交易员就死在这:以为这是” 回测”,其实是” 事后看图”。

另一个是生产世界。真正能稳定跑钱的交易系统,绝大多数都是事件驱动架构:C++/Java/Rust 写的核心,吃行情事件、订单事件、定时器事件,按确定性的时钟推进状态机。Bloomberg 终端、各大券商的 FIX 引擎、Jane Street 的 OCaml 基础设施、Stripe 的 Ruby+Rust hybrid,几乎都是这个套路。

这两个世界之间,通常需要一道” 翻译墙”:研究员把 Python 写出来的策略,工程师用 C++ 重写一遍,重写过程中顺便修了无数 bug(也顺便引入了无数 bug)。这套流程的代价就是 research-to-live divergence—— 回测与实盘脱节,最后的策略效果被打折。

Nautech Systems 的解法是:不要翻译墙,引擎本身用 Rust 写,但要能被 Python 直接调用。具体做法:

  • Rust 内核负责:事件循环、时钟、撮合、缓存、消息总线、订单状态机、确定性回放。
  • Python 通过 PyO3 调用 Rust 内核,做策略逻辑、组合配置、可视化。
  • 一份 Python 策略文件,在 BacktestEngine 里跑出回测曲线,直接在 LiveNode 里挂到实盘 —— 不需要重写一行代码

这听起来理所当然,但要在不牺牲性能的前提下做到,是个相当难的工程问题。NautilusTrader 8 年下来确实啃下来了:25.7k stars,OpenSSF Scorecard 贴牌,SLSA + Sigstore 三件套齐全,可信度拉满。

而且它现在还赶上一波”AI 训练交易 Agent” 的风口 ——README 里直接写了 “Engine fast enough to train AI trading agents (RL/ES)”,Rust 内核让 RL/ES 训练速度比纯 Python 快一个数量级。


二、核心功能:让一份策略代码跑遍回测、模拟、实盘

NautilusTrader 把自己的功能矩阵列得很清楚,我挑几个真正戳中我” 工程审美” 的地方讲。

2.1 Rust 原生核心 + mimalloc + tokio

Fast: Rust core with the mimalloc allocator and asynchronous networking using tokio.

这是它的性能基石。Rust 内核 + mimalloc 高性能内存分配器 + tokio 异步网络栈,意味着同一个 binary 既能跑回测(CPU bound)、也能跑实盘(IO bound)。MSRV = 1.97.1,几乎贴着最新 stable Rust 走 —— 团队在 Rust 新特性上的态度是” 用了再说”,这也意味着代码里能看到 let-else、GAT、trait alias 这些相对现代的 Rust 写法。

2.2 128-bit 价格与数量精度

交易系统最阴险的 bug 之一是浮点精度塌陷。你在 Python 里 0.1 + 0.2 都得吐 0.30000000000000004,更别说在订单簿里累加几千次成交。NauteilusTrader 提供两种精度模式:

  • High-precision: 128-bit 整数,最多 16 位小数。
  • Standard-precision: 64-bit 整数,最多 9 位小数。

默认情况下 Python 官方 wheel 走 128-bit 模式(所有支持的平台)。Rust crate 默认 64-bit,要 128-bit 就在 Cargo.toml 里加 feature flag。这个细节对加密货币、外汇这种” 小数点后 8 位就有意义” 的资产非常关键。

2.3 同一份代码、同一套撮合语义

这是 NautilusTrader 的灵魂。Python 写的策略,用 BacktestEngine 跑回测得到的订单簿填充、滑点假设、撮合结果 —— 和挂到 LiveNode 跑实盘时的撮合行为是同一套 Rust 代码在执行。没有” 研究用一份撮合、生产用另一份撮合” 这种灾难

策略从研究到部署是 0 改动(pip install -U nautilus_traderBacktestEngine(...).run() 改成 TradingNode(...).run() 完事),这种 research-to-live parity 在 NautilusTrader 的 README 里被反复强调。

2.4 全套订单类型与执行指令

专业交易系统的硬指标是支持的订单类型。NautilusTrader 的清单:

  • Time in force: IOC, FOK, GTC, GTD, DAY, AT_THE_OPEN, AT_THE_CLOSE
  • Execution instructions: post-only, reduce-only, icebergs。
  • Contingency orders: OCO, OUO, OTO

这套覆盖基本上把专业做市商、套利策略需要的单子全包了。一个 reduce-only 标志就能避免对冲策略不小心开新仓 —— 这是新手工程师手撸交易所 API 时最容易踩的坑。

2.5 多 venue、多资产类别同时运行

Multi-venue: Run market-making and cross-venue strategies across multiple venues simultaneously.

它可以同时连 Binance 做市、连 dYdX 套利、连 Interactive Brokers 跑美股、连 Polymarket 玩预测市场、连 Betfair 玩体育博彩。一个进程同时调度多个策略实例,每条腿的行情、订单、状态独立追踪。我自己写过多 venue 系统,知道光是” 几个时钟同步、订单路由、状态归一” 就够喝一壶的。

2.6 集成 16+ 交易所与数据源(截至本文撰写)

这是让我真正惊讶的部分。NautilusTrader 不是一个” 理论框架”,它已经把主流交易所全接通了:

  • 加密 CEX: Binance、BitMEX、Bybit、Coinbase、Kraken、OKX。
  • 加密 DEX: dYdX、Hyperliquid、Lighter、Derive(以及 UniswapV3 / PancakeSwapV3 / Aerodrome 等 BSC / Base 链上协议,v1.228.0 起)。
  • 传统券商: Interactive Brokers(股票、期货、期权一站搞定)。
  • 预测市场: Polymarket。
  • 体育博彩: Betfair。
  • 数据源: Databento、Tardis(这两个都是专业级历史 tick 数据供应商,按 GB 卖数据那种)。

每个 adapter 都通过统一的 domain model 暴露 —— 也就是说你写一个策略,调 submit_order(order) 时不关心底下是 Binance 还是 IB。这对个人量化交易员是巨大的节省时间:我以前自己接一个交易所就要 1-2 周,团队接一遍 16 家交易所基本是” 半年工程”。

2.7 零代码 AI 训练支持

README 里有一句被很多人忽略但其实非常关键的话:

AI Training: Engine fast enough to train AI trading agents (RL/ES)。

Rust 内核的事件循环确定性 + 纳秒级时间戳 + 模块化缓存,意味着你可以把 NautilusTrader 当成一个超快的交易模拟器,让 RL 或 Evolution Strategies Agent 一天跑几百万次 episode—— 而且是带真实撮合、真实滑点模型的模拟,不是 numpy 写的” 事后看图”。这才是 v2 路线图里”AI/ML tooling out of scope for the open-source project” 的真正含义 —— 他们把 AI 训练钩子留给上游,但保证引擎够快,够让 RL 飞起来。


三、技术架构 / 实现亮点

说几个我个人在审这种项目时最关注的工程亮点。

3.1 Rust + PyO3 的分层

NautilusTrader 的代码组织是典型的工作区(workspace)布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
crates/
├─ core/ # 核心类型、UUID、时钟、确定性原语
├─ model/ # 领域模型:Price、Quantity、Money、Order、Trade
├─ common/ # 跨模块共享:消息、组件生命周期
├─ network/ # tokio 网络栈、HTTP/WS 客户端
├─ persistence/ # 状态序列化、Redis 后端
├─ indicators/ # EMA、ATR、MACD 等(通过 PyO3 暴露给 Python)
├─ strategy/ # 策略引擎
├─ backtest/ # BacktestEngine
├─ trading/ # TradingNode / LiveNode
├─ adapters/ # 16+ 交易所实现
python/
└─ nautilus_trader/ # Python 包封装,PyO3 stub

这种分层让 Rust 内核保持纯粹 —— 所有高性能路径不经过 Python GIL,而 Python 端只是策略逻辑、可视化、配置。一个量化交易员可以在 Python 里写一个 EMA crossover 策略跑回测,rustc 这边把 indicators::Ema 直接导出给 Python,调用开销和写 Python 内置 list 一样低。

3.2 确定性事件循环

A Rust-native core provides a deterministic event-driven runtime for both research and live execution.

事件驱动不是新概念,但” 确定性” 是。NautilusTrader 的事件循环用一个统一的 Clock 抽象 —— 回测时用 TestClock(按历史时间戳喂数据),实盘时用 LiveClock(挂 wall clock + 行情延迟)。所有策略组件订阅同一个 MessageBus,所有状态写到同一个 Cache。这就意味着:

  • 回测里” 如果 14:30:01.123456789 收到一个 trade 事件,14:30:01.123456790 触发一个订单提交”,实盘里这个时序完全一致。
  • 没有”Python 那边 GIL 卡了 50ms 导致订单晚到” 这种事。
  • 回放调试时,你可以把所有 tick 数据按 nanosecond 重放,bug 复现概率 100%。

这就是为什么专业做市商团队愿意花大价钱自建 Rust 内核 —— 交易所那边是纳秒级撮合,你这边要是毫秒级抖动,对手就薅你

3.3 三分支模型 + 双周发布节奏

仓库采用三分支:

  • master: 最新 released 版本,生产环境推荐。
  • nightly: 每天 14:00 UTC 由 develop 自动合入,相当于 daily snapshot。
  • develop: 活跃开发分支,PR 默认目标。

发布节奏是双周一次(小特性可以更快)。每个 wheel 都打上 SLSA build provenance、每个 Docker image 都用 Sigstore cosign 签名。开发者还提供两个独立的 package index:

  • 官方 PyPI: pip install -U nautilus_trader
  • Nautech Systems 私有 index: 支持 v2 release-candidate wheels,比如 pip install -U nautilus_trader --pre --index-url=https://packages.nautechsystems.io/simple

这种” 官方 PyPI + 私有 index + nightly + develop” 四层分发,是典型的基础设施级 open-source 项目做法。

3.4 OpenSSF Scorecard + SLSA + Sigstore 三件套

我之前写过 vibe-coding-security 那一篇,提过” 开源不是免审代码就完事”。NautilusTrader 在供应链安全上的投入是教科书级的:

  • OpenSSF Scorecard 跑分公开,README 直接挂徽章。
  • SLSA Build Provenance 给所有 Python wheel 和 sdist—— 证明 artifact 是 GitHub Actions 跑出来的,没被中间人改过。
  • Sigstore cosign 给所有 Docker image(ghcr.io/nautechsystems/nautilus_traderjupyterlab)做 keyless 签名 + SPDX SBOM。
  • PyPI / crates.io 用 OIDC Trusted Publishing,发布环境是 protected branch,永不跑 PR 代码。
  • cargo-vet 审计 Rust 依赖来源,cargo-audit / cargo-deny / OSV Scanner / pip-audit 定期扫漏洞。
  • Gitleaks 预提交扫描密钥,CodeQL 跑 PR 安全分析,Zizmor Actions 审计 workflow 自身。
  • Ed25519 signing(aws-lc-rs + ed25519-dalek)做运行时签名。

对一个会真的拿真金白银挂上去跑的系统,这种安全姿态是必须的。坦白讲,我看到这块的时候是服气的 —— 很多被吹成” 生产级” 的金融开源项目连 SBOM 都没有。

3.5 v1 → v2 的过渡:Rust 原生 runtime

v1 的核心是 Cython 写的,v2 完全用 Rust 重写并通过 PyO3 暴露给 Python。从 v1.229.0 开始,Python 和 Rust 的 v2 API 已经有多处 breaking change;从 v1.231.0 开始,v1 进入” 最终维护期”,除非有严重 blocker 否则不再发新版。迁移路径在 MIGRATION_V2.md 里有详细说明。

我个人对这个过渡非常期待 ——v2 真正做到” 零 Python GIL 路径”,意味着策略即使复杂也不会卡内核。但过渡期确实有点痛,团队把 develop_v1 分支留着只接 critical security backport,算是给企业用户留个安全网。


四、怎么用 / 快速上手

我个人没真在生产里挂过 NautilusTrader(合规和资金量都不够),但本地跑回测是认真做过的,体验非常顺。

4.1 安装:两条路

路 1:从 PyPI 装 wheel(推荐)

1
2
python -m venv .venv && source .venv/bin/activate
pip install -U nautilus_trader

路 2:装 v2 release-candidate

1
pip install -U nautilus_trader --pre

团队推荐用 uv 管理 Python 环境,我自己也是 uv 重度用户,这点审美一致。Conda 和其他发行版可能能跑但官方不背书。

要带可视化(tearsheet / 图表)就加 extras:

1
pip install -U "nautilus_trader[visualization]"

4.2 写一个 EMA crossover 回测

crates/backtest/examples/engine_ema_cross.rs 里有一个 Rust 写的 EMA crossover 例子,但更典型的是 Python 写法。我把官方示例的精髓简化一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.indicators import ExponentialMovingAverage
from nautilus_trader.model.data import Bar
from nautilus_trader.model.enums import OrderSide
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.model.objects import Price, Quantity
from nautilus_trader.examples.strategies.ema_cross_tester import EMACrossTester
from nautilus_trader.examples.strategies.ema_cross_tester import EMACrossTesterConfig

# 1) 配置回测引擎
config = BacktestEngineConfig(
trader_id="DAISL-001",
strategies=[
StrategyConfig(
strategy_id="EMA-20-100",
class_name="EMACrossTester",
config_path="config.yaml",
),
],
)

engine = BacktestEngine(config=config)

# 2) 添加交易所 / 行情 / 数据
venue = add_binance_venue(engine)
instrument = add_binance_instrument(engine)
add_binance_bar_data(engine, instrument_id=instrument.id)

# 3) 注册策略
config = EMACrossTesterConfig(
instrument_id=instrument.id,
bar_type=BarType.from_str("BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL"),
fast_ema_period=20,
slow_ema_period=100,
trade_size=Decimal("0.01"),
order_id_tag="001",
)
strategy = EMACrossTester(config=config)
engine.add_strategy(strategy=strategy)

# 4) 跑回测
engine.run()

# 5) 拉报告
with engine.results:
report = engine.results.get()
print(report.total_pnl())
print(report.stats_pnl())

注意几个细节:

  • BarType 用字符串组合(BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL),同时描述了 symbol + venue + bar 类型 + aggregation + price type—— 这是 NautilusTrader 的 “identifier as code” 哲学。
  • EMACrossTester 是个普通 Python class,不用继承什么奇怪的 framework interface。
  • instrument_idorder_id_tag 都用纯字符串 + tag,没有 magic

然后实盘怎么用?把 BacktestEngine 换成 TradingNode,调 node.add_strategy(...) + node.run(),把 Binance 的 API key 配到 config 里,完事。这就是 research-to-live parity 的实际体验。

4.3 多 venue 套利示例

NautilusTrader 的官方 examples 目录里 examples/strategies/ 有跨交易所统计套利、做市、订单簿不平衡等多个真实策略。我特别推荐翻一翻 market_maker.pyorderbook_imbalance.py,里面展示了怎么订阅多个 venue 的 quote tick、用 Cache 维护本地订单簿、用 MessageBus 跨组件广播信号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 伪代码:跨 venue 做市
for venue in [Venue("BINANCE"), Venue("OKX")]:
node.add_venue(venue)
node.subscribe_quote_ticks(instrument_id=f"BTCUSDT.{venue}-SPOT")

# 策略里:
async def on_quote_tick(self, event: QuoteTick):
# 维护本地订单簿
book = self.cache.order_book(event.instrument_id)
book.apply(event)
# 当 Binance 买一价高于 OKX 卖一价 0.05% 时,做双边
if book.best_ask(BINANCE) < book.best_bid(OKX) * 0.9995:
self.submit_order(buy_binance_order, OKX=...)
self.submit_order(sell_okx_order, ...)

这种代码在 Python 端是干净的、所有 venue 都走同一个 InstrumentIdOrderBookCache—— 对比我以前用 ccxt + 自己写的状态机,那真是降维打击。

4.4 Docker 一键 jupyterlab

1
2
docker pull ghcr.io/nautechsystems/jupyterlab:nightly --platform linux/amd64
docker run -p 8888:8888 ghcr.io/nautechsystems/jupyterlab:nightly

浏览器开 http://127.0.0.1:8888/lab 就有现成的 JupyterLab,里面有官方 backtest 示例 notebook + 数据。适合不会配环境的交易员,或者想跳过环境搭建先看效果的人。


五、总结:适用人群、局限性与我的看法

适用人群

  • 个人 / 小团队量化交易员:想用一套开源、可信、有供应链安全背书的引擎跑多资产策略。NautilusTrader 是目前开源生态里最接近” 专业级” 的选择之一。
  • AI 训练交易 Agent 的研究员:RL/ES 需要极快的事件循环做模拟,Rust 内核的纳秒级时钟 + 确定性回放正好对路。v2 RC 可以让训练脚本直接用 Python 写、env 用 Rust 跑,比纯 Python gym 强几个数量级。
  • 金融科技团队的架构师:想要一个可商用 license、清晰架构、严格 CI 的事件驱动交易基础设施参考。LGPL-3.0 让它在大多数商业场景里是可用的(动态链接即可),不像 AGPL 那种” 用了就得全开源” 的紧箍咒。
  • Rust 爱好者:想看一个真正严肃的 Rust + PyO3 项目长什么样 ——workspace 怎么组织、PyO3 怎么打包、Cargo feature flag 怎么管理。Nautech Systems 这套代码组织是教科书级。

局限性(实话实说)

  • v1 → v2 过渡期:现在(2026 年 8 月)正好在过渡的节骨眼上。v1 进入最终维护期,v2 RC 有 breaking change。如果你现在按 v1 写策略,几个月内大概率要迁移。生产环境建议先用 v1 master,但要在 issue 里关注 v2 进度。
  • 文档仍以英文为主:对中文用户来说门槛略高。但 v1.230.0 起团队在补 v2 Python visualization 和文档,建议边用边看 nautilustrader.io/docs
  • UI 仪表盘不在开源范围内:README 明确写了 “UI dashboards, distributed orchestration, and built-in AI/ML tooling are out of scope”。你要 dashboard 就得自己写或用社区方案。这是个有意为之的取舍 —— 团队要把精力集中在引擎。
  • 小资产 / 小资金量不一定划算:全套系统学习曲线不算短。如果只是炒币买现货,根本用不上 16 个 adapter 和 128-bit 精度。
  • LGPL-3.0 的合规问题:LGPL 在某些公司的法务眼里依然敏感(” 动态链接” vs “静态链接”)。如果是大型金融机构内部部署,建议让法务先过一遍。

我的看法

作为在小团队里被” 回测赚钱实盘亏钱” 坑过的人,NautilusTrader 最让我佩服的不是 stars 数量,而是对 research-to-live parity 的执念。整个项目从架构、API、CI、安全姿态全部围绕” 让回测和实盘是同一套代码、同一套时钟、同一套撮合” 展开 —— 这是真正解决过量化交易核心痛点的工程师才会有的设计哲学。

而 Rust + PyO3 的混合架构在 2026 年已经非常成熟:Rust 提供性能与确定性、Python 提供策略灵活性、PyO3 把两者无缝缝起来。这个范式完全有可能扩散到其他领域 —— 比如实时数据 pipeline、低延迟游戏服务器、量化研究 Agent 平台。事实上我最近拆过的几个 AI Agent 框架,都在朝类似方向走(Rust 内核 + Python 控制面)。

如果你:

  • 是 Java 全栈 / 系统工程师,对确定性事件循环、低延迟、可信供应链感兴趣;
  • 是 AI Agent 工程师,想找一个真实能跑 RL 训练的环境
  • 或者是数字游民 / 独立交易员,想用开源工具武装自己的小金库;

都建议把 NautilusTrader 加进你的 star list。它不一定是你立刻就要用的项目,但作为一个工程范式参考,价值很大。


GitHub: https://github.com/nautechsystems/nautilus_trader

官网 / 文档: https://nautilustrader.io

Discord 社区: https://discord.gg/NautilusTrader

如果哪天我用它跑出一个像样的策略回测,再来写一篇实战复盘。今天就到这里 —— 拜拜。