2026年九月24日 · 研究

我們在重新啟動後重播了一個模擬策略,結果委託變了。

我們在重新啟動後重播了一個模擬策略,結果委託變了。

我們在一筆交易進行到一半時重新啟動了模擬策略,重新啟動後的委託順序和之前不同。市場資料相同、策略版本相同、帳戶餘額也相同。訊號計算結果一致,但策略對持倉和待成交委託的記憶卻不一樣。

我們花了一天重播並追查這個落差,得到一個簡單的教訓:對軟體來說,重新啟動也是一種市場事件。如果你沒有測試策略如何重建狀態,再乾淨的回測也可能掩蓋模擬交易系統忘了自己持有什麼的問題。

09:10 — 我們選了一筆普通的持倉

測試策略交易一種流動性高的永續合約:短期均線向上穿越長期均線時做多,反向穿越時出場。我們開始重播時,先設定一筆小額持倉,並掛著一張只減倉的限價單來減少部位。這讓復原流程必須重建 2 件事:我們持有什麼,以及已經請交易場所執行哪些操作。

在檢查點,帳戶持有 0.04 口合約,另有一張 0.01 口的委託仍在掛單中。策略程序原本把這兩個數值都快取在記憶體裡,但啟動流程只抓取了持倉,並把快取的委託當成已經不存在。

09:25 — 第一張重複委託出現

重新啟動後,策略看到原有的多單,執行訊號邏輯,接著又送出一張 0.01 口的減倉委託。現在模擬交易場所上有 2 張有效委託。單看每張都沒問題,但如果兩張都成交,就會賣出預定數量的 2 倍。

我們一開始怪罪訊號迴圈。問題不在迴圈,而在不完整的狀態快照。策略問了「我持有什麼部位?」,卻沒問「哪些委託還在掛單中?」

重新啟動後的狀態程序認為的狀態帳戶實際狀態
持倉多單 0.04多單 0.04
未成交的減倉委託無2 張,各 0.01
成交 1 張後的預期曝險多單 0.03可能變成多單 0.02

10:00 — 我們修好了復原流程,接著發現一個時序問題

我們修改啟動流程,讓它先從帳戶的持倉和未成交委託重建狀態,再啟用新的決策。這解決了重複委託問題。接著我們讓斷線情況更不順利一點:策略離線時有一張委託成交,而成交通知在重新連線後才送達。

帳戶快照已經反映這筆成交,但延遲送達的通知又讓本機持倉減少了一次。有幾秒鐘,策略以為自己持有 0.02 口合約,實際上帳戶持有 0.03 口。它接下來的再平衡因此是根據一個並不存在的部位缺口進行。

我們加入了狀態核對規則:以帳戶快照作為起始狀態,使用事件識別碼忽略已反映在快照中的成交,並在初始同步完成前禁止送出委託。通知可能延遲,也可能重複送達。復原流程必須能應付這兩種情況。

13:40 — 重播抓到一個不明顯的落差

我們用相同的價格路徑,分別重播原始執行和重新啟動後的執行。如果只比較最終損益,就會漏掉問題:市場反轉後,兩個版本最後持有相同部位。比較委託事件才看得出差異。

我們記錄每次決策讀取的狀態:持倉、未成交委託、最後處理的成交識別碼、訊號值和策略版本。這樣一來,第一個出現差異的事件就有了解釋。一個執行看到有委託掛單,另一個卻看到清單為空。之後,其中一個執行又把同一筆成交套用了 2 次。

最終餘額相同,不代表行為一致。請比較決策和委託的順序,尤其是復原流程的前後。

16:20 — 下次我們會採取不同做法

我們花太多時間重播價格資料,卻太晚檢查帳戶狀態如何轉換。下次我們會先注入故障情境,並讓市場走勢盡可能平穩。這樣軟體錯誤就容易看出來,不會被劇烈波動干擾判斷。

我們也學會把復原快照和策略版本、事件紀錄一起保存。這讓我們幾分鐘內就能重現故障,不必仰賴某個人記得確切的重新連線順序。

如果模擬策略只有在程序持續執行時才表現正常,就還沒通過完整演練。試著在持倉期間重新啟動,讓成交延遲送達,並檢查它之後送出的每一張委託。目的不是證明它永遠不會故障,而是在模擬帳戶用意外再教你一次之前,先看清楚它如何復原。

模擬交易策略狀態回測委託管理可重現性
← 所有文章