NautilusTrader Rust 如何编写能提交订单的 Strategy?
2026/9/12 16:31:40 网站建设 项目流程

NautilusTrader Rust 如何编写能提交订单的 Strategy?

【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader

在 NautilusTrader 中,Strategy 是在 Actor 基础上扩展出来的组件:它除了接收行情数据,还能通过Strategytrait 的方法向交易场所提交、修改和撤销订单。本文的任务是写一个纯 Rust 的最小 Strategy——订阅QuoteTick报价,在每笔报价到达时构建一个市价单并调用submit_order提交——然后把它挂到回测引擎上跑通,确认订单链路可用。适用前提:Rust 工具链满足最低版本 MSRV1.98.1,Nautilus 各 crate 已发布到 crates.io(当前文档给出的版本线为0.63),全程不需要 Python 运行时。Rust API 处于活跃开发中,方法签名和 trait 要求可能随版本变化,以你所依赖的版本文档为准。

准备条件:添加 crate 依赖

Nautilus 的 crate 位于仓库的crates/目录,外部项目通过 crates.io 引用。在Cargo.toml中加入:

[dependencies] nautilus-backtest = "0.63" nautilus-common = "0.63" nautilus-execution = "0.63" nautilus-model = { version = "0.63", features = ["test-support"] } nautilus-trading = { version = "0.63", features = ["examples"] } anyhow = "1" log = "0.4"

两个 feature flag 的作用(来自 Rust 概念指南 的 Feature flags 表):

  • test-supportnautilus-model):提供测试 fixture、builder、spec 和默认值,示例中的模拟合约 stub 依赖它。
  • examplesnautilus-trading):启用示例策略EmaCrossGridMarketMaker,后面验证环节会用到。

如果做加密市场,需要在nautilus-model上额外开启high-precision(默认 9 位精度,加密场所价格小数位更多时文档要求开启)。

如果希望跟踪最新开发分支,需把所有 Nautilus 依赖指向同一个 git 源,避免 crates.io 与 git 版本之间出现类型不匹配;本文主路径使用 crates.io 版本。

定义 Strategy 结构体:持有StrategyCore

Strategy 结构体必须持有一个StrategyCore字段,用于运行期接线。常规策略逻辑不直接使用该字段,而是通过self上的 facade 方法访问运行时:

use nautilus_common::actor::DataActor; use nautilus_model::{ data::QuoteTick, enums::OrderSide, identifiers::{InstrumentId, StrategyId}, types::Quantity, }; use nautilus_trading::{nautilus_strategy, strategy::{Strategy, StrategyConfig, StrategyCore}}; pub struct MyStrategy { core: StrategyCore, instrument_id: InstrumentId, trade_size: Quantity, }

构造函数中,StrategyConfig接收两个关键字段:strategy_idorder_id_tag。tag 会追加到本策略发出的所有 client order ID 上,用于在多个策略交易同一标的时避免 ID 冲突。文档对 tag 有一个硬性限制:tag 不能包含连字符,因为运行时会从 strategy ID 最后一段以连字符分隔的部分把它读回来。StrategyCore::new遇到非法 tag 会 panic;希望以错误方式处理时改用StrategyCore::new_checked

impl MyStrategy { pub fn new(instrument_id: InstrumentId) -> Self { let config = StrategyConfig { strategy_id: Some(StrategyId::from("MY_STRAT-001")), order_id_tag: Some("001".to_string()), ..Default::default() }; Self { core: StrategyCore::new(config), instrument_id, trade_size: Quantity::from("1.0"), } } }

nautilus_strategy!宏接线并实现Debug

nautilus_strategy!宏生成注册和Strategytrait 实现所需的 native runtime 接线,默认委托给名为core的字段,字段名不同时传第二个参数。宏还额外提供config()方法,返回传给StrategyCore::newStrategyConfig

运行期注册依赖 blanket 的ActorComponent实现,它们要求 native 接线(宏负责)和Debug(自己实现或 derive):

