樣本外驗證怎麼做:為什麼這裡沒有「留 30% 當測試集」

唯一的工具是 rolling walk-forward,而它驗的不是一組參數。

最後更新 2026-09
重點整理
  • 工作頁上沒有「訓練/測試比例」這個設定。唯一的樣本外工具是第五分頁的 rolling walk-forward,兩個輸入框填的是天數,而且只有 rolling、不提供 anchored。
  • 做法:每一輪在訓練窗裡重新挑一次參數,套到緊接著的測試窗;測試窗互不重疊,接成一整段樣本外序列。
  • 判準是 WFE(樣本外效率)=樣本外 Sharpe ÷ 樣本內平均 Sharpe。0.5 及格、0.7 算好是業界慣例,不是證明——這句是產品自己的說明原文。
  • 實例:教學範例策略 btc_sma_cross 在 2026-09-17 那次執行,樣本內平均 Sharpe 1.3471、樣本外 −0.45、WFE −0.334;而同一支策略同一天的 MCPT 是過的。兩個工具問的不是同一件事。
  • 它不會給你一組可以拿去用的參數。那次執行 20 輪選出 4 組不同參數,成績不屬於其中任何一組。

你在教科書上、甚至在我們自己的〈回測是什麼?回測報告怎麼看〉裡都讀過同一句話:不要在全部資料上最佳化,至少留 20–30% 做樣本外驗證。然後你打開工作頁,把每個分頁都點過一遍,找不到那個比例設定。

沒找到是正常的,產品沒有這個功能。樣本外這件事在 Blave 上只有一個實作:第五分頁的 rolling walk-forward,而它填的是天數、驗的東西也跟簡單切分不太一樣。這篇講清楚差在哪、那個分頁上的每個數字怎麼讀。

概念上的樣本外,跟這裡的樣本外差在哪

如何避免策略過擬合〉裡有一張表,把三種做法標了等級:全資料最佳化(無效)、前 70% 訓練後 30% 測試(有效但有限)、滾動窗口重選(最真實)。那張表是概念層的判斷;產品層的事實是——只有第三種有按鈕

做法 概念上 在 Blave 上
用全部歷史最佳化,回報全部歷史樣本內,必然樂觀回測分頁本來就是在整段歷史上算成績,所以才需要另外驗
切一刀:前段訓練、後段測試有效但只能用一次沒有這個功能,找不到比例設定
Rolling walk-forward:每輪重選、測下一段最接近實盤的做法工作頁第五分頁「樣本外驗證」

差別不只是介面。簡單切分驗的是「這一組參數在後段資料上好不好」;rolling walk-forward 驗的是「用歷史挑參數」這個做法本身在這支策略上還站不站得住——它把「用一段歷史挑參數」這個動作重複做了 n 次,每次都用沒看過的下一段來記分。

它實際上怎麼跑

一句話:在每一個訓練窗裡重新挑一次參數,套到緊接著的測試窗;把所有測試窗接成一條。

樣本外序列 = 20 段測試窗接起來的那一條。
訓練窗 測試窗
12022-01-05 → 2024-12-302024-12-31 → 2025-01-29
22022-02-04 → 2025-01-292025-01-30 → 2025-02-28
32022-03-06 → 2025-02-282025-03-01 → 2025-03-30
(中間各輪同樣每次往前挪一個測試窗,共 20 輪)
202023-07-29 → 2026-07-232026-07-24 → 2026-08-22

測試窗首尾相接到日:輪 1 停在 2025-01-29、輪 2 從 2025-01-30 接上去,中間沒有空隙也沒有重疊——20 段接起來就是那條樣本外序列。

訓練窗則是大幅重疊:三年的窗每一輪只往前挪 30 天,所以任兩輪的訓練期幾乎是同一段資料。重疊的東西拼不成一條連續的線——這就是為什麼圖上只有樣本外那一條。

實作上它跑兩趟:第一趟把每一組候選參數的訊號在全歷史上只算一次,切出各輪訓練片段定價;第二趟只重算各輪的勝出組合,把測試片段串成一條、用一次定價算完整段。所以它比「跑 n 次完整掃描」快得多——下面那個 20 輪、4.7 年小時線的例子,2026-09-17 那次執行 3.5 秒跑完(介面確認框給的是通則:「通常兩分鐘左右跑完,結果會出現在這個分頁。」)。

只有 rolling,沒有 anchored

Rolling 是訓練窗每一輪整個往前滑;anchored 是起點固定、訓練窗越滾越長。產品只提供 rolling,anchored 刻意不提供。 你跟 agent 要 anchored,它會回一句固定的話就照跑 rolling:

這裡只提供 rolling(訓練窗跟著往前滑);anchored 不提供。

也不用想著繞過去:跑 walk-forward 的那支 lib 是唯讀的,常駐程式會直接拒絕編輯;而且結果檔裡沒有欄位可以標記「這是 anchored 跑的」,真的改了,畫面還是會照 rolling 顯示。

訓練窗與測試窗怎麼填

