chundev
日期:2026-05-22 主題:量化策略的機制驗證|資料:期貨交易所三大法人持倉
一個回測績效漂亮、統計檢定也過關的策略,仍然可能是過度擬合——因為「績效好」和「機制說得通」是兩回事。與其再跑十次回測,不如直接檢驗策略敘事的因果鏈。本文記錄四個可轉移的檢驗方法:跨商品轉移測試、把敘事拆成可否證環節、用零和恆等式做資料分解、換語言獨立重算。實作後發現:策略的核心機制成立,但長年沿用的「敘事」有一半是錯的——而策略一樣有效,因為它靠的不是錯的那半。
手上有一個以 Put/Call Ratio(P/C)為核心進場訊號的期貨策略:P/C 衝高時做多。回測八年、勝率約 70%,而且做過完整的統計驗證——隨機進場檢定(p < 0.0001)、Bootstrap 信賴區間、Walk-Forward、Runs Test 全部過關。
問題是:這些驗證都只回答「績效是不是運氣」,沒有回答「為什麼會賺」。一個過度擬合的策略,在它失效之前,長相和一個真有 edge 的策略一模一樣。少了機制解釋,你無法分辨「最近一段回撤」是正常波動還是 edge 已經消失——你沒有熄火判斷標準(kill criterion)。
所以這次不再跑回測,改成檢驗機制本身。
統計驗證和機制驗證回答的是不同問題:
| 工具 | 回答的問題 | 回答不了的問題 |
|---|---|---|
| 統計驗證(隨機進場、Bootstrap、WF) | 績效是不是運氣? | 為什麼會賺?何時會失效? |
| 機制驗證 | edge 的因果來源是什麼? | —— |
再跑一次回測,只是把第一欄的事重做一遍。要回答第二欄,得換工具。
策略原本交易某權值龍頭股的期貨。把「完全相同的進出場訊號」改成交易另一個標的(對應大盤的兩倍槓桿 ETF),不動任何參數。
結果:勝率 70.0% → 68.6%,每筆平均報酬 +2.4% → +3.1%——幾乎重疊。
這是一次幾乎免費的外樣本測試。如果策略是過度擬合原標的的特異性,把訊號搬到另一個標的應該崩掉;它沒崩,代表 edge 抓的是整個大盤的 beta/趨勢,不是單一個股的特性。
換標的而 edge 存活,比「在原標的再測十次」更能反駁過度擬合——因為它真的換了一組獨立的價格資料。
策略長年的敘事是一句話:「P/C 高 = 大戶在漲勢中買 put 避險 = 趨勢會延續」。這句話太滑溜,整句沒辦法檢驗。把它拆成兩個各自可否證的環節:
拆開的好處是:兩個環節用不同資料、可以各自成立或失敗。混在一句話裡,你只會得到二元的「成立/不成立」,看不出是哪一段斷掉。
用交易所公布的三大法人持倉(期貨/選擇權未平倉量,2019–2026,1789 個交易日)對 P/C 檢定:
環節 A — ✅ 成立。 P/C 與三大法人指數期貨淨多單,Spearman 相關 +0.32;分桶看更清楚:
| P/C 桶 | 三大法人指數期貨淨多單(口) |
|---|---|
| < 90(冷清) | −4,579 |
| 90–130(正常) | −340 |
| 130–150 | +6,561 |
| ≥ 150(極高) | +8,527 |
策略實際進場的那些日子,法人淨多單 +7,489 口 vs 全樣本平均 +1,174 口。→ 訊號可靠地篩出「法人重壓指數多單」的市場狀態。
環節 B — ⚠️ 敘事需修正。 P/C 與三大法人的 put 淨部位反而是負相關。再拆到各類法人:大型外資的 put 避險部位是「常態固定」的、跟 P/C 高低幾乎無關;隨 P/C 波動的,其實是造市商在賣 put、以及散戶在買。「大戶加碼買 put」這個因果說法,不精確。
關鍵收穫:策略的 edge 靠環節 A,不靠環節 B。 敘事錯的那半(B)只是色彩說明;承重的那半(A)成立。敘事可以修,策略不用動。
環節 B 想追問「P/C 衝高時,put 到底是誰在買」。直覺要市場總成交量,但資料源沒有、逐檔抓又太重(數百萬列)。
繞過去的方法是用未平倉量(open interest)的零和性質:每一口合約必有一個多方、一個空方,所以全市場「多方未平倉總和 = 空方未平倉總和」,把多方記正、空方記負,全體加總恆為 0。
於是:
非三大法人的 put 淨部位 = −(三大法人的 put 淨部位)
這是恆等式,不是估計。三大法人的部位資料拿得到,一相減就得到「散戶+其他」的淨部位,完全不需要市場總量。
結果:P/C 從正常區到極高區,put 淨多單從三大法人「移轉」到散戶手上(三大法人 +15,764 → −4,659 口;散戶相應 −15,764 → +4,659 口)。
通用心法:當你缺一份資料,先看看有沒有守恆律(零和、總量守恆、會計恆等式)能讓你從已有的部分反推出缺的那塊。
主分析是 TypeScript 寫的。要確認結論不是程式 bug 或數字抄錯,我用 Python 重寫一份獨立驗證:
結果:1789 個交易日逐筆比對,0 筆不符;分桶均值、進場日統計、相關係數全部一致。
心法:同一個人用同一種語言重看自己的程式,容易把同樣的 bug 再讀過去一次。換一種語言、從原始資料重來,才能真正排除實作錯誤和轉錄錯誤。 兩份獨立實作得到同樣答案,信心才足夠。
這次最值得記的一點:一個策略的說明文字裡,有些句子是承重牆(拿掉策略就垮),有些只是敘事色彩(好聽、幫助理解,但不影響盈虧)。
過去的敘事把一個正確的結論綁在一個不精確的機制上。檢驗之後才看清楚:結論對、機制要修,而結論才是承重的那個。
做策略研究(或任何模型)時值得定期問自己:我這套說法裡,哪幾句真的承重?哪幾句只是讓故事順?分清楚,你才知道哪裡禁得起打、哪裡其實可以放手改。