現(xiàn))
NautilusTrader Market-To-Limit 訂單完全指南從定義、代碼示例到匹配引擎實(shí)現(xiàn)【免費(fèi)下載鏈接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture項(xiàng)目地址: https://gitcode.com/GitHub_Trending/na/nautilus_traderMarket-To-Limit市場(chǎng)轉(zhuǎn)限價(jià)是 NautilusTrader 九種訂單類型中唯一的混合型Hybrid訂單它以市價(jià)單Market形態(tài)提交完成首次成交后將剩余未成交量以該成交價(jià)為限價(jià)掛入訂單簿。本文基于 docs/concepts/orders/market_to_limit.md 展開結(jié)合 訂單模型實(shí)現(xiàn) 與 匹配引擎源碼完整講解其定義、使用場(chǎng)景、Rust/Python 調(diào)用方式、參數(shù)語義、底層成交邏輯與回測(cè)/撮合驗(yàn)證幫助你在薄盤或大單場(chǎng)景中控制沖擊成本。什么是 Market-To-Limit 訂單在 FIX 5.0 SP2 協(xié)議中Market-To-Limit 對(duì)應(yīng)OrdType 40 KMarket With Left Over as Limit。其核心行為是以Market訂單提交獲得最佳可用價(jià)格的即時(shí)成交首次成交后任何未成交的剩余數(shù)量以該成交價(jià)格作為限價(jià)繼續(xù)掛單。也就是說這只訂單同時(shí)具備兩個(gè)階段的身份市價(jià)階段Aggressive立即在最優(yōu)檔位吃掉流動(dòng)性限價(jià)階段Passive未成交部分轉(zhuǎn)化為限價(jià)單限價(jià)等于首筆成交價(jià)等待市場(chǎng)回落或回升后成交。關(guān)鍵點(diǎn)在于剩余部分不會(huì)繼續(xù)橫掃更深的檔位而是停在首筆成交價(jià)上。若市場(chǎng)隨后遠(yuǎn)離該價(jià)格剩余部分可能一直保持未成交狀態(tài)直至被取消或到期。在 訂單類型總覽 中MARKET_TO_LIMIT被歸類為Hybrid混合型與 AggressiveMARKET和 PassiveLIMIT并列其 FIX 映射為KMarket With Left Over as Limit這一點(diǎn)在 FIX OrdType 映射表 中有明確記載。適用場(chǎng)景原文檔明確指出Market-To-Limit 的核心價(jià)值在于在最佳價(jià)位吃單但避免橫掃更深檔位。典型的適用場(chǎng)景包括薄盤thin books檔位淺、流動(dòng)性稀疏時(shí)市價(jià)單可能瞬間打穿多個(gè)價(jià)位造成大幅滑點(diǎn)MTL 只取最優(yōu)檔后即轉(zhuǎn)為限價(jià)掛單大單larger orders當(dāng)訂單量超過最優(yōu)檔深度時(shí)不希望一次性把整個(gè)盤口吃穿而是吃掉首檔后讓剩余部分以首檔價(jià)被動(dòng)等待控制市場(chǎng)沖擊limiting market impactMTL 天然把吃單和掛單兩階段分開減少持續(xù)沖擊接受部分成交如果市場(chǎng)在首筆成交后離開該價(jià)格剩余數(shù)量可以保持未成交而非被強(qiáng)制以更差價(jià)格成交。與純 Market 訂單無價(jià)格保護(hù)、可橫掃所有檔位、存在滑點(diǎn)風(fēng)險(xiǎn)相比MTL 是有剎車的市價(jià)單與 Limit 訂單一開始就以指定價(jià)格被動(dòng)掛單相比MTL 保證至少先拿到首檔流動(dòng)性。代碼示例在策略中創(chuàng)建 Market-To-Limit 訂單原文檔給出了在 Interactive BrokersIdealProForex ECN上 BUY 200,000 USD/JPY 的完整示例。Rust 策略通過self.order()即OrderFactory創(chuàng)建Python 策略通過self.order_factory創(chuàng)建。Rustuse nautilus_model::{ enums::{OrderSide, TimeInForce}, identifiers::InstrumentId, types::Quantity, }; let order self.order().market_to_limit( InstrumentId::from(USD/JPY.IDEALPRO), OrderSide::Buy, Quantity::from(200_000), Some(TimeInForce::Gtc), // optional (default GTC) None, // expire_time Some(false), // reduce_only (default false) None, // quote_quantity (default false) None, // display_qty (default full display) None, // exec_algorithm_id None, // exec_algorithm_params None, // tags None, // client_order_id );Pythonfrom nautilus_trader.model import InstrumentId from nautilus_trader.model import MarketToLimitOrder from nautilus_trader.model import OrderSide from nautilus_trader.model import Quantity from nautilus_trader.model import TimeInForce order: MarketToLimitOrder self.order_factory.market_to_limit( instrument_idInstrumentId.from_str(USD/JPY.IDEALPRO), order_sideOrderSide.BUY, quantityQuantity.from_int(200_000), time_in_forceTimeInForce.GTC, # -- optional (default GTC) reduce_onlyFalse, # -- optional (default False) display_qtyNone, # -- optional (default None which indicates full display) tagsNone, # -- optional (default None) )注意USD/JPY 在 IdealPro 上以 JPY 報(bào)價(jià)此處quantity200_000表示 20 萬基礎(chǔ)貨幣USD的規(guī)模。參數(shù)語義與默認(rèn)值market_to_limit的參數(shù)語義由 Rust 版 OrderFactory 實(shí)現(xiàn) 和 Python stub 簽名 共同定義參數(shù)類型默認(rèn)值說明instrument_idInstrumentId必填交易標(biāo)的如USD/JPY.IDEALPROorder_sideOrderSide必填BUY/SELLquantityQuantity必填訂單數(shù)量必須為正數(shù)time_in_forceOptionTimeInForceGTC有效時(shí)間常用GTC/IOC/FOK/GTD/DAY等expire_timeOptionUnixNanosNone配合GTD使用指定過期時(shí)刻reduce_onlyOptionboolfalse僅允許減少倉位quote_quantityOptionboolfalse數(shù)量以報(bào)價(jià)貨幣計(jì)display_qtyOptionQuantityNone全量顯示顯示數(shù)量小于總量時(shí)為冰山單exec_algorithm_idOptionExecAlgorithmIdNone執(zhí)行算法 IDexec_algorithm_paramsOptionIndexMapNone執(zhí)行算法參數(shù)tagsOptionVecUstrNone自定義標(biāo)簽client_order_idOptionClientOrderId自動(dòng)生成自定義客戶端訂單 ID從 工廠源碼 可以看到默認(rèn)值的落地邏輯time_in_force為空時(shí)使用TimeInForce::Gtcreduce_only、quote_quantity為空時(shí)均為falsepost_only固定為falseMTL 必然先吃單與 post-only 語義互斥client_order_id為空時(shí)由工廠自動(dòng)生成當(dāng)指定了exec_algorithm_id時(shí)exec_spawn_id會(huì)被自動(dòng)設(shè)為該訂單的client_order_id。此外Python 端的MarketToLimitOrder完整字段可參考 模型 stub 定義包括price、has_price、display_qty、leaves_qty、avg_px、slippage、is_open/is_closed/is_inflight等只讀屬性。模型層實(shí)現(xiàn)價(jià)格留白與校驗(yàn)規(guī)則MarketToLimitOrder在 Rust 側(cè)定義于 crates/model/src/orders/market_to_limit.rs其內(nèi)部字段包括price: OptionPrice、expire_time: OptionUnixNanos、is_post_only: bool與display_qty: OptionQuantity其余訂單元數(shù)據(jù)存放在OrderCore中。最值得注意的設(shè)計(jì)是price初始為None。源碼注釋明確寫著price: None, // Price will be determined on fill——MTL 訂單在創(chuàng)建時(shí)沒有限價(jià)限價(jià)由交易所首筆成交回報(bào)確定之后通過OrderUpdated事件寫入。has_price()在成交前返回falsetrigger_price()恒為None它不是條件單。成交后計(jì)算滑點(diǎn)。apply()中當(dāng)訂單收到Filled或FillVoided事件且已經(jīng)持有price時(shí)會(huì)調(diào)用set_slippage(price)用最終限價(jià)與成交價(jià)比較計(jì)算滑點(diǎn)。對(duì)應(yīng)測(cè)試 test_market_to_limit_order_sets_slippage_when_filled 驗(yàn)證了 BUY 單以 90.00 限價(jià)、98.50 成交時(shí) slippage 為 8.50。new_checked構(gòu)造函數(shù)執(zhí)行三類校驗(yàn)源碼 L94-L96quantity必須為正否則 panicinvalid Quantity for quantity not positivedisplay_qty不得大于quantity當(dāng)time_in_force GTD時(shí)expire_time必填且不能為零。這些規(guī)則均有單元測(cè)試佐證例如 test_quantity_zero、test_gtd_without_expire、test_display_qty_gt_quantity。另外update()會(huì)拒絕攜帶trigger_price的修改事件MTL 無觸發(fā)價(jià)格拋InvalidOrderEvent并且 對(duì)應(yīng)測(cè)試 驗(yàn)證了非法更新會(huì)被原子性拒絕訂單狀態(tài)不發(fā)生任何改變。撮合引擎行為首檔成交、剩余轉(zhuǎn)限價(jià)在回測(cè)與模擬撮合中MTL 的處理邏輯位于 crates/execution/src/matching_engine/mod.rs 的process_market_to_limit_orderL3493-L3536無市場(chǎng)檢查若 BUY 單時(shí)盤口無 ask或 SELL 單時(shí)無 bid直接生成OrderRejectedNo market for {instrument_id}可選 ACK若引擎配置use_market_order_acks先發(fā)送OrderAccepted立即吃單調(diào)用fill_market_order完成市價(jià)階段成交剩余部分轉(zhuǎn)限價(jià)用order.quantity() - filled_qty計(jì)算剩余量若剩余不為零則通過accept_order讓剩余部分以限價(jià)單形態(tài)留在盤口。在fill_order的填充循環(huán)中L4825-L4944對(duì) MTL 有兩個(gè)關(guān)鍵處理首次成交時(shí)order.filled_qty() 0且類型為MarketToLimit先發(fā)出OrderUpdated把限價(jià)設(shè)為首筆成交價(jià)fill_px并置位initial_market_to_limit_fill首檔成交完成后立即returnL4941-L4944不再橫掃更深檔位——這與文檔without sweeping deeper levels的描述完全一致。事件序列驗(yàn)證集成測(cè)試 test_process_market_to_limit_orders_not_fully_filled 構(gòu)造了一個(gè) L2 盤口ask 1500.00 深度 1.000提交數(shù)量 2.000 的 BUY MTL 單驗(yàn)證了完整事件序列OrderUpdated—— 訂單被更新為市場(chǎng)停止成交處的限價(jià)1500.00OrderFilled—— 市價(jià)階段成交 1.000 1500.00OrderAccepted—— 剩余 1.000 被接受為限價(jià)單且撮合核心中確實(shí)存在這一筆 resting 訂單。測(cè)試 test_fully_filled_market_to_limit_not_in_core 則覆蓋了完全成交的 MTL全部成交后訂單不會(huì)殘留在撮合核心中。剩余部分的二次成交maker 還是 taker測(cè)試 test_deferred_market_to_limit_remainder_keeps_fill_price 深入驗(yàn)證了剩余限價(jià)部分的后續(xù)行為剩余部分保持首筆成交價(jià)作為限價(jià)此處為 1500.00若剩余部分以原限價(jià)被動(dòng)成交不修改訂單liquidity_side為Maker且按 maker 費(fèi)率計(jì)傭金若先對(duì)剩余部分發(fā)出ModifyOrder把限價(jià)改為 1501.00再成交則liquidity_side變?yōu)門aker傭金按 taker 費(fèi)率計(jì)算。這說明 MTL 的限價(jià)剩余并非簡(jiǎn)單地等同于一張靜態(tài)限價(jià)單——它同樣遵循撮合引擎對(duì)流動(dòng)性方向maker/taker與傭金的完整處理。Interactive Brokers 適配器支持原文檔示例選擇了 IB 的 IdealPro倉庫中的 IB 適配器對(duì) MTL 有顯式支持IB 訂單類型枚舉 包含IbOrderType::MarketToLimit其 wire 字符串為MTLL313并且from_nautilus將NautilusOrderType::MarketToLimit直接映射為MTLL388在 訂單轉(zhuǎn)換邏輯 中Market與MarketToLimit都按無 limit_price、無 aux_price處理——MTL 不攜帶任何預(yù)設(shè)價(jià)格限價(jià)完全由交易所首筆成交回報(bào)決定這印證了模型層price None的設(shè)計(jì)IB 適配器測(cè)試 覆蓋了MTL與NautilusOrderType::MarketToLimit的雙向解析。需要說明的是不同交易所對(duì) MTL 的原生支持差異很大。NautilusTrader 提供統(tǒng)一 API但正如 Orders 總覽 所提醒訂單類型與指令的支持度因交易所與適配器而異適配器可能在提交前拒絕不支持的請(qǐng)求或由交易所直接拒單。使用前請(qǐng)核對(duì)目標(biāo)集成的能力文檔。注意事項(xiàng)與邊界不可模擬cannot be emulated在 ExecutionAlgorithm::spawn_market_to_limit 的源碼注釋中明確說明MARKET_TO_LIMIT訂單始終以無模擬觸發(fā)emulation trigger初始化無法被OrderEmulator模擬模擬器只使用MARKET與LIMIT完成實(shí)際執(zhí)行。創(chuàng)建 MTL 時(shí)傳入emulation_trigger會(huì)被忽略。無價(jià)格保護(hù)階段的滑點(diǎn)市價(jià)階段仍可能產(chǎn)生滑點(diǎn)成交價(jià)相對(duì)首檔價(jià)偏離模型通過slippage字段量化若盤口完全無市場(chǎng)訂單會(huì)被拒絕。IOC 語義若使用IOC作為time_in_force撮合引擎在 L4955-L4958 的處理是有剩余且未完全成交時(shí)直接取消——即立即成交或取消剩余部分不會(huì)轉(zhuǎn)為限價(jià)掛單。這與剩余轉(zhuǎn)限價(jià)的默認(rèn)GTC行為不同選擇 TIF 時(shí)需要結(jié)合目標(biāo)語義。相關(guān)指南Orders訂單概念總覽 —— 訂單類型、執(zhí)行指令與 OrderFactory 的完整介紹Market市價(jià)單 —— 與 MTL 對(duì)比理解無價(jià)格保護(hù)與橫掃檔位的差異Limit限價(jià)單 —— MTL 剩余部分的限價(jià)階段語義Execution執(zhí)行概念 —— 訂單如何到達(dá)交易所、成交回報(bào)如何處理?!久赓M(fèi)下載鏈接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture項(xiàng)目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考