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 が取れる。
アルゴリズム
- 元データ (N サンプル) から with replacement で N 個ランダム抽出 → 1 回の resample
- その resample から平均 / Sharpe / MaxDD など対象統計量を計算
- これを B 回繰り返す (典型 B = 10,000)
- 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 を組み込む手順:
- backtest pipeline に Bootstrap CI を default で組む: 平均・Sharpe・MaxDD すべて CI 付きで報告
- B=10,000 を最低ライン: B=1,000 は荒すぎる、B=100,000 は過剰
- 時系列なら Block Bootstrap: block size = N^(1/3) から始めて感度確認
- CI 下限が ゼロを跨ぐ戦略は捨てる: 平均が正でも、CI 下限が負なら採用基準を満たさない
- 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)”.