nautilus_strategy!(MyStrategy); impl std::fmt::Debug for MyStrategy { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MyStrategy").finish() } }

注意宏不会让 Strategy 或其StrategyCore自动 deref 到运行时内部,core字段不要直接当 API 用。

实现DataActor并调用submit_order提交订单

数据部分与 Actor 完全一致:在on_start里订阅,在 handler 里响应。提交订单的关键就两步——self.order()构建订单,self.submit_order发出:

impl DataActor for MyStrategy { fn on_start(&mut self) -> anyhow::Result<()> { self.subscribe_quotes(self.instrument_id, None, None); Ok(()) } fn on_quote(&mut self, quote: &QuoteTick) -> anyhow::Result<()> { let order = self.order().market( self.instrument_id, OrderSide::Buy, self.trade_size, None, None, None, None, None, None, None, ); self.submit_order(order, None, None, None)?; Ok(()) } }

self.order()返回的OrderApi可构建的订单类型包括:marketlimitstop_marketstop_limitmarket_to_limitmarket_if_touchedlimit_if_touchedtrailing_stop_markettrailing_stop_limitbracketcreate_list,另有generate_client_order_idgenerate_order_list_idsubmit_order通过宏生成的Strategytrait 实现挂在self上。

仓库内的完整示例 EmaCross 展示了带注释的市价单提交写法:enter()方法里self.order().market(...)的参数依次为time_in_forcereduce_onlyquote_quantityexec_algorithm_idexec_algorithm_paramstagsclient_order_id,随后调用self.submit_order(order, None, None, None)nautilus_strategy!(EmaCross)Debug实现的位置、形态与上文一致,可直接对照。

覆盖订单事件钩子,观察提交结果

Strategytrait 的订单事件 handler(如on_order_rejectedon_order_filledon_order_canceled)通过宏的第二个参数块传入。宏自动生成内部管道,DataActorhandler 保持在单独的impl DataActor块中:

nautilus_strategy!(MyStrategy, { fn on_order_rejected(&mut self, event: OrderRejected) { log::warn!("Order rejected: {}", event.reason); } });

这是文档给出的直接观察订单结果的手段:订单被拒时会输出拒绝原因日志。Strategytrait 提供的完整订单管理 facade 如下:

方法作用
submit_order向场所提交新订单
submit_order_list提交一组条件订单
modify_order修改价格、数量或触发价
modify_orders批量修改同一标的的多个订单
cancel_order撤销指定订单
cancel_orders按过滤条件撤销一组订单
cancel_all_orders撤销某标的的全部订单
close_position用市价单平掉一个仓位
close_all_positions平掉全部未平仓位

挂到回测引擎上运行验证

策略写好后,用低层级BacktestEngine注册并运行即可验证整条订单链路。流程:创建引擎 →add_venue加模拟场所 →add_instrument加合约并add_data加载数据 →add_strategy注册策略 →run

use nautilus_backtest::{config::{BacktestEngineConfig, SimulatedVenueConfig}, engine::BacktestEngine}; use nautilus_model::{ enums::{AccountType, BookType, OmsType}, identifiers::Venue, instruments::{Instrument, InstrumentAny, stubs::audusd_sim}, types::Money, }; let mut engine = BacktestEngine::new(BacktestEngineConfig::default())?; engine.add_venue( SimulatedVenueConfig::builder() .venue(Venue::from("SIM")) .oms_type(OmsType::Hedging) .account_type(AccountType::Margin) .book_type(BookType::L1_MBP) .starting_balances(vec![Money::from("1_000_000 USD")]) .build()?, )?; let instrument = InstrumentAny::CurrencyPair(audusd_sim()); let instrument_id = instrument.id(); engine.add_instrument(&instrument)?; engine.add_data(quotes, None, true, true)?; // quotes 为你的行情数据加载结果 engine.add_strategy(MyStrategy::new(instrument_id))?; engine.run(None, None, None, false)?;

SimulatedVenueConfig使用 builder 模式,只有必填字段需要设置,其余回退到文档化默认值;build()会校验配置并返回结果,需要传播或 unwrap。运行不报错即说明策略注册、数据分发和订单提交链路走通;订单层面的反馈(如拒单原因)通过上文的on_order_rejected日志观察。

不想自己写 main 时,可以跑仓库现成的示例验证环境与订单链路(EmaCross本身就是一个会提交市价单的 Strategy):

cargo run -p nautilus-backtest --features examples --example engine-ema-cross

对应源码在 engine_ema_cross.rs:它用合成 AUD/USD 报价在SIM场所上回测EmaCrossengine.run(None, None, None, false)?后以Ok(())正常退出。高层BacktestNode路径(从 Parquet catalog 流式读数据,需nautilus-backteststreamingfeature)运行命令为:

cargo run -p nautilus-backtest --features examples,streaming --example node-ema-cross

源码见 node_ema_cross.rs。两条路径的详细步骤见 Run a Backtest (Rust)。

限制与下一步

  • 常规策略代码不要导入DataActorNativeStrategyNative,也不要直接调用core()strategy_core_mut()order_factory()这类 native handle——它们暴露的是借用态运行时状态,只在引擎、注册、PyO3、testkit 或明确追求低延迟的 native 代码中使用(适用矩阵见 Rust 概念指南 的 Native traits 一节)。
  • Rust 编写的 Strategy 除了回测,还可以挂到LiveNode对接真实场所,LiveNode路径下用node.add_strategy(strategy)?; node.run().await?;注册运行,各 adapter 提供自己的工厂与配置类型,完整流程见 Run Live Trading (Rust)。从 Python 侧注册内置示例策略的add_builtin_strategy路径仅用于 bundled 示例,自定义 native 策略应走纯 Rust 路径。
  • 需要更复杂行为(多档挂单、补单、仓位对冲)时,可参考仓库内置的 GridMarketMaker 与 EmaCross 两个完整示例,以及 Strategies 概念指南。

【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询