十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nautilus Trader 合成工具(Synthetic Instruments)完全指南:公式语言、创建流程与性能原理

Nautilus Trader 合成工具(Synthetic Instruments)完全指南:公式语言、创建流程与性能原理 Nautilus Trader 合成工具Synthetic Instruments完全指南公式语言、创建流程与性能原理【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader合成工具Synthetic Instrument是 Nautilus Trader 平台中的一类本地定义工具其价格由其他一个或多个真实工具通过一段派生公式计算得出并以标准 Nautilus 工具的形式暴露给策略层交易所代码固定为SYNTH。本文以 docs/concepts/synthetics.md 为核心骨架结合crates/model/src/instruments/synthetic.rs、crates/model/src/expressions/表达式引擎与数据引擎订阅逻辑系统讲解公式语言语法、运算符优先级、内置函数、类型规则、编译期限制、创建与更新流程、仿真订单触发emulation trigger以及热路径性能。读完本文你将能够自行编写并接入价差spread、加权平均、条件输出等合成工具并理解其底层编译一次、求值多次的零分配求值架构。合成工具不是用于直接交易的它存在于平台本地是纯分析工具。其典型用途包括让DataActor与Strategy订阅由派生价格产生的行情或成交流、从派生价格触发仿真emulated订单、以及基于合成行情构建 K 线。Nautilus 未来可能会支持基于合成工具行为直接交易其组成工具但当前版本不提供此能力。合成工具的核心概念从源码结构看SyntheticInstrument在 crates/model/src/instruments/synthetic.rs 中定义其公共字段包括id: InstrumentId唯一标识形如{symbol}.SYNTHprice_precision: u8与price_increment: Price价格精度与最小价格增量由精度推导见new_checked中对Price::from_mantissa_exponent_checked(1, -price_precision, price_precision)的调用components: VecInstrumentId组成工具的 ID 列表formula: String派生公式原文ts_event/ts_init事件时间与初始化时间纳秒级 Unix 时间戳。此外还有两个私有字段component_names与compiled_formula前者是组件 ID 的字符串列表后者是公式编译后的字节码。构造时build_checked/new_checked会完成公式校验与编译反序列化Deserialize时也会重新编译保证加载即校验。一个关键实现细节是组件绑定在 crates/model/src/expressions/mod.rs 的Bindings结构中维护——纯标识符字母、数字、下划线走哈希表 O(1) 查找包含/、-、.等特殊字符的 ID 则按首字符分组、按名称长度降序排序采用最长匹配策略解析这正是公式可以直接书写AUD/USD.SIM、ETH-USDT-SWAP.OKX这类 ID 的原因。公式语言Formula Language每个合成工具都定义一段派生公式。Nautilus 用内置数值表达式引擎求值公式并把最终数值结果转换为合成工具的Price。公式支持引用组件InstrumentId原文包括含/与-的 ID。支持的语法构造示例说明组件引用BTCUSDT.BINANCE直接使用原始InstrumentId文本组件引用AUD/USD.SIM含/的 ID 合法组件引用ETH-USDT-SWAP.OKX含-的 ID 合法数值字面量1、0.5、1.2e-3按f64语义求值布尔字面量true、false用于条件与逻辑表达式括号(a b) / 2覆盖默认优先级一元运算符-x、!flag一元-取负、一元!取反二元运算符 - * / % ^、 !、 、 \|\|算术作用于数值逻辑作用于布尔局部赋值spread a - b; spread / 2语句从左到右执行公式必须以一个值结尾注释// line、/* block */注释被忽略注意新公式应使用原始InstrumentId。为了向后兼容把组件 ID 中的-替换为_的旧式公式仍然被接受——这对应源码 crates/model/src/instruments/synthetic.rs 中build_bindings为连字符 ID 注册replace(-, _)别名的逻辑测试用例test_hyphenated_instrument_ids_support_legacy_sanitized_formula验证了这一点。运算符优先级表达式引擎按下表从高到低求值级别运算符说明最高^幂运算右结合一元-、一元!-2 ^ 2求值为-(2 ^ 2)*、/、%乘法、除法、取模、-加法、减法、、、数值比较、!相等/不等两侧类型必须一致最低、\|\|布尔运算符赋值不是表达式运算符。语句之间用;分隔最后一条语句必须是合成工具要产出的值。内置函数函数签名说明absabs(x)绝对值ceilceil(x)向上取整floorfloor(x)向下取整roundround(x)按 Rustf64规则四舍五入到最近整数minmin(x1, x2, ...)接受一个或多个数值参数maxmax(x1, x2, ...)接受一个或多个数值参数ifif(condition, when_true, when_false)条件必须为布尔两个分支类型必须一致只求值被选中的分支类型规则组件输入是数值类型算术运算符要求数值操作数并返回数值、、、要求数值操作数并返回布尔与!接受任意匹配类型同为数值或同为布尔返回布尔、\|\|与一元!要求布尔操作数与\|\|会短路右侧仅在需要时才求值局部变量必须先赋值后使用局部变量名必须以 ASCII 字母或_开头其后只能包含 ASCII 字母、数字或_公式最终结果必须是数值。以赋值结尾或产出布尔结果的公式对合成工具无效——源码中compile_numeric会检查result_type()并返回NonNumericResult错误见 crates/model/src/expressions/mod.rs。编译期限制表达式引擎在编译期强制以下限制超限公式会在构造时得到明确报错限制值说明栈深度32求值栈上最多可容纳的中间值数量局部变量16最多可用的不同局部变量名数量嵌套深度128最大语法嵌套与表达式树深度顶层表达式计为一层以上常量对应 crates/model/src/expressions/eval.rs 中的MAX_STACK 32、MAX_LOCALS 16以及 crates/model/src/expressions/parser.rs 中的MAX_EXPRESSION_DEPTH 128。一个 8 组分的加权和峰值栈深度为 3、零局部变量N 个组分的加权和会构建深度为 N 1 的表达式树因此嵌套深度限制把加权和封顶在 127 个组分。测试用例test_new_checked_rejects_excessive_expression_depth129 项1 1 ...验证了超限报错文案Expression nesting depth 129 exceeds maximum 128。公式示例# Simple spread formula BTCUSDT.BINANCE - ETHUSDT.BINANCE # Average of two FX pairs formula (AUD/USD.SIM NZD/USD.SIM) / 2 # Reuse an intermediate value formula spread BTCUSDT.BINANCE - ETHUSDT.BINANCE; spread / 2 # Conditional output formula if(BTCUSDT.BINANCE ETHUSDT.BINANCE, BTCUSDT.BINANCE, ETHUSDT.BINANCE)创建合成工具创建前请确保所有组件工具都已存在于缓存cache中并同时订阅每个组件的报价或成交流以及合成工具自身的流。合成报价只由组件报价推导合成成交只由组件成交推导。当某个组件 tick 到达时引擎会把该 tick 与其他组件最新的缓存价格组合起来计算合成价格。在所有组件都至少产生过一个 tick 之前合成工具不会发布任何东西。下面的示例在一个 actor 或 strategy 中创建合成工具表示 Binance 上 BTC 与 ETH 现货的简单价差并假定BTCUSDT.BINANCE与ETHUSDT.BINANCE已存在于缓存from nautilus_trader.model import SyntheticInstrument btcusdt_binance_id InstrumentId.from_str(BTCUSDT.BINANCE) ethusdt_binance_id InstrumentId.from_str(ETHUSDT.BINANCE) synthetic SyntheticInstrument( symbolSymbol(BTC-ETH:BINANCE), price_precision8, components[ btcusdt_binance_id, ethusdt_binance_id, ], formulaf{btcusdt_binance_id} - {ethusdt_binance_id}, ts_eventself.clock.timestamp_ns(), ts_initself.clock.timestamp_ns(), ) self._synthetic_id synthetic.id self.add_synthetic(synthetic) self.subscribe_quotes(self._synthetic_id)注意上例中合成工具的instrument_id是{symbol}.SYNTH即BTC-ETH:BINANCE.SYNTH。这与源码SyntheticInstrument::new_checked中InstrumentId::new(symbol, Venue::synthetic())的构造逻辑一致。price_precision决定合成价格的精度与最小增量例如精度 8 时最小价格增量为1e-8源码中由Price::from_mantissa_exponent_checked推导test_new_checked_constructs_exact_price_increment用例对精度 0、5、FIXED_PRECISION均做了验证。从数据引擎源码看订阅行为是分类的SubscribeCommand::Quotes/Trades且instrument_id.is_synthetic()时进入subscribe_synthetic_quotes/subscribe_synthetic_trades分支而合成工具的Instrument、InstrumentStatus、InstrumentClose订阅会被直接拒绝见 crates/data/src/engine/mod.rs。更新公式合成公式可以随时更新synthetic self.cache.synthetic(self._synthetic_id) new_formula (BTCUSDT.BINANCE ETHUSDT.BINANCE) / 2 synthetic.change_formula(new_formula) self.update_synthetic(synthetic)源码中change_formula会针对现有组件重新编译公式编译失败则返回错误且不修改原公式测试test_change_formula_rejects_invalid_formula_without_mutation验证了失败时公式与计算结果均保持原样。update_synthetic是 actor/strategy 层的公开接口crates/common/src/actor/data_actor.rs中的update_synthetic委托给核心组件且要求合成工具已注册见test_update_synthetic_panics_when_unregistered。触发仿真订单Trigger Instrument ID可以用合成价格触发仿真订单。下面的示例中一旦合成价格达到触发条件合成工具就释放一个仿真订单order self.order_factory.limit( instrument_idInstrumentId.from_str(ETHUSDT.BINANCE), order_sideOrderSide.BUY, quantityQuantity.from_str(1.5), pricePrice.from_str(30000.00000000), emulation_triggerTriggerType.DEFAULT, trigger_instrument_idself._synthetic_id, ) self.submit_order(order)这里订单的instrument_id是真实工具ETHUSDT.BINANCE而trigger_instrument_id指向合成工具。相关文档可继续阅读 Orders其中说明订单可以使用合成工具 ID 作为仿真触发条件。性能公式在构造时编译一次然后在每个到来的组件价格 tick 上求值。表达式引擎采用编译一次、求值多次compile-once/eval-many架构配合零分配的f64栈let mut stack [0.0_f64; MAX_STACK]的定长内联栈见 crates/model/src/expressions/eval.rs求值对 tick 处理路径的额外开销可以忽略不计。以下数据在 Apple M4 Pro、rustc 1.94.1、release profileopt-level 3下测得求值热路径公式模式耗时(A B) / 2.012 nsA * 0.4 B * 0.3 C * 0.2 D * 0.118 nsif(A B, A - B, B - A)12 nsspread A - B; mid ...; mid ...19 nsmax(min(A, B * 20), abs(A - B))15 ns求值扩展性加权和组件数耗时214 ns418 ns828 ns编译冷路径公式模式耗时简单平均675 ns4 输入加权1.4 us条件式1.0 us含局部变量1.3 us连字符 ID755 ns从求值扩展性可以看出组件数翻倍带来的开销增量很小2→4→8 组件为 14→18→28 ns与零分配栈式求值 输入槽位直接装载的实现方式吻合。编译器在eval::compile阶段还会做常量折叠等优化例如Instruction::PushNumber与PushBool直接将字面量压栈。错误处理Nautilus 在每一个边界都会校验合成工具编译期公式编译会拒绝未知符号、类型错误与容量超限。例如引用未在components中声明的标识符会得到 Unknown symbolmissing 错误见 crates/model/src/expressions/error.rs 与合成工具测试用例。求值期求值会拒绝错误的输入数量与非有限价格NaN、Infinity。输入数量不匹配返回InputCountMismatchExpected 2 input values, received 1缺失组件价格返回MissingInputMissing price for component: ...非有限输入返回NonFiniteInput若公式结果无法构成合法Price则返回InvalidPriceResult。所有错误类型定义在 crates/model/src/instruments/synthetic.rs 的SyntheticInstrumentError中。除了求值校验calculate还会对组件名称与输入值逐项做有限性检查且calculate_from_map在组件数超过 8MAX_INLINE_COMPONENTS时会回退到堆分配路径保证大组件集同样可用。合成工具的输入要求与异常详见SyntheticInstrument的 API 参考模型工具 API。关联阅读Instruments工具定义与各交易所工具类型Data引用工具的市场数据类型Orders订单可使用合成工具 ID 作为仿真触发条件上述内容中公式语言、创建/更新流程、触发与性能数据均直接继承自 docs/concepts/synthetics.md表达式引擎的栈/局部变量/嵌套限制常量、绑定解析策略、求值期错误类型与编译一次求值多次的实现均由仓库源码 crates/model/src/expressions/、crates/model/src/instruments/synthetic.rs 与 crates/data/src/engine/mod.rs 印证。【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表