分頁上只有兩個輸入框:訓練窗測試窗,單位都是天,旁邊即時顯示會切出「共 n 輪」。兩個都不填,就走這張預設表:

資料長度(天) 訓練窗(天) 測試窗(多久重選一次,天)
≥ 11851095(三年)30
455–1184365(一年)30
< 455測試窗的 4 倍總天數 ÷ 12,最少 30

三年那一階是有理由的:它比較接近「用戶從整段回測裡挑一組固定參數」的真實做法。中等長度的歷史若直接套比例公式,訓練窗會短於一年,所以中間補了 365/30 這一階。

兩個硬上下限會直接擋下來,不給半調子的結果:少於 3 輪不跑、也不寫結果檔(「資料只夠 {n} 輪,至少要 3 輪才看得出樣本外表現」);超過 1000 輪一樣擋(「把測試窗調大」)。末尾不足一輪的資料不會硬湊,圖下方會註明「末尾 {d} 天不足一輪,未納入」。

樣本外效率(WFE)怎麼讀

結論卡只看一個數字:

WFE = 樣本外 Sharpe ÷ 樣本內平均 Sharpe

分子是拼接後那一整段樣本外序列的 Sharpe;分母是各輪訓練窗裡選中那一格自己的 Sharpe 的平均。四檔標籤照這個分界(都是「小於」,所以 0.5 落在「剛過門檻」、0.7 落在「高於門檻」):

WFE結論卡顯示
算不出來樣本外效率:無法判斷
< 0.2樣本外效率:遠低於門檻
< 0.5樣本外效率:低於門檻
< 0.7樣本外效率:剛過門檻
≥ 0.7樣本外效率:高於門檻

而那個數字旁邊的說明,請照字面讀:

Walk-Forward Efficiency(WFE):樣本外 Sharpe ÷ 樣本內 Sharpe(即上表兩列)。業界常用 0.5 當及格線、0.7 以上算好;樣本內 Sharpe 低於 0.25 就不做這個除法。這是慣例,不是證明。

分母有兩道防線,而且順序有意義

一個很小或負的分母會把整個診斷倒過來:一支樣本內從來就不強的策略,反而會因為「沒吐回什麼」而拿到很高的「效率」。所以有兩道防線:

  1. 訓練窗 Sharpe ≤ 0 的那一輪算失敗,不加入樣本內平均。它仍然留在輪表、留在參數漂移圖、留在獲利窗比例裡——只是不進分母。每輪明細會註明「第 {k} 輪訓練窗 Sharpe ≤ 0,不計入樣本外效率的平均。」
  2. 扣完之後的樣本內平均低於 0.25,就不做這個除法,直接顯示「無法判斷」。

一次真實的 walk-forward:2026-09-17 那次執行

教學範例策略 btc_sma_cross(BTCUSDT 1h,2022-01-01 起、共 1,720 天,SMA 45/100,參數一字未改)。資料落在第一階,預設窗 1095/30,切出 20 輪(測試窗合計 600 天),末尾 25 天不足一輪、未納入。

項目 樣本外(測試窗接起來,600 天) 樣本內(20 輪訓練窗各自算完取平均)
Sharpe−0.451.3471
年化報酬−16.55%+50.16%
最大回撤−46.57%
交易筆數183
樣本外效率 WFE = −0.45 ÷ 1.3471 = −0.334   →  遠低於門檻

三件事值得指出。第一,沒有任何一輪被排除——20 輪的訓練窗 Sharpe 全都大於 0,分母是完整的 20 輪平均、不是挑剩的。

第二,分母 1.3471 遠高於 0.25,第二道防線沒啟動,除法有效:「WFE 是負的」和「WFE 無法判斷」是兩回事,前者是算出來的結果,後者是拒絕作答。

第三,那兩欄涵蓋的期間本來就不同——樣本內是 20 個互相重疊的訓練窗的平均,樣本外是其後那 600 天,所以不是乾淨的同期對照;WFE 要量的就是這個落差本身。

提示: 這是 END = None 的回測,跑到執行當天為止,本身也是一張快照。引用任何回測或驗證數字都要標執行日期。

同一支策略,MCPT 是過的

同一天、同一份碼,這支策略的 MCPT p 值是 0.0160(n = 2000),stdout 自己印 significant edge at 95%——照上架閘門的判準是過的。

檢定 它問的問題 結果
MCPT在這組固定的部位序列上,這個成績分不分得出實力與運氣?p = 0.0160 → 過
Walk-forward照歷史挑參數這件事本身,到下一段還管不管用?WFE = −0.334 → 遠低於門檻

兩個都沒算錯,因為它們回答的不是同一個問題。這也是為什麼 p 值再漂亮都不能當成樣本外驗過了(見〈MCPT p 值怎麼看〉)。順帶說清楚:這不是在說這支策略壞掉了——它是 workspace 附的教學範例,這裡用它示範的是兩個檢定的語意差異。

挑參數用鄰域平均,回報的卻是那一格自己的 Sharpe

每一輪選參數用的是 3×3 鄰域平均(跟參數掃描同一條規則,也就是〈如何避免策略過擬合〉講的挑高原不挑峰值),但輪表上回報的訓練 Sharpe 是選中那一格自己的數字。這是刻意的:

