實驗室

M/05 · 選擇偏誤分解

分解 IS-OOS 的 Sharpe 落差

一份變異數預算,將樣本內到樣本外的 Sharpe 退化拆解為選擇偏誤、參數選擇雜訊與殘餘技巧,橫跨十個深度滾動前推的 crypto 語料庫。

數學原理

假設一個策略家族以參數 k = 1, …, K 索引。對每個 k,你觀測到一個樣本內 Sharpe SISk 與一個樣本外 Sharpe SOOSk。標準做法,挑選樣本內的最大值,並寄望它在樣本外有最佳表現,將 IS-OOS 落差定義為

將 Δ 做加法分解。把每個 SISk 寫成一個真實技巧項加上一個參數選擇偏差再加上雜訊:

於是落差分裂為三項:

第一項純屬機械性。對 K 個獨立的 N(0, σ²) 抽樣而言,Mills 界給出期望最大值

在主導階上此界為緊緻。第二項是所選 k* 繼承的網格內 σ。只有第三項,殘餘技巧,才應該取決於該策略在樣本外確實做了某些有用的事。

變異數預算

搭配的儲存庫在一個(策略 × 視窗)面板上對 OOS Sharpe 變異數做雙向分解,並在每個單元上觀測一整組專有擾動,這組特定的擾動是 Daru Finance 顧問工作的一部分,此處不予列舉。面板層級的恆等式為

其中 Vparam = E[Vart SOOS(s, w, t)] 為橫跨擾動的單元內變異數(刀鋒般的敏感度),Vstrategy 與 Vwindow 為策略間與視窗間的均值差異,Vfinite = (1 + ½·Sh²)/n 為解析的有限樣本雜訊下限,而 R 為未解釋的交互作用。

實例演算

取深度 WFO crypto 語料庫中的 BTC_30m_27W:538k 筆 OOS 列,27 個滾動前推視窗。存活族群的平均 OOS Sharpe 為 −0.696。平均 Vparam 0.243。實盤代理獲利率(漏斗濾波後的最後兩個視窗): 8.4%

現在代入虛無。對一個 K = 400 組合的參數網格、σ = 1(500 筆交易、q ≈ 0.2 時典型的 IS Sharpe 雜訊)而言,期望最大值的界為

也就是說:在完全沒有技巧的情況下,從 400 個組合的網格中挑出樣本內贏家,會產生一個接近 +3.5 的期望 IS Sharpe,而其 OOS 期望接近零。無須援引任何真實優勢,便能輕鬆重現經驗落差。下方的互動式示範會在你每次移動 K 或 σ 時重新計算這一切。

Demo: predicted IS-OOS gap under a no-skill null

For a parameter grid of size K with iid N(0, σ²) IS Sharpes, the expected maximum is ≈ σ·√(2 log K). Move the sliders, the bar shows the predicted gap, decomposed into selection bias, parameter noise, and residual skill.

K, parameter-grid size400
σ, IS Sharpe noise1.00
E[max IS]
3.462
OOS skill
0.000
IS−OOS gap
3.462
√(2 log K)
3.46
selection bias
2.612
parameter σ
0.850

Under the null hypothesis of no skill, the entire IS-OOS gap is mechanical: scaling with √(log K) (selection) and σ (parameter noise). The residual skill term sits at zero.

-0.600.331.262.203.134.06Sharpe ratio (annualized units)OOS ≈ 0E[max IS] = 3.46selection biasparam σσ·√(2 log K) = 3.462 Var-share(selection) ≈ 0.137

At K=400 and σ=1, the expected-max-of-K Gaussians is ≈ 3.46, the entire IS-OOS gap a strategy population reports under the null can be reproduced without invoking any real edge.

經驗分解

在正典的 10 資產語料庫上(ETH、BTC、LTC、TRX、XRP、LINK、ZEC、DOGE、BCH、AVAX,皆為 ≥17 個滾動前推視窗的 30m crypto;727 萬筆 OOS 列;289,374 個實盤代理候選),彙總變異數分解為:

  • Vparam18.6%(橫跨擾動的參數選擇雜訊)。
  • Vstrategy16.8%(策略間主效應)。
  • Vfinite3.1%(解析的有限樣本下限)。
  • Vwindow1.2%(視窗間均值/機制代理)。
  • 殘餘/交互作用,60.4%

