📌 30 秒摘要

這篇在講:從 N 組參數裡挑回測最好的那組,挑選這個動作本身就會過擬合。論文把它量化成一個機率 PBO:樣本內冠軍到了樣本外,排名掉到中位數以下的機率。估計方法叫 CSCV:把時間切成 S 段,窮舉所有「一半當樣本內、一半當樣本外」的組合。實驗中,純隨機漫步上回測出來的漂亮策略(年化 Sharpe 1.27),PBO 高達 55%。

🗺 心智圖(Canvas)

回測過擬合的機率(PBO)

回測過擬合的機率(PBO)

🧠 為什麼挑冠軍會灌水

🎯 什麼情境該想到我

當你「從很多次嘗試裡挑出表現最好的那一個,正準備相信它」的時候。
★ 挑最大值這個動作本身就會灌水:試的次數越多,冠軍越可能只是運氣最好的雜訊。

⚙️ 怎麼用

0. 先理解為什麼會灌水(可自己驗算)

假設 N 個嘗試其實全是雜訊,各自的分數是均值 0、標準差 1 的獨立常態。最大值的期望會隨 N 上升:

試了幾次 N期望最大值(模擬 2,000 次)上界 √(2 ln N)
10≈ 1.55σ2.15σ
100≈ 2.51σ3.03σ
880≈ 3.20σ3.68σ

(2026-10-25 自己模擬;√(2 ln N) 是常態極值的標準上界,不是這篇論文推的。)

換算成回測:500 個交易日估出來的年化 Sharpe,標準誤約 √(252/500) ≈ 0.71。所以從 880 組全是雜訊的參數裡挑冠軍,年化 Sharpe 期望就有 3.2 × 0.71 ≈ 2.3。實際的參數組合彼此高度相關,有效的 N 會小一些,但量級就是這樣。論文第 3.2 節也說:樣本內 Sharpe 落在 1 到 3 之間,「tell us nothing」。

1. 記下你到底試了幾次

  • 參數組合、模型版本、特徵組合、提示詞版本,都算一次嘗試。失敗的也要算。
  • 論文把只報告成功組合的做法比作新藥試驗剔除無效受試者,也就是「抽屜問題」。

2. 拿「雜訊冠軍」當基準線

  • 冠軍分數沒有明顯高過上表對應 N 的「純雜訊期望最大值」,就先當成運氣。
  • 能量化時,直接評估挑選流程:回測用 工具-回測過擬合機率PBO,問的是樣本內冠軍在樣本外會不會掉到中位數以下。

3. 看「越追高分,樣本外越差」的跡象

  • 把每次嘗試的(挑選用資料上的分數,另一段資料上的分數)畫成散點。斜率是負的,就是過擬合的典型樣子。
  • 論文的說法是:「The model is so fit to past noise, that it is often rendered unfit for future signal.」

4. 別把防過擬合的指標變成新目標

  • 例如改成挑 PBO 最低、或驗證集分數最高的那組,等於換一個指標繼續過擬合。
  • 論文引 Goodhart 定律:「when a measure becomes a target, it ceases to be a good measure」。

同一個陷阱的其他樣子(我的延伸,不是論文內容)

情境「試很多次」指的是對應做法
調模型超參數在同一份驗證集上反覆比較留一份只在最後用一次的測試集
A/B 測試每天看結果,一顯著就停事先定好樣本數和停止條件
刷 benchmark反覆改版,直到公開排行榜分數上升見 基準污染與分數失真
提示詞迭代在同一批範例上反覆修修的範例和驗收用的範例分開

🧪 我實際套用的紀錄

  • 2026-10-25:重現論文實驗。在純隨機漫步上試 880 組季節策略,樣本內冠軍看起來很好,但 PBO 是 0.56–0.84,也就是半數以上的情況下,冠軍到了樣本外連中位數都不如。

⚠️ 注意 / 什麼時候不適用

  • 只試一兩次、而且事先就決定好方案時,這個問題很小。麻煩的是事後從很多結果裡挑。
  • 上表假設各次嘗試彼此獨立。參數相近的組合高度相關,有效的 N 比名目上的 N 小,灌水幅度會比表上低,但不會消失。
  • 冠軍不可信,不代表全部都爛。N 個嘗試都好、只是彼此差不多時,挑哪個都可以;這種情況也會讓 PBO 偏高。

🔗 相關工具

