某個星期二 UTC 08:00,一家加密貨幣交易場所調整了一份中價位永續合約的跳動點。我們的基差策略毫無察覺。訊號看到的現貨與期貨價差依然相同,風險限額沒有改變,回測結果也仍然一如往常。
模擬交易卻發現了問題。委託轉接器把買進限價向下取整到最近的有效價格,讓委託比回測模擬的價格低了一個跳動點。市場觸及舊價格時,模擬委託成交了,紙上委託卻一直沒動靜。到了午餐時間,策略的庫存已經失衡。
這起事件看似只是小小的取整錯誤,實際上卻是模型邊界出了問題:策略知道價格,但回測不知道交易場所的價格格線。
我們交易的是簡單的基差信號:當期貨溢價擴大到超過門檻時,買進現貨並賣出永續合約。由於預期基差優勢不大,委託採取被動方式掛單。幾個跳動點就可能決定進場獲利是否足以支付費用,以及之後的出場成本。
跳動點變更後,發生了什麼?
更新前,永續合約接受以 0.01 為增量的價格。更新後,在相關價格區間內,價格必須以 0.05 為增量。訊號算出的目標賣價是 42,318.03,依照舊規則有效,依照新規則則無效。
交易所會拒絕無效價格,但我們的轉接器設有備援處理:先將賣價向下取整到 42,318.00,結果仍然無效。第二次備援又取整了一次,這回變成 42,318.05,價格雖然有效,對賣方來說卻較不積極。委託無法再以模型設定的價格賣出。這段程式原本是為另一個市場撰寫的,卻悄悄把拒單改成了重新定價。
這筆委託牽涉到兩個不同的問題。第一,交易場所允許哪些價格?第二,當目標價格不在價格格線上時,策略應該如何處理?第一個問題由交易所決定;第二個則必須由策略或執行政策決定。
| 委託意圖 | 格線規則 | 常見的取整方向 | 可能造成的影響 |
|---|---|---|---|
| 買進限價 | 價格必須是跳動點的倍數 | 向下取整,以維持價格不高於限價 | 成交機率降低 |
| 賣出限價 | 價格必須是跳動點的倍數 | 向上取整,以維持價格不低於限價 | 成交機率降低 |
| 可立即成交的限價單 | 也必須符合價格上下限 | 取決於可接受的最高價格 | 是否會穿越價差 |
取整方向沒有放諸四海皆準的正解。買進價格向下取整可以維持買方的價格限制,但成交機率可能降低。向上取整則可能讓委託立即成交,進而改變費用與市場衝擊。對我們的被動基差進場來說,悄悄移動委託價格是錯誤的處理方式。策略已經選定目標價格,轉接器卻改變了交易的經濟條件。
為什麼回測看起來還是很正常?
我們的歷史委託模擬器把限價視為連續數值。如果 K 棒低點觸及買價,或高點觸及賣價,就判定委託成交。對被動委託而言,這種近似本來就偏寬鬆,因為成交價格觸及限價,並不能說明我們在隊列中的位置。但這次跳動點更新揭露了更根本的問題:委託根本不可能以那個價格存在。
我們從規則生效時間起套用新格線,重新播放相同的交易決策。好幾筆成交消失了;也有幾筆委託取整後穿越價差,付的是 taker 費用,而非 maker 費用。接著部位變化路徑也產生分歧,後續對沖與出場因此跟著改變。看似只是中繼資料的一項規則,竟改變了整串交易順序。
而且,這次更新並不是藏在圖表裡的突發狀況。交易場所早已公布商品規則變更及其生效時間。我們妥善保存了市場資料,商品中繼資料卻只存在啟動時才更新的快取裡。回測對每個歷史日期都讀取今天的規則;模擬交易則在程序重新啟動前一直使用過期規則。兩種環境都沒有呈現交易場所當時允許的條件。
回測應該如何模擬跳動點變更?
像其他時間點資料一樣,依有效期間為商品規則建立版本。至少要保留生效時間,以及委託驗證所需的規則值:跳動點、數量增量、最小數量和任何價格區間。模擬器應載入模擬決策當時有效的規則集。
接著,明確定義委託處理方式。目標價格無效時,可以拒絕委託、依照明文政策取整,或將目標重新計算到格線上,並記錄實際採取的方式。自動修正每筆委託的回測,或許適合用來估算特定執行政策,但不該把該政策偽裝成交易所成交。
對被動委託而言,價格符合跳動點規則只是成交的第一個條件。你還需要模型判斷市場是否穿越你的價格、你前方有多少排隊委託、有哪些取消,以及你能取得哪個費率級距。
我們新增了兩項檢查。第一項會用時間點對應的商品規則檢查每筆產生的委託,一旦價格或數量無效,就明確報錯。第二項會比對回測與模擬交易轉接器最後正規化後的委託,包括方向、價格、數量、委託時效和費用意圖。只要兩者不一致,這次執行就不算具備可比性。
完成後,我們重新播放了星期二的變更。格線更新後,回測不再宣稱委託以 42,318.03 成交。即使決策是略過委託,模擬交易和模擬器對每個無效目標的處理也完全一致。
訊號並沒有失效,過時的是它對可交易標的所抱持的假設。策略可以適應新的跳動點,但前提是研究系統把交易場所規則納入所模擬的市場。
← 所有文章