此語料庫的平均 IS-OOS Sharpe 退化為 0.84。殘餘技巧項在統計上與零無法區分,此落差是機械性的。

Fig. 1:30 資產語料庫中 10 個深度 WFO 分割上的彙總 OOS Sharpe 變異數分解。V_param + V_strategy + V_finite + V_window 約占總變異數的 ~40%;其餘為交互作用。關鍵在於,殘餘技巧,唯一應當反映真實優勢的項,在族群層級上不可見。
Fig. 2:依 V_param 十分位區分的實盤代理獲利率,於 10 個資產上彙總。D1(最低樣本內敏感度)落在 11.7%;D10(最高敏感度)落在 5.3%。在全部十個十分位上呈單調,小參數擾動下的樣本內變異數,是樣本外獲利能力的一個可用預測因子。
Fig. 3:逐資產 D1−D10 落差。ETH、ZEC、XRP 構成最高一層,落差達 11.7-12.4 個百分點。每個資產都呈正向提升;TRX 最弱,為 +1.3pp。訊號在實盤代理基準率最低之處最強,LTC 基準率為 4.7%,但 D1 達到 7.6%(相對提升 61%)。

合成虛無

為檢查此分解並非面板結構的人為產物,同一套流程在具三個植入類別(穩健/脆弱/雜訊)與確定性 RNG 的合成資料上執行。變異數形狀與十分位提升皆可重現,確認此分解所辨識的是機械性結構,而非真實語料庫中的異常。

Fig. 4:合成虛無上的變異數分解(三個植入類別、確定性 RNG)。同一套流程、同樣的形狀,經驗分解並非人為產物。

為何這對系統性策略至關重要

有兩個實務後果。其一,任何源自在 K 大小參數網格上做樣本內最大化的正向優勢主張,都必須先越過 σ·√(2 log K) 才值得認真看待,而在 K 棒層級的 crypto Sharpe 估計上,σ 很少小於 1。其二,Vparam 在樣本內完全可觀測(它僅由 IS 那一輪計算得出,無 OOS 洩漏),因此可在策略選擇時用作預先濾波器。深度 WFO 的經驗結果指出,Vparam 最低的十分位在實盤代理獲利能力上以 2.2× 的倍數單調地勝過最高十分位。

Bailey–López de Prado 的緊縮 Sharpe(deflated-Sharpe)與 PBO 框架,是從檢定統計量這一側切入同一個問題。本分解是互補的:它在族群層級而非逐策略層級運作,並產生一個可用的樣本內預測因子(Vparam)來預測樣本外獲利能力。

可重現性

DaruFinance / strategy-overfitting

Python · 開源參考實作

最小調用

from strategy_overfitting import (
    load_metrics, decompose_oos_variance, param_vs_live_lift
)

# Walk-forward output: long-format DataFrame with
#   columns: asset, strategy, window, perturbation, S_IS, S_OOS, n_trades
df = load_metrics(parquet_root="/data/strategies", min_trades=20, sharpe_clip=5)

# Two-way decomposition over (strategy x window) x perturbations
shares = decompose_oos_variance(df)
shares["share_v_param"]      # 0.186  - parameter-choice noise
shares["share_v_strategy"]   # 0.168  - between-strategy main effect
shares["share_v_window"]     # 0.012  - regime / window
shares["share_v_finite"]     # 0.031  - analytic finite-sample floor
shares["share_residual"]     # 0.604  - interaction + unexplained

# Predictive validity: rank strategies by V_param (in-sample) and
# measure live-proxy profitable rate by decile.
lift = param_vs_live_lift(df, n_deciles=10)
lift.D1_pct, lift.D10_pct    # e.g. 11.7, 5.3

參考文獻

  1. [1]Bailey, D. H., Borwein, J. M., López de Prado, M., & Zhu, Q. J. (2014). The probability of backtest overfitting. Journal of Computational Finance 20(4), 39–69.
  2. [2]Harvey, C. R. & Liu, Y. (2014). Backtesting. Journal of Portfolio Management 42(1), 13–28.
  3. [3]Lo, A. W. & MacKinlay, A. C. (1990). Data-snooping biases in tests of financial asset pricing models. Review of Financial Studies 3(3), 431–467.
  4. [4]López de Prado, M. (2018). Advances in Financial Machine Learning. Wiley, ch. 11–12.