📐 怎麼量化:CSCV 與 PBO

🎯 什麼情境該想到我

當你「掃了一堆參數組合,挑出回測最好的那組,正要決定要不要上線」的時候。
★ 它不評估某一個策略好不好,而是評估「你挑策略的流程」有沒有在挑雜訊。

⚙️ 怎麼用

1. 準備矩陣

  • 把試過的 N 組參數,每期損益排成 T×N 矩陣 M(每列同一時間點)。
  • 所有試過的組合都要放,包括失敗的。藏掉失敗的組合,PBO 會被低估。
  • 用最佳化演算法引導搜尋時,放每次搜尋收斂後的結果,不放中間步驟。

2. 跑 CSCV

  1. 依時間切 S 段(預設 S=16)。
  2. 窮舉 C(S, S/2) 種「哪一半當樣本內」的組合。
  3. 每種組合:在樣本內挑冠軍,看它在樣本外的相對排名 ω = rank/(N+1),算 λ = ln(ω/(1−ω))。
  4. PBO = λ ≤ 0 的比例。

Node 實作(2026-10-25 自己寫並驗證過)。關鍵技巧是 Sharpe 只需要每段的 sum、sum of squares、count,任意段組合可以直接加總,不用重掃資料。880 個策略 × 12,870 種組合,約 1 秒跑完:

function pbo(M, S = 16) {
  const T = M.length, N = M[0].length, L = Math.floor(T / S);
  const blk = Array.from({ length: S }, (_, s) => {        // 每段每策略的 sum、sumsq
    const sum = new Float64Array(N), sq = new Float64Array(N);
    for (let t = s * L; t < (s + 1) * L; t++)
      for (let n = 0; n < N; n++) { sum[n] += M[t][n]; sq[n] += M[t][n] ** 2; }
    return { sum, sq };
  });
  const sharpe = (blocks) => {                              // 合併多段算 Sharpe(只比排名,不必年化)
    const out = new Float64Array(N), cnt = blocks.length * L;
    for (let n = 0; n < N; n++) {
      let a = 0, b = 0;
      for (const s of blocks) { a += blk[s].sum[n]; b += blk[s].sq[n]; }
      const mu = a / cnt;
      out[n] = mu / Math.sqrt(Math.max(b / cnt - mu * mu, 1e-18));
    }
    return out;
  };
  const logits = [];
  const comb = (start, pick) => {                           // 窮舉 C(S, S/2)
    if (pick.length === S / 2) {
      const oos = [...Array(S).keys()].filter((s) => !pick.includes(s));
      const R = sharpe(pick), Rb = sharpe(oos);
      let best = 0;
      for (let n = 1; n < N; n++) if (R[n] > R[best]) best = n;
      let rank = 1;                                         // 1 = 樣本外最差,N = 最好
      for (let n = 0; n < N; n++) if (Rb[n] < Rb[best]) rank++;
      const w = rank / (N + 1);
      logits.push(Math.log(w / (1 - w)));
      return;
    }
    for (let s = start; s < S; s++) comb(s + 1, [...pick, s]);
  };
  comb(0, []);
  return logits.filter((l) => l <= 0).length / logits.length;  // PBO
}

3. 判讀

結果意思動作
PBO > 0.05挑選流程很可能在挑雜訊不要上線;減少參數維度或拉長資料
PBO 低,但樣本外虧損機率高沒過擬合,但策略本身就不賺錢不是調參問題,回頭檢查策略邏輯
PBO 低,且樣本外冠軍隨機支配整體挑選流程確實有效可以進下一關(模擬盤、小資金)

順便看績效衰退:把每種組合的(樣本內冠軍 Sharpe,樣本外 Sharpe)畫成散點。斜率是負的,代表越去追樣本內最高分,樣本外越差。

參數怎麼選(可自行驗算)

  • S:組合數是 C(S, S/2),S=16 時是 12,870,論文誤印為 12,780。PBO 是比例估計,標準差最大是 √(1/(4·12870)) ≈ 0.0044,夠精確。
    • 4 年日資料切 16 段,每段約一季,能保住日、週、月的序列結構。
    • 要研究季效應就改用 S=12(924 種),或把資料長度加倍。
  • N:要遠大於 10。N 太小時 ω 只有幾個離散值,PBO 的解析度不夠。
  • T:取「實際用來挑策略的資料長度」的兩倍,因為 CSCV 每次只用一半資料挑。

