有個問題是每一次回測都在迴避的:同一份程式碼,餵給它即時的市場,會不會做出同樣的事?再多的回測都答不出來。唯一的答案,是讓策略接上即時資料、以真實的執行語意跑起來,然後逐筆檢查兩個世界是否一致。我們每天自動做這件事,而它是整個平台裡產出最豐碩的抓蟲工具。
第一天:把鏡像蓋起來
每一支晉級的策略都跑在自己獨立的即時節點上,吃真實的交易所串流:用即時報價成交、真實價差、真實盤中時段。策略之間不共用任何狀態(這一課我們是硬碰硬學來的——共用節點會讓某支策略的部位查詢滲透到另一支去)。每一筆成交都會連同產生它的訊號值一起記錄下來。
每天早上:重播與比對
每日排程會取出各策略的模擬交易時間窗,把一模一樣的程式碼丟進回測引擎、以目錄資料跑同一段期間,然後一對一比對成交:同方向、同時間戳容差、同數量。輸出的不是相關係數,也不是感覺,而是一張表:已匹配、僅模擬、僅重播。健康的策略會落在 55 筆中匹配 54 筆。不健康的那支,則會明明白白告訴你哪一筆、在什麼時候分岔了。
壞掉的東西,按壞掉的順序排
- 暖機期成交。即時節點會餵歷史資料替指標暖機——而帶有自訂 bar 處理邏輯的策略就這麼開心地拿它下單了。回測從來看不到這些幽靈進場。修法是在下單提交層加防護,而不是改策略,因為不這麼做的話每一支策略都會繼承這個 bug。
- 多腿暖機的順序問題。某支橫斷面策略是一次暖機一個標的;每一條腿看到的兄弟標的都是空的,錨點永遠沒被初始化。上線後它什麼都沒交易;重播時卻交易得好好的。匹配筆數是零——但只有比對表把這件事大聲說了出來。
- tick 精度的當機迴圈。即時 aggTrade tick 進來的精度,和沙盒 instrument 預期的並不一樣。節點卡在一個回測永遠觸發不了的斷言上不斷當機重啟,因為目錄裡的 bar 早就正規化過了。
- 重啟失憶。行程重啟會對已經存在的部位重新觸發進場邏輯——對再平衡型策略來說,一次重啟就悄悄變成一次再平衡。放到實盤,這就不是一致性報告裡的小註腳了,那是一支綁著真金白銀的紅旗。
注意這個共通點:上面沒有一個是訊號的 bug。它們全都是執行邊界的 bug——暖機、狀態、精度、重啟。而這正是回測在結構上完全看不見的那一類失效,因為在回測裡,回測引擎本身就是那道執行邊界。
我們刻意保留的不對稱
這兩個世界本來就不該一模一樣。回測在 PnL 裡收取模型化的半價差,外加平方根衝擊成本;模擬交易則是在成交價裡付出真實價差,而且沒有衝擊模型。把模型化的價差加進模擬交易(或把真實價差加進回測)都會變成重複計算。一致性指的是相同的決策、容差之內的相同成交——而不是逐位元相同的 PnL。分得清哪些差異是有原則的、哪些是 bug,才是這門功夫的大半。
回測是假設。模擬交易是實驗。重播一致性則是那本會抓到你自欺欺人的實驗紀錄簿。
如果你在跑策略,卻沒有定期把即時行為和重播行為拿來比對,那你手上就有一整類自己從沒見過的 bug。我們大概每隔一兩週就會抓到一個,而每一個從回測內部看都是隱形的。
← 所有文章
