NautilusTrader 执行体系全解析:从订单提交、风险管理到成交修正的完整链路
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
导读
NautilusTrader 是一套生产级的 Rust 原生事件驱动交易引擎。执行(Execution)子系统是其核心:它负责协调订单提交、风险校验、交易所成交、对账(reconciliation)与持仓更新,让多个策略、多个交易所(venue)在同一套确定性消息流中协同工作。本文以 docs/concepts/execution/index.md 为骨架,结合 crates/execution 与 crates/risk 的源码实现,系统讲解执行链路中的各个组件、OMS 类型、风险引擎规则、取消路由、命令结果分类、订单拒绝原因码,以及超额成交(overfill)与成交修正(fill correction)等高级话题。读完本文,你将能回答"一个订单命令从策略发出到交易所成交,中间经过了哪些组件、哪几条路由、哪些校验"这一核心问题,并掌握相关的配置项与排查依据。
一、执行组件全景
执行子系统主要由以下组件构成:
| 组件 | 职责 |
|---|---|
Strategy | 交易策略,负责发起订单与执行相关的命令 |
ExecutionAlgorithm | 执行算法,负责将主订单拆分为更小的派生订单(如 TWAP) |
OrderEmulator | 订单模拟器,支持在本地模拟订单生命周期(如模拟滑点、盘口) |
RiskEngine | 风险引擎,位于提交与修改路径上,执行风险校验 |
ExecutionEngine | 执行引擎,核心编排器,管理订单、持仓与对账 |
ExecutionClient | 执行客户端,与具体交易所适配器交互,负责命令下发与事件上报 |
其中ExecutionEngine的配置结构体定义在 crates/execution/src/engine/config.rs,包含load_cache、manage_own_order_books、snapshot_orders、snapshot_positions、carry_replay_events_on_reopen、allow_overfills、external_clients等字段;RiskEngineConfig定义在 crates/risk/src/engine/config.rs,两者都是 Rust 原生实现并通过 Pyo3 绑定暴露给 Python(见 crates/execution/src/python/config.rs 与 crates/risk/src/python/config.rs)。
二、执行流程(Execution flow)
Strategy在数据 actor 能力之上,增加了管理与执行相关的方法:
submit_order(...)submit_order_list(...)modify_order(...)cancel_order(...)cancel_orders(...)cancel_all_orders(...)close_position(...)close_all_positions(...)query_account(...)query_order(...)
这些方法通过消息总线发送点对点的执行命令;订单创建时还会发布OrderInitialized等事件。策略侧的方法声明可参见 crates/trading/src/strategy/mod.rs 与 crates/trading/src/strategy/binding.rs(StrategyBinding负责把self.submit_order(...)连接到后端实现)。
2.1 命令的分流规则
不同命令走不同路由:
submit_order(...):模拟订单(emulated)路由到OrderEmulator;设置了exec_algorithm_id时路由到ExecutionAlgorithm;其余情况路由到RiskEngine。submit_order_list(...):与上面相同的分支逻辑(取决于是否模拟以及exec_algorithm_id)。modify_order(...):模拟订单路由到OrderEmulator;订单带有exec_algorithm_id且仍在本地系统中活跃时路由到ExecutionAlgorithm;其余情况路由到RiskEngine。- 取消与查询命令:根据命令与订单状态,可直接路由到
OrderEmulator、ExecutionAlgorithm或ExecutionEngine。
2.2 新订单的下游路径
新订单通常进入以下路径之一:
Strategy -> OrderEmulator 或 ExecutionAlgorithm 或 RiskEngine其下游流转为:
OrderEmulator -> ExecutionAlgorithm 或 ExecutionEngine ExecutionAlgorithm -> RiskEngine -> ExecutionEngine -> ExecutionClient用 mermaid 图表示如下(原文档图示的复现):
执行路径先按"模拟"与"算法"两个维度分支,再汇聚到执行引擎与客户端。OrderEmulator发出OrderReleased事件给RiskEngine继续走正常风险校验路径,这是模拟订单与真实订单在风险校验上的统一点。
三、订单管理系统(OMS)
订单管理系统类型(OmsType)决定了某个品种的订单如何映射到持仓。策略与交易所(无论是模拟还是实盘)各自使用OmsType枚举定义的类型。该枚举定义在 crates/model/src/enums.rs,三个变体为:
UNSPECIFIED:策略沿用交易所的 OMS 类型。NETTING:每个品种、每个策略合并为一个持仓。HEDGING:每个品种、每个策略可以同时存在多个持仓。
当策略与交易所的 OMS 类型不一致时,ExecutionEngine会在OrderFilled事件上赋值或覆盖position_id。NautilusTrader 中存在"虚拟持仓"(virtual position),但它不是交易所侧独立的持仓。
策略 OMS 与交易所 OMS 的组合结果如下:
| 策略 OMS | 交易所 OMS | 结果 |
|---|---|---|
NETTING | NETTING | 每个品种和策略一个持仓 |
HEDGING | HEDGING | 每个品种和策略多个持仓 |
NETTING | HEDGING | 跨交易所持仓合并为一个虚拟持仓 |
HEDGING | NETTING | 针对交易所单一净持仓维护多个虚拟持仓 |
如果某个成交(fill)解析到缓存中属于不同品种的持仓,ExecutionEngine会记录错误并丢弃该成交;订单保持非终态,后续合法成交仍可被应用。
3.1 OMS 配置
当策略省略oms_type或使用UNSPECIFIED时,ExecutionEngine沿用交易所的 OMS 类型,且不覆盖交易所的position_id。在回测中,应把回测交易所配置为被建模交易所所使用的 OMS 类型。
交易所的持仓模式可能需要适配器级配置,例如 Binance Futures 对冲模式。
3.2 自定义持仓 ID 与 NETTING
自定义持仓 ID 仅在HEDGINGOMS 下有效。NETTING下每个品种与策略只有一个持仓,其确定性 ID 形式为{instrument_id}-{strategy_id}。这一点在源码中有直接印证:crates/execution/src/engine/mod.rs 的determine_netting_position_id实现为PositionId::new(format!("{}-{}", fill.instrument_id, fill.strategy_id))。
ExecutionEngine在提交时强制执行该规则:如果生效的 OMS 解析为NETTING,且submit_order(或submit_order_list)传入的position_id不匹配{instrument_id}-{strategy_id},订单会被拒绝并产生OrderDenied事件说明不匹配。
这条规则仍允许常见的平仓习惯:Strategy.close_position(position)转发position.id,在NETTING下它恰好就是那个确定性 ID,因此会被接受。若想用任意 ID 标记或划分持仓,请将策略配置为oms_type=HEDGING。
对于submit_order_list,只要提供了position_id,引擎还会拒绝任何混合品种的订单列表(无论 OMS 类型)——一个持仓只属于一个品种,因此组合会被拒绝并给出明确的OrderDenied原因。混合品种订单列表的更多注意事项见 订单列表。
3.3 NETTING 周期间的持仓重放
在NETTING下,引擎在平仓与重新开仓的周期之间复用同一个持仓 ID,因此该持仓的重放日志会累积该 ID 上曾经应用过的所有成交。ExecutionEngineConfig.carry_replay_events_on_reopen控制该日志在重新开仓后是否保留:
carry_replay_events_on_reopen | 行为 |
|---|---|
False(默认) | 只保留当前周期的状态,限制每次成交的成本 |
True | 保留早期周期的成交使其可被修正,但持仓状态可能增长 |
实盘交易固定将该选项置为True:LiveExecutionEngineConfig始终携带重放日志,这样引用早期周期的交易所OrderFillVoided事件仍能被解析。模拟交易所从不发出 fill void,因此回测采用有界的默认值。当使用自定义或外部执行客户端、且它可能修正来自先前周期的成交时,需要显式启用该选项;否则引擎找不到匹配的持仓片段,会拒绝该修正。
已实现盈亏(Realized-PnL)快照会跟随修正。一个触及早期周期的 fill void 会跨周期边界重建持仓,从而移动其归档快照所描述的边界,引擎会将这些快照结算进修正后历史自身的已关闭周期中,保证已实现盈亏对每个周期只统计一次。仅局限于当前周期的 void 不会破坏归档。详见 Position snapshotting。
源码佐证:crates/execution/src/engine/config.rs 注释说明"Enable to keep fills from earlier cycles correctable by anOrderFillVoided";crates/execution/src/engine/mod.rs 中carry_replay_events_on_reopen为true时引擎会克隆先前持仓以携带跨周期的重放状态。
四、风险引擎(RiskEngine)
RiskEngine是每个 Nautilus 系统(回测、沙箱、实盘)的组成部分。它位于提交与修改路径上,同时也会收到来自OrderEmulator的OrderReleased等订单事件。取消与查询命令直接路由到其他执行组件,不经过RiskEngine。
除非在RiskEngineConfig中显式bypass,否则引擎会校验:
- 品种的价格与触发价精度。
- 价格为正(除非品种允许负价格:期权、期货价差、期权价差、现货大宗商品)。
- 数量精度与基础数量最小/最大值边界。
- GTD 订单未过期。
reduce_only订单不会增大被引用的持仓。- 引擎级
max_notional_per_order限额与品种的min_notional、max_notional字段。 - 非保证金账户的现金账户余额影响。
- 提交与修改的速率限制。
- 交易状态限制(
ACTIVE、HALTED、REDUCING)。
提交时的风险校验失败会生成带标准化 原因码 的OrderDenied事件;修改时的失败则生成OrderModifyRejected事件。
4.1 整仓条件退出(Whole-position conditional exits)
部分执行客户端支持"条件退出":触发时由交易所根据当前持仓决定平仓数量。Nautilus 的订单仍会携带一个占位数量(placeholder quantity)供本地校验。RiskEngineConfig与LiveRiskEngineConfig上的full_position_exit_venues设置用于标识执行客户端强制执行上述语义的交易所,默认为空。源码中该字段为AHashSet<Venue>,见 crates/risk/src/engine/config.rs。
订单只有在满足以下全部条件时才享有占位数量豁免:
- 订单单独提交,而非在订单列表中。
- 其交易所列于
full_position_exit_venues。 - 使用受支持的期货或永续合约品种。
- 是带触发价的
StopMarket或MarketIfTouched订单,且close_position=true。 - 占位数量为正且设置
reduce_only=true。 - 命令、订单与被引用的缓存持仓使用相同的品种与持仓 ID。
- 被引用的持仓处于开启状态、订单方向与之相反,且占位数量不超过持仓数量。
对符合条件的退出订单,风险引擎的校验处理如下:
| 风险校验 | 处理方式 |
|---|---|
| 数量精度与正数性 | 强制执行 |
| 价格与触发价精度与正数性 | 强制执行 |
| GTD 过期、交易状态限制、提交速率限制 | 强制执行 |
| 持仓敞口、保证金与余额 | 视为减仓处理 |
| 品种最小/最大数量 | 对占位数量跳过 |
| 品种最小/最大名义价值 | 对占位名义价值跳过 |
配置的max_notional_per_order | 对占位名义价值跳过 |
| 不满足条件的订单 | 全部常规风险校验照常适用 |
只有当下游执行客户端确实强制执行整仓平仓时,才应将该交易所加入白名单。受支持的配置示例见 Binance Futures 平仓订单。
:::warning 模拟交易所不会解释close_position,也不会用当前持仓数量替换占位数量。因此不要把模拟回测交易所加入full_position_exit_venues;回测退出请改用显式数量加reduce_only来建模。 :::
4.2 交易状态(Trading state)
交易状态依次变得更严格:
| 状态 | 数值 | 允许的命令 |
|---|---|---|
ACTIVE | 1 | 提交、修改、取消、查询命令正常运行 |
REDUCING | 2 | 符合条件的单独 reduce-only 提交、取消与查询 |
HALTED | 3 | 仅取消与查询,不允许新提交与修改 |
在REDUCING状态下,只有当订单设置reduce_only=true、命令与订单指向同一品种、提供的持仓 ID 与订单缓存的开启持仓一致时,单独的SubmitOrder才被允许;订单方向必须与持仓相反,且提交数量不得超过缓存持仓数量。订单列表与修改命令一律被拒绝。
风险引擎在转发命令前应用这些规则。启用RiskEngineConfig.bypass后交易状态不再被强制;执行客户端仍遵循 reduce-only send-or-reject 契约。
RiskEngineConfig的完整配置细节可参考 Python API 参考文档中的nautilus_trader.risk.RiskEngineConfig。
五、执行算法(Execution algorithms)
ExecutionAlgorithm接收由exec_algorithm_id选中的主订单(primary order),并可将其拆分为更小的派生订单(spawned orders)。NautilusTrader 支持自定义算法,并内置了原生 Rust 实现的 TWAP。
TWAP 配置、自定义算法、派生订单行为与缓存查询,详见 执行算法。
六、取消全部路由(Cancel-all routing)
Strategy.cancel_all_orders(...)支持策略范围与宽泛两种取消模式:
strategy_only | 策略输出 | 范围 | 下游路由 |
|---|---|---|---|
True | 每个匹配订单一个CancelOrder | 与调用策略关联的匹配订单 | 每个订单走其常规取消路由 |
False | 一个根CancelAllOrders(即使本地没有匹配) | 解析出的单个执行客户端与账户上的匹配订单 | 执行引擎创建所需子命令 |
宽泛模式在策略检查其缓存之前就进行委托,因此即使 NautilusTrader 本地没有匹配订单,命令也能到达解析出的执行客户端。这允许交易所的批量取消端点删除"存在于交易所但本地缓存缺失"的订单;当适配器提供此类端点时,单条命令还能减少取消请求量。
6.1 本地客户端解析顺序
对于本地执行客户端,ExecutionEngine按以下顺序把根命令解析到恰好一个客户端:
- 显式指定的
client_id(当它标识一个已注册的本地客户端时)。 - 为该品种交易所注册的客户端。
- 默认执行客户端。
随后引擎为选中的客户端及其账户创建全新的子命令:
- 一个覆盖该执行客户端匹配交易所订单的
CancelAllOrders。 - 一个覆盖
OrderEmulator匹配模拟订单的CancelAllOrders。 - 每个符合条件的活跃本地执行算法订单一个
CancelOrder。
流程如下(原文档图示的复现):
6.2 子命令与归属规则
宽泛模式在扇出之前只选择一个客户端,绝不会向所有执行客户端广播。若要在多个客户端上取消,需要对每个客户端分别调用一次cancel_all_orders(...)。
每个子命令都有新的命令 ID,复制根参数,与根操作关联,并把根命令记录为自身的 cause。品种与可选方向过滤适用于每一条本地路由。选中的执行账户还界定了匹配引擎的取消范围,包括SUBMITTED及其他可取消的在途状态订单。
客户端归属(client ownership)适用于本地模拟订单与执行算法订单:
- 已归属其他客户端的订单保持不动。
- 根命令省略
client_id时,引擎在本地取消前会把匹配的未归属订单归属给选中的客户端。 - 根命令提供
client_id时,未归属订单保持不动——引擎无法推断它们属于该显式客户端。 - 模拟订单匹配其交易品种,即使触发价来自另一个品种。
显式配置的外部执行客户端会原样收到根命令;边界之后的所有扇出由外部客户端自行负责。
七、命令结果分类(Command outcomes)
执行命令区分三类结果:确定的本地失败、确定的交易所结果、未知的实盘结果。未知结果保持"在途"状态,等待流更新、轮询、查询或对账来推进;重试耗尽后可以应用一个合成的终端对账事件。
证据类别、投递与重试限制、持久化边界、终端对账来源,详见 执行策略:命令结果;持续对账流程见 执行对账:运行时检查。
八、订单拒绝原因码(Order denied reasons)
本地拒绝(OrderDenied)携带标准化的CATEGORY_CONDITION原因码,并可能附带诊断后缀;只有前导码是规范性的。消息使用这些形式:
CODE:拒绝不需要诊断后缀。CODE: value:一个类型化值或自由文本诊断。CODE: key=value, key=value:多个类型化值需要消歧义。CODE: value; free text:一个类型化值后跟自由文本诊断。
下表覆盖执行算法与客户端以及风险、执行引擎发出的本地拒绝。这些码是本地被拒订单的事实来源。交易所确认的OrderRejected事件携带的是交易所提供的含义;合成对账拒绝使用 终端对账来源 中记录的原因。适配器在发出前会去除协议包装并限制不可信的交易所文本,而不会用标准化本地拒绝码替换它。
价格与数量校验也可以在OrderModifyRejected上发出以下带码原因:
PRICE_PRECISION_EXCEEDS_MAXIMUMPRICE_NOT_POSITIVEQUANTITY_PRECISION_EXCEEDS_MAXIMUMQUANTITY_EXCEEDS_MAXIMUMQUANTITY_BELOW_MINIMUM
对于价格类原因,field为PRICE或TRIGGER_PRICE,指明被拒的命令字段。其他修改拒绝原因保持自由文本;OrderDeniedCode不对它们分类。
OrderRejected.due_post_only仅在交易所证据证明 post-only 订单会穿过或立即成交时为true;其他交易所拒绝保持false。
下表由
OrderDeniedReason枚举(crates/model)生成。重新生成命令:cargo test -p nautilus-model regenerate_order_denied_reasons_doc -- --ignored。
| Code | Description |
|---|---|
PRICE_PRECISION_EXCEEDS_MAXIMUM | The price precision exceeds the instrument maximum. |
PRICE_NOT_POSITIVE | The price is not positive. |
QUANTITY_PRECISION_EXCEEDS_MAXIMUM | The quantity precision exceeds the instrument maximum. |
QUANTITY_CONVERSION_FAILED | The order quantity could not be converted for risk checks. |
QUANTITY_EXCEEDS_MAXIMUM | The effective order quantity exceeds the instrument maximum. |
QUANTITY_BELOW_MINIMUM | The effective order quantity is below the instrument minimum. |
INVALID_MAX_NOTIONAL_PER_ORDER | The configured maximum notional per order is invalid. |
MISSING_EXPIRE_TIME | A GTD order is missing its expire time. |
EXPIRE_TIME_IN_PAST | The order's expire time is in the past. |
MISSING_TRAILING_OFFSET_TYPE | The order is missing a required trailing offset type. |
UNSUPPORTED_TRAILING_OFFSET_TYPE | The order's trailing offset type is not supported. |
MISSING_TRIGGER_TYPE | The order is missing a required trigger type. |
MISSING_TRAILING_OFFSET | The order is missing a required trailing offset. |
INSTRUMENT_NOT_FOUND | The instrument was not found in the cache. |
POSITION_NOT_FOUND | The position for a reduce-only order was not found. |
MARKET_PRICE_UNAVAILABLE | No market price is available for the order risk check. |
TRAILING_STOP_CALCULATION_FAILED | The trailing stop trigger price could not be calculated. |
NOTIONAL_CALCULATION_FAILED | The order notional value could not be calculated. |
NOTIONAL_BELOW_MINIMUM | The order notional is below the instrument minimum. |
NOTIONAL_EXCEEDS_MAXIMUM | The order notional exceeds the instrument maximum. |
NOTIONAL_EXCEEDS_MAX_PER_ORDER | The order notional exceeds the configured maximum per order. |
NOTIONAL_EXCEEDS_FREE_BALANCE | The order notional exceeds the account free balance. |
INITIAL_MARGIN_CALCULATION_FAILED | The order initial margin could not be calculated. |
INITIAL_MARGIN_EXCEEDS_FREE_BALANCE | The order initial margin exceeds the account free balance. |
BETTING_BALANCE_LOCKED_CALCULATION_FAILED | The balance to lock for the betting order could not be calculated. |
CUMULATIVE_NOTIONAL_EXCEEDS_FREE_BALANCE | The cumulative order notional exceeds the account free balance. |
CUMULATIVE_INITIAL_MARGIN_CALCULATION_FAILED | The cumulative initial margin could not be calculated. |
CUMULATIVE_INITIAL_MARGIN_EXCEEDS_FREE_BALANCE | The cumulative initial margin exceeds the account free balance. |
REDUCE_ONLY_WOULD_INCREASE_POSITION | A reduce-only order would increase the position. |
ORDER_LIST_INCOMPLETE | The order list is missing orders in the cache. |
ORDER_LIST_DENIED | The order was denied because its order list failed risk checks. |
TRADING_HALTED | Trading is halted; new submissions and modifications are denied. |
TRADING_STATE_REDUCING | Trading is reducing; only eligible reduce-only submissions are permitted. |
RATE_LIMIT_EXCEEDED | The order submission rate limit was exceeded. |
STREAM_RECONCILING | The execution stream is unavailable or recovering; retry after recovery. |
NO_EXECUTION_CLIENT | No execution client was found for the routed command. |
CLIENT_VENUE_MISMATCH | The execution client does not handle the order venue. |
SUBMIT_FAILED | Submitting the order to the execution client failed. |
INVALID_CLIENT_ORDER_ID | The client order ID is invalid for the venue. |
INVALID_POSITION_ID | The supplied position ID is invalid for the order submission. |
UNSUPPORTED_ORDER_LIST | The venue does not support the requested order list. |
UNSUPPORTED_ORDER_TYPE | The order type is not supported. |
UNSUPPORTED_REDUCE_ONLY | The execution client or venue does not support the requested reduce-only instruction. |
UNSUPPORTED_TIME_IN_FORCE | The order's time in force is not supported. |
UNSUPPORTED_TP_SL | The venue does not support the requested take-profit/stop-loss parameters. |
VALIDATION_FAILED | The order failed validation before submission. |
九、自有订单簿(Own order books)
启用manage_own_order_books后,ExecutionEngine会为每个品种维护你方在途订单的按订单簿(MBO/L3)视图。策略可以从公开盘口中减去这些订单,以估算净可用流动性。生命周期、查询、过滤与审计见 自有订单簿。
9.1 安全取消查询
在查询自有订单簿中的取消候选时,应从status过滤器中排除PENDING_CANCEL。
:::warning 包含PENDING_CANCEL可能导致重复的取消请求,并反复选中那些已等待确认的订单。 :::
十、超额成交(Overfills)
超额成交指订单累计成交数量超过其原始数量。例如,总成交 110 单位相对于 100 单位的订单超额 10 单位。
10.1 超额成交如何产生
当上报数量超过订单数量时,引擎观察到超额成交。这可能是真实的交易所结果、不同 trade ID 下的重复投递,或交易所报告不一致——仅凭数量无法识别原因。
实盘成交可通过两个渠道到达:
- 通过 WebSocket 实时到达的成交事件。
- 周期性对账轮询交易所的成交历史与持仓状态。
稳定的trade_id让引擎能跨两个渠道对同一成交去重。如果逻辑上的同一成交以不同 ID 到达,引擎会把它们当作不同的报告。连续对账的配置见 配置实盘交易:连续对账。
10.2 系统行为
ExecutionEngine在应用每个成交事件前,会比较订单当前的filled_qty加上入站的last_qty与原始quantity,以检查潜在超额成交。源码可见 crates/execution/src/engine/mod.rs:calculate_overfill为正时,若allow_overfills=false则记录警告并拒绝该成交(提示可在ExecutionEngineConfig中开启allow_overfills),若为true则记录警告并应用。
allow_overfills配置选项(默认False)控制处理方式:
allow_overfills | 行为 |
|---|---|
False | 记录日志并拒绝该成交,保持订单当前状态 |
True | 记录警告、应用该成交,并在overfill_qty中跟踪超额部分 |
允许超额时,订单的overfill_qty字段跟踪超额数量;订单转入FILLED状态,leaves_qty被钳制为零。
10.3 重复成交检测
Order模型对每个trade_id只允许应用一个成交。Order.apply()在相同 ID 已存在于订单上时返回错误。接口定义于 crates/model/src/orders/mod.rs 的Ordertrait,各订单类型(如 market.rs、limit.rs)分别实现apply。
核心引擎路径
应用成交前,ExecutionEngine调用Order.is_duplicate_fill(),比较:
trade_idorder_sidelast_pxlast_qty
完全匹配则跳过并记录警告。若trade_id匹配但其他字段不同,四字段检查不会将其归类为完全重复;随后Order.apply()会拒绝被复用的 ID,引擎记录日志并丢弃该成交。crates/execution/src/engine/mod.rs 中validate_fill_for_order调用is_duplicate_fill并对重复成交发出警告跳过。
对账路径
对账路径在生成OrderFilled事件前检查trade_id;当该 ID 已存在于订单上时丢弃报告,无论其价格或数量如何。
合成与推断的对账成交使用确定性 ID。重启后重放相同输入会产生相同的trade_id,从而被去重。
10.4 配置
实盘交易可在LiveExecutionEngineConfig中开启超额容忍:
from nautilus_trader.config import LiveExecutionEngineConfig config = LiveExecutionEngineConfig( allow_overfills=True, ):::warning 请根据交易所的执行契约选择该设置。默认False保护本地状态,但合法交易所超额成交后可能留下差异;True会应用超额数量,且不能替代重复成交检测。请使用执行对账检测差异。 :::
十一、成交修正(Fill corrections)
部分交易所后续会减少或作废一笔成交。Nautilus 将其记录为OrderFillVoided事件,绝不以反向成交表示。事件标识原始交易,携带累计作废数量与费用修正。
执行引擎在把修正发布给策略与执行算法前,会重建受影响的订单与持仓,并刷新组合持仓与 PnL 缓存。支持成交修正的适配器会在 void 后请求一次权威账户刷新。
适配器必须先发布被引用的成交,然后才能进行重新打开的修正或使订单保持可执行的局部修正。若本地没有该成交,非重新打开的修正会使整个订单进入终态——即使voided_qty小于订单数量。后续的 working 状态报告不会重新打开VOIDED。完整契约见OrderFillVoided契约。
11.1 作废成交如何产生
作废是交易所对其已报告交易采取的行动。其原因跨资产类别反复出现:
- 错误执行审查:交易所作废一笔与成交时市场严重不一致的打印,或由交易所系统故障导致的成交。
- 结算失败:已撮合交易未能结算,成交从未产生经济效果。
- 事件失效:底层事件被放弃或对手方被撤出,撮合后的持仓不承担敞口。
- 交易后重述:交易所在清算期间重述交易的数量或费用。
该事件不重述成交价格,因此交易所的价格调整无法用单次修正表达。
不同交易所的 break 到达客户端的方式不同。FIX 交易所通过ExecType <150>的H(trade cancel)与G(trade correct)值发出信号;带外通知的交易所则让 break 通过执行对账浮现。
11.2 交易所参考
各交易所公布其采取行动的条件(原文中的外部链接此处从略,仅保留机制与说明):
| 交易所 | 机制 | 说明 |
|---|---|---|
| Nasdaq | Clearly erroneous transactions(规则 11890) | 明显错误交易政策 |
| NYSE | Clearly erroneous executions(规则 7.10) | 明显错误执行审查 |
| Cboe US equities | Clearly erroneous executions(BZX 规则 11.17) | 明显错误执行表格 |
| CME Group | Trade cancellations and price adjustments(规则 588) | 交易取消与价格调整 |
| Betfair | Voided bets,以累计作废规模(sv)报告 | Stream API 对作废投注的处理 |
| Polymarket | 链上回滚或重组后的FAILED交易状态 | user channel |
Nautilus 适配器在交易所通过其消费的流发布作废时发出OrderFillVoided:Betfair 来自订单变更消息的sv字段,Polymarket 来自 user channel 的交易状态。
十二、相关指南
- 事件(Events):订单与持仓事件类型及其分发。
- 执行算法:TWAP、自定义算法与派生订单。
- 执行策略:投递、状态、持久化与恢复边界。
- 执行对账:实盘状态恢复与运行时一致性检查。
- 订单簿:公开与自有订单簿行为。
- 订单(Orders):订单类型与管理。
- 持仓(Positions):从执行结果跟踪持仓。
- 策略(Strategies):策略侧订单提交。
【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考