🧪 我實際套用的紀錄

  • 2026-10-25:用上面的程式碼重現論文第 6 節。月度季節策略,進場日 × 持有天數 × 多空,共 880 組,1,000 個交易日,每種各 3 個隨機種子:
    • 純隨機漫步:PBO 0.56/0.60/0.84(論文 55%)
    • 每月前 5 天埋入 +0.25σ 效應:PBO 0.00/0.16/0.05(論文 13%)
    • 觀察:我的每一次 PBO 都剛好等於樣本外虧損機率。原因是參數格點裡做多、做空成對出現,每個策略都有一個鏡像,樣本外中位數 Sharpe 恰好是 0,「低於中位數」就等於「虧錢」。格點不對稱時,兩者就不會相等。

⚠️ 注意 / 什麼時候不適用

  • 不檢查回測本身對不對:手續費、滑價設錯,或用到當時拿不到的未來資料,PBO 一樣會給出漂亮的數字。這些要另外檢查。
  • 不能拿 PBO 當挑策略的目標,例如「挑 PBO 最低的那組參數」。這樣就是在對 PBO 過擬合(Goodhart 定律)。它只用來評估挑選流程。
  • 只涵蓋資料期間內的市場狀態:資料期間外換了行情,它無能為力。
  • PBO 高不代表策略全爛:N 個策略都很好又彼此差不多時,PBO 也會高。
  • 對稱切分不一定最適合:績效序列自我相關很強時,切段可能破壞時間結構。對績效分布有更多了解時,針對模型設計的方法會更準。

🔗 相關工具

⚠️ 限制與誤用

  • 不檢查回測本身對錯
  • 要交出所有試過的組合
  • 別拿 PBO 當目標函數
Link to original

🎯 為什麼存這篇 / 未來想拿它做什麼

  • 以後寫交易策略回測、開始掃參數時,用它判斷「挑出來的最佳參數能不能信」。
  • 它講的不只是金融:只要是「試很多次、挑最好的那個」,例如調模型超參數、反覆看 A/B 測試、刷 benchmark,都會遇到同一個陷阱。

🧰 這篇給我的工具

✨ 關鍵重點

1. 問題定義:過擬合的是「挑選過程」

  • 這裡的樣本內(IS)指用來挑最佳策略的那段資料,不是模型本身擬合參數的那段。所以 PBO 不需要知道策略內部用了什麼模型,是 model-free、無母數的。
  • 定義 2.2:PBO = 樣本內最佳的策略,在樣本外排名低於中位數的機率。
  • 論文認為一般的 hold-out(留一段資料驗證)在這裡不可靠,主要原因是它不管你試了幾次。證明在作者另一篇論文。

2. CSCV 演算法(論文 Algorithm 2.3)

  1. 把 N 個策略的每期損益排成 T×N 矩陣 M(每列同一時間點)。
  2. 依時間切成 S 段(S 為偶數),每段 T/S 列。
  3. 列出所有「從 S 段取 S/2 段」的組合,共 C(S, S/2) 種。
  4. 每種組合 c:
    • 取出的段拼成樣本內 J,其餘拼成樣本外 J̄,兩邊各 T/2 列。
    • 在 J 上找出績效最佳的策略 n*。
    • 看 n* 在 J̄ 的排名,換成相對排名 ω = rank/(N+1)。
    • 算 logit:λ = ln(ω/(1−ω))。
  5. PBO = λ ≤ 0 的組合比例,也就是樣本內冠軍在樣本外沒贏過中位數的比例。

為什麼這樣設計(論文第 4 節):

  • 樣本內與樣本外一樣大,兩邊的 Sharpe 估計精度相當。
  • 不靠隨機抽樣:同樣輸入跑兩次結果完全一樣,別人可以重現。
  • 若回測毫無資訊量,ω 接近均勻分布,λ 就近似標準常態。這提供了「完全沒用」的基準線。

參數怎麼選:

  • S=16 是論文建議的預設值。若 4 年日資料切 16 段,每段約一季,序列相關結構還保得住。
  • S 太小,λ 分布的左尾估不準;S 太大,會把季節性切碎。
  • N 要遠大於 10,否則 ω 只有少數幾個值可取,λ 分布太離散。
  • T 要取「實際用來挑策略的資料長度」的兩倍,因為 CSCV 每次只用一半。