分母用什麼後果
該格自己的 Sharpe(現行)分母偏高,WFE 偏保守
3×3 鄰域平均鄰域平均在結構上必然低於被它包住的那一格 → 分母被壓小 → WFE 灌水,整個分頁讀起來過度樂觀

分母灌水的診斷不如不做。

換參數的接縫不會先平倉

兩輪交界的地方,序列帶的是新那一輪自己的部位——是被剪開,不是歸零。強制每個接縫平倉等於憑空捏造 n−1 筆沒人交易過的出場。

換參數的成本不會被漏掉:接縫處權重改變,定價時照收手續費。也因為每一輪的數字都是從同一條拼好的序列切出來的、不重新定價,輪表加總就等於整段總數。

只有訓練窗扣暖身期,測試窗不扣

訊號在全歷史上算(rolling 指標才準),但每個訓練片段各自跳過自己開頭的暖身根數——不是只有第一輪。沒有這一步,第一輪會在指標還沒熱的 K 棒上訓練、挑到雜訊,各輪的有效長度也不一樣、不可比。上面那張輪表就是實證:策略的 START 寫的是 2022-01-01,但輪 1 的訓練窗從 2022-01-05 才開始——差的那幾天正是 WARMUP = 100 根小時線(約 4.2 天)被扣掉。

測試窗不裁切,因為它已經熱了,而且必須連續才能拼接。順帶回答一個進階讀者常問的問題:這裡不需要 embargo 隔離期——測試窗就緊貼在挑它參數的訓練窗後面,它之後的資料完全沒被用到。

提示: 圖上為什麼只有一條線?介面自己寫得很清楚:「樣本內沒有曲線:各輪訓練窗互相重疊,拼不出一條連續的線」。

它不會給你參數,這是硬契約

跑完之後沒有「套用建議參數」這個按鈕,agent 也不准因為這個結果去改你的策略碼。空狀態就把話講在前面了:

不會產生可採用的參數 —— 驗的是「用歷史挑參數」這個做法本身。

為什麼不能抄?看那次執行的參數漂移。20 輪只選出 4 組不同參數:

(45,100) ×14 → (55,80) → (45,100) → (45,80) ×3 → (35,80)

前 14 輪都停在同一格。就算「大部分時候都選 45/100」看起來像個結論,那條 −0.45 的樣本外曲線也不是 45/100 的成績——它是 4 組參數接力跑出來的一整段,不屬於其中任何一組,所以沒有一組可以被「採用」。你要求套用時,agent 會回固定的一句:

樣本外驗證不產生可採用的參數——它的成績來自每輪重選,不屬於任何一組;要換參數請走參數掃描的穩健點。

參數漂移網格會畫出每一輪選中哪一格、被選中幾輪,虛線框標出你目前的參數,圖例也明寫「最後一輪選中的參數只是參考,不是建議值」——那次執行最後一輪選的是 35/80,只代表「最後那一輪的訓練窗剛好挑到這一格」。另外,這個分頁不顯示 p 值、也永不跑 MCPT;跑一次 walk-forward 在 agent 的工作守則裡算一次迭代

打開這個分頁,先看這五件事

1

輪數夠不夠? 少於 3 輪根本不會跑。輪數太少時,WFE 只是一兩個測試窗的運氣。

2

有沒有輪被排除? 每輪明細會註明哪幾輪訓練窗 Sharpe ≤ 0。上面那次一輪都沒被排除;被排除的輪越多,代表這支策略連在自己的訓練窗裡都常常挑不到東西。

3

WFE 是「無法判斷」還是一個負數? 不一樣。「無法判斷」代表樣本內平均低於 0.25、這個比值沒有意義;負數代表除法做了、樣本外那段是虧的。

4

參數漂移得多兇? 看「{n} 輪選出 {u} 組不同參數」那一行。上面那次是 20 輪 4 組;每輪都跳到完全不同的格子,等於每次重選都在追不同的東西。

5

你是不是在找建議參數? 沒有。要換參數走參數掃描的穩健點,不是抄最後一輪。

誠實提醒: 兩件事要講白。第一,這不是上架閘門。策略庫那三道品質關卡是誠實回測的手續費、統計顯著(MCPT)、參數穩健,walk-forward 不在裡面——它是你的自助工具。第二,0.5 和 0.7 是慣例,不是證明。產品自己的說明就是這樣寫的,本文不會講得比介面更武斷:WFE 高只代表「用歷史挑參數這件事,在這段資料上沒有明顯吐回去」,不代表未來會複製同一個結果;反過來,一次 WFE 為負,也只是那一組窗、那一段資料下的一個結果。

接下來

跑過一次之後,如果 WFE 掉得很難看,問題通常不在樣本外這一步,而在挑參數那一步——那是〈如何避免策略過擬合〉的範圍。如果你手上還沒有值得驗的策略,策略庫裡的官方策略每一支都附真實回測與品質關卡結果,可以先看數字再決定:策略庫