Bootstrap 信頼区間と「N が小さい時の正しい統計」

TL;DR

  • 中心極限定理 (CLT) が効くのは N≥30 程度。retail backtest では N<30 が普通
  • t 検定の正規性仮定は fat-tailed return で破綻、CI が too narrow になる
  • Bootstrap (Efron 1979) は分布仮定なしで CI 計算、retail でも実装簡単
  • 時系列構造があれば Block Bootstrap (Künsch 1989) で autocorrelation 保持

Hook

「Sharpe 1.5 と Sharpe 0.8、その差を 30 trade で語れるか」

戦略開発者が backtest を見せて「Sharpe 1.5」と言う。それが 1,000 trade のサンプルなら信用できる。だが 30 trade なら、本当の Sharpe は 0.5 かもしれない、2.5 かもしれない。N が小さい時、点推定は語れない。語れるのは信頼区間 (CI) だけだ。

Background

retail quant の backtest はサンプル数が小さい。低頻度戦略 (月数回 trade) で 1 年回しても N=数十程度。学術論文の N=数千とは桁が違う。この regime では古典的検定の前提が崩れる。

中心極限定理の働く範囲

CLT は「サンプル平均が正規分布に近づく」性質。一般則として N≥30 で「ほぼ正規」と教科書は言うが、これは「分布が比較的素直」前提。fat-tailed (kurtosis 高) な分布では N=30 でも CLT は弱い。trading return は典型的な fat-tail。

Theory — Bootstrap の発想

Efron (1979) は「観測データから with replacement で resample → 統計量分布を経験的に再構成」というアプローチを提案した。分布仮定なし で CI が取れる。

アルゴリズム

  1. 元データ (N サンプル) から with replacement で N 個ランダム抽出 → 1 回の resample
  2. その resample から平均 / Sharpe / MaxDD など対象統計量を計算
  3. これを B 回繰り返す (典型 B = 10,000)
  4. B 個の統計量分布の percentile から CI を取る

Numpy 擬似コード

import numpy as np
rng = np.random.default_rng(42)
returns = ...  # backtest returns array, length N

B = 10_000
boot_sharpes = []
for _ in range(B):
    sample = rng.choice(returns, size=len(returns), replace=True)
    sr = sample.mean() / sample.std() * np.sqrt(252)
    boot_sharpes.append(sr)

ci_low, ci_high = np.percentile(boot_sharpes, [2.5, 97.5])

Block Bootstrap

時系列に autocorrelation があれば iid bootstrap は構造を破壊する。Künsch (1989) や Politis & Romano (1994) の Block Bootstrap は連続 k 個をブロック単位で resample する。block size は k ~ N^(1/3) 程度が目安。

Concrete example

教科書的な数値感覚。N=30 trade、平均リターン 1.0%、std 3.0% という backtest:

  • t 検定 CI (95%): 約 [-0.1%, +2.1%] (CLT 仮定下)
  • Bootstrap CI (95%): 約 [-0.5%, +2.5%] (実分布が fat-tail なら更に広い)
  • N=300 にサンプル数を増やすと Bootstrap CI も [+0.7%, +1.3%] 程度まで縮む

つまり N=30 では「平均リターンが正である」とすら自信を持って言えない。Bootstrap で初めてそれが見える。

N_BOOT の影響

B=100 vs B=10,000 で CI percentile の安定性が違う。B=100 では 95% CI の境界が ±10% 程度ふらつく、B=10,000 ではほぼ安定。retail でも B=10,000 程度は推奨。

Limitation / Counter-argument

1. Bootstrap は「データの bias」を補正しない

Bootstrap は与えられたサンプルからの resample なので、サンプル自体に survivorship bias、look-ahead bias、selection bias があれば、それは resample にも乗る。Bootstrap は「サンプル分布の不確実性」だけを語る。

2. iid 仮定の限界

単純 Bootstrap は iid を仮定する。autocorrelation、volatility cluster がある時系列では block bootstrap が必要。block size の選択に研究分野がある。

3. heavy tail 分布での percentile 推定の不安定さ

extreme tail (1% percentile など) を Bootstrap で推定すると、サンプル境界の影響が大きく、不安定。tail 推定には extreme value theory (EVT) のような別アプローチが要る。

4. 計算コスト

B=10,000 × N=1,000 で約 1,000 万回の演算。Numpy で数秒〜数十秒。retail でも問題ないが、リアルタイム判定には重い。

Practical takeaway

retail で Bootstrap CI を組み込む手順:

  1. backtest pipeline に Bootstrap CI を default で組む: 平均・Sharpe・MaxDD すべて CI 付きで報告
  2. B=10,000 を最低ライン: B=1,000 は荒すぎる、B=100,000 は過剰
  3. 時系列なら Block Bootstrap: block size = N^(1/3) から始めて感度確認
  4. CI 下限が ゼロを跨ぐ戦略は捨てる: 平均が正でも、CI 下限が負なら採用基準を満たさない
  5. N が小さい段階では「保留」: N=30 で何かを判断するより、N=100 まで増やしてから判断する

ただしこの結果は限定的な期間の OOS 検証であり、future performance を保証しない。N を増やしても regime が変われば全て無意味になりうる。

まとめ

retail backtest の N は小さい。点推定 (平均、Sharpe) を見て判断する習慣を捨て、Bootstrap CI を見る習慣に置き換える。CI の幅が「自分が何を知らないか」を語ってくれる。

Sharpe 1.5 と Sharpe 0.8 の差は、CI が重ならなければ意味がある、重なれば偶然の範囲内かもしれない。N が小さい時の最強の道具は CI、最大の罠は点推定

参考文献

  • Efron, B., Tibshirani, R.J. (1993). An Introduction to the Bootstrap. Chapman & Hall.
  • Künsch, H.R. (1989). The Jackknife and the Bootstrap for General Stationary Observations. The Annals of Statistics, 17(3), 1217-1241.
  • Politis, D.N., Romano, J.P. (1994). The Stationary Bootstrap. Journal of the American Statistical Association, 89(428), 1303-1313.
  • Lopez de Prado, M. (2018). Advances in Financial Machine Learning. Wiley. Ch. 7.
  • Wikipedia, “Bootstrapping (statistics)”.

コメントする