3. 四項檢查(論文第 3 節)

檢查問的是
PBO樣本內冠軍跌到樣本外中位數以下的機率
績效衰退樣本內越好,樣本外是不是反而越差。拿 (樣本內, 樣本外) 績效做迴歸,斜率通常是負的
樣本外虧損機率選出的策略在樣本外虧錢的比例。PBO 低時這項也可能很高,那代表策略爛,原因不是過擬合
隨機支配依回測挑,有沒有比隨便亂挑一個好。看一階、二階隨機支配

判讀門檻:比照 Neyman-Pearson 的慣例,PBO > 0.05 就拒絕。PBO 也可以當貝氏分析的先驗,或拿 (1−PBO) 當多策略組合的權重。

4. 實驗(論文第 6 節)

  • 設定:一個月度季節策略,有四個參數:進場日 1–22、持有天數 1–20、停損 0–10、多空 ±1,共 8,800 組。資料是 1,000 個交易日(約 4 年)。
  • 例 1,純隨機漫步:最佳組合年化 Sharpe 1.27,PSR 統計量 2.83,看起來非常顯著。但 CSCV 給出:約 53% 的樣本外 Sharpe 是負的,PBO 約 55%,選出的策略也沒有隨機支配。正確判定為過擬合。
  • 例 2,在每月前 5 天埋入 +0.25σ 的真實效應:最佳 Sharpe 1.54,只有 13% 的樣本外 Sharpe 為負,PBO 約 13%,而且有隨機支配。正確判定效應存在。
  • 重點:兩個例子的樣本內 Sharpe 差不多,只看回測績效完全分不出哪個是真的。

5. 限制與誤用(論文第 5 節)

  1. 對稱切分不一定適合每種策略。若對績效分布有結構性的知識,針對模型設計的方法會更準。
  2. 要交出所有試過的組合。藏掉失敗的會低估過擬合,就像新藥試驗把無效的受試者剔掉,也就是「抽屜問題」。反過來,故意加一堆注定失敗的組合來襯托,也會讓結果失真。用最佳化演算法引導搜尋時,要放每次搜尋收斂後的結果,不要放中間步驟。
  3. 不檢查回測本身對不對:手續費設錯、用到當時拿不到的資料,它都抓不出來。
  4. 只涵蓋資料期間內的結構變化。資料期間外換了市場狀態,它無能為力。
  5. PBO 高不代表全部策略都爛:N 個策略都很好但彼此差不多時,PBO 也會高。
  6. 不能拿 PBO 當挑策略的目標函數。論文引 Goodhart 定律:「指標一旦變成目標,就不再是好指標。」它只能用來評估挑選流程。

6. 我自己驗算與重現(2026-10-25)

  • 組合數:C(16,8) = 12,870,論文印成「12,780」,是錯字。C(24,12) = 2,704,156、C(12,6) = 924 都正確。p=1/2 時的標準差 √(1/(4·12870)) ≈ 0.0044,所以論文「小於 0.0045」的結論仍成立。
  • 用 Node 重現例 1、例 2:簡化成不含停損,880 組參數,每種各跑 3 個隨機種子。程式碼見 工具-回測過擬合機率PBO。
    • 純隨機漫步:PBO 0.56/0.60/0.84
    • 埋入效應:PBO 0.00/0.16/0.05
    • 方向與論文一致。
  • 原文兩處前後不一:
    • 第 3.2 節的實際策略例子(Figure 3),前文說只有 4% 低於中位數,後文寫「PBO of 0.04%」。
    • 第 2 節的定義用中位數(median),結論段寫成平均(mean)。
    • 以定義和演算法為準,兩處都採中位數。

💬 原文摘錄

  • “We say that the backtest strategy selection process overfits if a strategy with optimal performance IS has an expected ranking below the median OOS.”(定義 2.1)
  • “The model is so fit to past noise, that it is often rendered unfit for future signal.”(第 3.2 節)
  • “We cannot hope escaping the risk of overfitting by exceeding some SR IS threshold. On the contrary, it appears that the higher the SR IS, the lower the SR OOS.”(第 3.2 節)
  • “Any counter-overfitting technique used to select an optimal strategy will result in overfitting.”(第 5 節)

🔗 相關

  • 基準污染與分數失真 —— 同一個機制在 LLM 評估上的版本:私有評估集調參久了,就是在對著它過擬合