試行回数で上がる「偶然の最良値」
100人がそれぞれ10回コインを投げると、誰か1人くらいは10回中9回表を出します。その人のコイン投げの腕が良いわけではありません。人数が多いので、偶然の極端な結果が1つは出るのです。 ルールの最適化も同じ仕組みです。候補を1つ試すたびに「くじ」を1枚引いていると考えると、引いた枚数が多いほど、一番当たったくじの成績は高くなります。
第2回では、これを規則のない相場で確かめました。探索期間(2005〜2016年)と同じ日数・同じ時間帯別の値動きの大きさを持ち、平均がゼロのランダムウォークを200本作り、Aさんの縮小グリッド3,456通りを当てたものです。 どの案にも本物の優位はないので、成績の差はすべて偶然です。試す数Nを変えながら、最良の案の年率Sharpe(収益の平均を変動の大きさで割った値を1年あたりに直したもの)を平均すると、次のようになりました。
- N=1:0.08。1通りしか試さなければ、ほぼゼロ。
- N=10:0.42。10通り試しただけで、見栄えのする数字になる。
- N=100:0.59、N=1,000:0.69、N=3,456:0.72。
最初の10通りで大きく上がり、その後は上がり方が緩やかになります。最大値は、候補が増えるほど伸びが鈍くなる性質を持つためです。 裏を返すと、「少しだけ試した」段階で、すでに偶然の上乗せはかなり入っているということです。10通りだから大丈夫、とは言えません。
数学者の Bailey、Borwein、López de Prado、Zhu は、2年分のバックテストなら、将来の期待Sharpeがゼロの戦略でも、7通りほど試すだけで年率Sharpe 1を超えるものが1つ見つかると期待できることを示しました("Pseudo-Mathematics and Financial Charlatanism", Notices of the AMS, 2014)。 データが短いほど、偶然の最良値は高くなります。
偶然の最良値を超えても、まだ「ルールの実力」とは限らない
実際のドル円(探索期間)に同じ縮小グリッドを当てると、最良の案の年率Sharpeは1.44でした。ランダムウォーク200本の最良値は中央値0.72、上から5%の水準でも1.06なので、実データは1本も届かない高さです。 つまり実データには「偶然の最良値」では説明できない何かがあります。ただし第12回の置換検定で見たとおり、その正体の多くは、東京時間のブレイクではなくドル円の年ごとの流れ(上昇)でした。 試した数による上乗せを差し引くことは、比較対象との差を見ること(第10回)の代わりにはなりません。この回で扱うのは、あくまで「たくさん試して選んだこと」の補正です。
DSR が補正するもの
DSR(Deflated Sharpe Ratio、デフレートしたSharpe)は、Bailey と López de Prado が提案した指標です("The Deflated Sharpe Ratio", 2014)。 考え方は2段階です。
- 基準線を引き上げる:何も優位がなくても、N通り試せば「最良の Sharpe」は偶然にある高さまで上がります。その高さ(偶然の最良値の期待値)を SR0 とし、合否の基準線にします。N=1なら基準線はゼロです。
- 推定のぶれで割る:観測した Sharpe は推定値なので、取引数が少ないほど、損益の分布が歪んでいるほど、ぶれます。観測値が基準線をどれだけ上回ったかを、このぶれの大きさで割って、確率(0〜1)に直します。
SR̂ は観測した Sharpe、SR0 はN通りの偶然の最良値、SE(SR̂) は Sharpe の推定のぶれ(標準誤差)、Φ は「平均0・標準偏差1の正規分布で、その値以下になる確率」です。 DSR 0.95 は、おおまかに言えば「N通り試したことを考えに入れても、偶然の最良値を上回っていると95%の確からしさで言える」という意味です。 SR0 の近似式と導出は、上級コースの多数試行の期待最大SharpeとDeflated Sharpe Ratioで扱います。
DSR が補正するもの・しないもの
| DSR が補正するもの | DSR が補正しないもの(別の回で確かめる) |
|---|---|
| 試した数による選択の偏り(N) | コストと約定の楽観(第9回) |
| 取引数の少なさによる推定のぶれ(T) | 相場の流れを拾っただけの利益(第10回) |
| 原論文では、損益の分布の歪み(歪度・尖度) | 先読み、データの誤り、時刻のずれ |
| 将来の構造変化(第15回、第18回) |
DSRはNを入力に使います。Nが正しく数えられていなければ、DSRは何も補正しません。何を試行に数えるかは第8回で決めたとおりで、期間・通貨ペア・方向・フィルタを結果を見て選んだことも入ります。
補正したい「上乗せ」は実データでも見える
DSRが差し引こうとしているのは、「選ばれた1位に乗っている偶然の分」です。その上乗せが、実データでどれくらいの大きさになるかを見ておきます。 Aさんのグリッドのうち「買いのみ」の19,200案を、探索期間の1取引あたり平均の順に並べ、上位の案が最終テスト(2023年1月〜2026年7月)で出した平均を示したのが次の図です(第1回でも使った図です)。
探索期間の1位は、最終テストでは1取引 −1.01 pipsで、19,200案の下から1.6%の位置でした。上位10案の平均も −0.65 pipsです。一方、上位100案は +2.03、上位1,000案は +4.11 pipsで、全19,200案の平均 +3.16 pipsを上回りました。 広い上位の塊には、最終テストまで続いた差がありました。それでも頂上の1つは、その差に加えて探索期間の偶然を一番多く取り込んだ案なので、偶然の分が消えると最下位近くまで落ちます。 DSRは、この「頂上に乗った偶然の分」を、Nと推定のぶれから見積もって差し引く道具です。
ヘアカットという考え方
運用の実務では、バックテストで報告された Sharpe を半分に割り引いて読むという慣習がよく使われます。この割引をヘアカットと呼びます。 Campbell Harvey(Duke大学)と Yan Liu は、この慣習を出発点に、割引の大きさを計算で決める方法を示しました("Backtesting", Journal of Portfolio Management, 2015。要約は Man Group の解説記事)。 半分に割り引く理由は、報告される戦略が、たくさん試された中から選ばれた「データの掘り出し物」だからです。一方で彼らは、50%という数字は経験則にすぎないとも書いています。
ヘアカットの計算の流れ
- Sharpe を t値に直す:Sharpe と取引数(観測数)から、「平均がゼロでない」ことの確からしさを表す t値を出す。
- 1回だけ試した場合の p値を出す:p値は、優位がなくても偶然でその成績以上が出る確率。
- 試した数で p値を補正する:1回なら5%でしか起きない成績でも、何十回も試せば偶然に出る確率はずっと高い。これを多重検定の補正と呼ぶ。
- 補正した p値を Sharpe に戻す:「1回だけ試してこの p値になる Sharpe」がヘアカット後の Sharpe。元の Sharpe との差の割合が割引率。
論文の例では、20年分の月次データ(240か月)で年率Sharpe 0.75の戦略は、1回だけ試したのなら p値 0.0008 で非常に有意です。しかし200通り試した中から選んだと考えると補正後の p値は0.15になり、Sharpe は0.32まで下がります。割引は約60%です。 また、10通り試した中の1つが1回の検定で p値0.05だった場合、補正後は0.401、つまり「偶然でも4割ほどの確率で出る成績」になります。
割引は一律ではない
Harvey と Liu の結果で大事なのは、次の2点です。
- 試した数が多いほど、割引は大きい:同じ Sharpe でも、10通りから選んだのか1,000通りから選んだのかで割引は変わる。
- 元の Sharpe が低いほど、割引は大きい:年率Sharpe が0.4未満の戦略は、ほとんどの条件で50%を超えて割り引かれる。1.0を超える戦略では、割引は最大でも25%程度にとどまる。ぎりぎりの成績の戦略ほど偶然で説明しやすく、非常に高い成績は偶然だけでは出にくいからです。
つまり「一律に半分」は、ぎりぎりの戦略には甘すぎ、非常に強い戦略には厳しすぎます。彼らはまた、割引の計算には「何通り試されたか」という判断が欠かせないこと、戦略どうしの損益の相関によって実質的な試行数が変わることも注意しています。
実データでも、割り引くべき量は塊ごとに違った
Aさんの57,600案を、方向(買いのみ・売りのみ・両方向)ごとに探索期間の成績で10段階に分け、各段階の最終テストの平均を並べたのが次の図です。
買いのみの19,200案では、探索期間の下位10%の塊が最終テストで +1.57 pips、上位10%の塊が +4.33 pipsで、順位は最終テストでもおおむね保たれました(10段階の順位相関 0.49)。 一方、売りのみでは探索期間の順位と最終テストの順位の相関が −0.40、両方向でも −0.22 で、探索期間で上位だった案ほど最終テストでは悪くなりました。 そして前の章で見たように、買いのみでも頂上の1位は最終テストで下から1.6%に落ちています。
探索期間の成績から「将来に残る分」を読むとき、割り引くべき量は、上位の塊では小さく、頂上の1点や順位が逆転する方向では、探索期間の優位がすべて消えるどころかマイナスに変わるほど大きくなりました。一律の割引では、この違いを表せません。 だからこのコースでは、報告された Sharpe に一律の割引をかけるのではなく、試した数を入力にしたDSRを計算し、0.95で線を引きます。 ヘアカットは、試した数が分からない他人の成績を読むときの目安として使います。その場合は「少なくとも何百通りは試しているだろう」と多めに見積もるのが安全です。
最小実装
バックテストのコードには、試行回数NとDSRの出力を必ず入れます。N_TRIALS は研究ログの累計から取り、実行する前に更新します(第8回)。
このコースのDSRは、すべて次の関数で計算しています。読まなくても本文は理解できます。
N_TRIALS = 3456 # 累計の試行回数(研究ログから。実行する前に更新する)
print(f"試行回数 N = {N_TRIALS}")
import numpy as np
from scipy.stats import norm
def deflated_sharpe_ratio(sr, N, T, sr_std=None):
"""sr: 選んだ案のSharpe(1取引あたりなど。年率に直さない)
N: 累計の試行回数 T: srを計算した観測数(取引数など)
sr_std: 試行間のSharpeの標準偏差(srと同じ単位)。省略時は帰無分布の幅"""
if sr_std is None:
sr_std = np.sqrt(1.0 / (T - 1))
eg = 0.5772156649 # オイラー=マスケローニ定数
sr0 = 0.0 if N <= 1 else sr_std * (
(1 - eg) * norm.ppf(1 - 1 / N)
+ eg * norm.ppf(1 - 1 / (N * np.e))
) # 優位がなくても期待される「N通りの最良値」
return norm.cdf((sr - sr0) / np.sqrt(1.0 / (T - 1)))
sr = returns.mean() / returns.std(ddof=1) # 1取引あたりのSharpe
dsr = deflated_sharpe_ratio(sr, N_TRIALS, len(returns))
print(f"SR = {sr:.4f} | T = {len(returns)} | DSR = {dsr:.3f}",
"採用候補" if dsr >= 0.95 else "不合格(0.95未満)")
入力は3つです。sr は選んだ案の Sharpe、T はその Sharpe を計算した観測の数、N は試行回数です。
sr と T の単位をそろえるのが最も大事な約束で、1取引ごとの損益で Sharpe を計算したなら T は取引数、日次の損益なら日数にします。年率の Sharpe と取引数を組み合わせると、DSR はでたらめに高く出ます。
第9回で取り上げたスキャルEAの窓(2025年で最適化)では、学習期間の1取引あたり Sharpe が 0.0197、取引数 T=10,043、N=3,456 で、DSR は 0.053 でした。同じ関数に N=1 を入れると 0.976 になります。
sr_std は、基準線 SR0 の高さを決める「試行間の Sharpe のばらつき」で、sr と同じ単位でなければなりません。
ネット上のコード例には sr_std=1.0 と固定したものがありますが、1取引あたりの Sharpe は0.02のような小さな値なので、単位が合いません。基準線がけた違いに高くなり、N≥2 ならどんな戦略でもDSRがほぼゼロに潰れる、壊れた判定になります。
省略したときは、上のコードのように「優位がないときの Sharpe の推定のぶれ」sqrt(1/(T−1)) を使います。N通りすべての Sharpe を記録してあるなら、そのばらつきを同じ単位で渡します。
この関数は最小版で、原論文にある損益の分布の歪み(歪度)と裾の厚さ(尖度)の補正を省いています。損切りと利確の置き方で左右非対称になった損益や、まれな大負けがある損益では、推定のぶれは正規分布の場合より大きくなるので、最小版はDSRを高めに出しがちです。 歪度・尖度を必ず併記し(第13回)、分布の歪みが大きいときは原論文の式で計算し直してください。
AさんとBさんの DSR(スキャルEAとの比較)
Aさん・Bさん、そして参考実験のスキャルEAに、同じ関数でDSRを付けました。Nはそれぞれの研究ログ(試行台帳)の値で、最終テストでも付け替えず、そのルールが生まれるまでに試した数のまま計算しています。
| 誰・どの成績 | 条件 | N | 取引数・1取引平均 | DSR |
|---|---|---|---|---|
| Aさん 探索 2005〜2016年 | 報告値(終値約定・コスト0) | 57,662 | 351件、+8.65 pips(年率Sharpe 1.18) | 0.418 |
| Aさん 検証 2017〜2022年 | 報告値(終値約定・コスト0) | 57,662 | 190件、+3.94 pips(年率Sharpe 0.61) | 0.003 |
| Aさん 検証 2017〜2022年 | 次の足の始値・往復0.4 pips | 57,662 | 190件、+3.55 pips(年率Sharpe 0.54) | 0.002 |
| Aさん 最終テスト 2023-01〜2026-07 | 次の足の始値・往復0.4 pips | 57,662 | 163件、+5.61 pips | 0.002 |
| Bさん 探索 2005〜2016年 | 次の足の始値・往復0.4 pips | 1 | 1,893件、−0.14 pips | 0.40 |
| Bさん 検証 2017〜2022年 | 同上 | 1 | 914件、+1.57 pips | 0.92 |
| Bさん 最終テスト 2023-01〜2026-07 | 同上 | 1 | 561件、+4.42 pips | 0.981 |
| (参考)スキャルEA 学習 2025年 | テスター(終値約定・コスト0) | 3,456 | 10,043件、+0.140 pips(1取引あたりSharpe 0.0197) | 0.053(N=1と偽ると0.976) |
Aさん:Sharpe 1.18 でも、57,662通りの1位としては平凡
Aさんの報告書では、探索期間の年率Sharpe 1.18、PF 1.83、勝率59.5%が並びます。1通りだけ試した成績なら十分に立派です。しかし57,662通りを試した後の1位だと分かれば、DSRは0.418で、合格ラインの半分にも届きません。
検証期間ではさらに下がり、報告値の条件で0.003です。Aさんは探索期間の上位12案の検証成績(+589〜+749 pips)を見比べ、一番良かった3位案に乗り換えました。 12回見て選んだ時点で、検証期間の成績も「選ばれた成績」になり、Aさんの台帳は57,650から57,662に増えています。Sharpe も0.61に下がっていて、偶然の最良値を上回る余地は残っていません。 最終テストの平均 +5.61 pipsはプラスですが、DSRは0.002で、57,662通りを試した後に選んだルールの成績としては、偶然で十分に説明できる水準です(第17回)。
Bさん:N=1でも、DSRが自動的に合格になるわけではない
Bさんは事前に1通りだけ決めたので、N=1です。このときDSRの基準線はゼロで、DSRは「Sharpe がゼロを上回っていると言える確からしさ」になります。 それでも探索期間は0.40、検証期間は0.92で、どちらも合格ラインに届きませんでした。探索期間は平均がゼロ付近なので当然の結果で、検証期間は平均がプラスでも取引数に対してぶれが大きかったためです。 最終テストでようやく0.981となり、DSRの項目は合格しました。ただしBさんの判定は「保留」です。悪化コストでの信頼区間の下限と比較対象との差、という別の2項目が不合格だったからです(第17回)。DSRの合格は、採用の必要条件の1つにすぎません。
スキャルEAの例:数字は同じで、Nの申告だけが違う
スキャルEAの取り上げる窓の学習期間は、10,043回の取引で1回 +0.140 pipsでした。正直に3,456通りから選んだと数えるとDSRは0.053、「最初からこの設定だった」と偽ってN=1にすると0.976です。 取引数が多いので推定のぶれは小さく、Nを隠せばゼロと区別できる成績に見えてしまいます。DSRの信頼性は、Nの申告の正直さでほぼ決まります。他人のEAの成績を読むときに、Nが書かれていないDSRやSharpeを信用しない理由です。 なお、この案は往復0.4 pipsのコストを入れると学習期間から1取引 −0.277 pipsで、DSR以前にコストで崩れています(第9回)。
なお、このスキャルEAの実験(単発記事参照)は、検証者が事前に相場を見ていた影響を排除するため、買いと売りを対称にし、39回くり返した窓の割合を主な数字にし、取り上げる窓も結果を見る前に固定しています。
2人の「やったこと/結果」
| やったこと | 結果 | |
|---|---|---|
| Aさん | 最良の1通りの Sharpe・PF・勝率だけを報告。Nは書かない | Nを反映するとDSRは探索0.418、検証0.003、最終テスト0.002。報告書の数字の大半は試した数で説明できた |
| Bさん | N=1を事前に固定し、各期間の生の Sharpe とDSRを並べて報告 | 探索0.40・検証0.92で不合格、最終テスト0.981で合格。ほかの2項目が不合格で「保留」 |
DSR の前に必要な確認
DSRは、入力が正しいときだけ意味を持つ最後の補正です。計算する前に、次を確かめます。
- 収益の形:価格差ではなく、対数収益(log return)を基本にする。pipsで評価するときも、Sharpe の単位(1取引・1日)と T をそろえる。
- 分布の形:歪度・超過尖度・Jarque–Bera検定(正規分布からのずれを調べる検定)を出す。歪みが大きければ、最小版のDSRは高めに出ると考える(第13回)。
- サンプル数:n<30 は「サンプル不足」と明記し、DSRを判断に使わない。n≥30 は平均の95%信頼区間も並べる。
- コストと約定:次の足の始値で約定させ、通常・悪化・ストレスの3段階でコストを入れた成績でDSRを出す(第9回)。コスト0の成績のDSRは、どれだけ高くても採用の根拠にならない。
- 先読み・欠損・時刻:シグナルに未来の値を使っていないか、欠損日の扱い、サーバー時刻とJSTの対応を確認する。
- N:研究ログの累計を使う。正確に復元できなければ、分かる範囲の「少なくともN」を使い、そう明記する(第8回)。
- リスクの目安:VaR(一定の確率で起こり得る損失の目安)は正規近似だけでなく、歪度と尖度で補正した Cornish–Fisher VaR も出す。
DSRが高くても、ここで誤りが見つかれば採用できません。DSRはレポートの最後に付ける飾りではなく、検証の工程の1つです。
よくある間違い
「Sharpe を半分に割れば、試した数は気にしなくてよい」
一律50%の割引は経験則です。Harvey と Liu の計算では、年率0.75の Sharpe でも200通りから選べば約60%割り引かれ、0.4未満の Sharpe はほとんどの条件で50%を超えて割り引かれます。 Aさんのグリッドで探索期間1位だった案(買いのみを1取引平均で並べた1位)は、最終テストで下から1.6%まで落ちました。試した数が分かっているなら、その数を入れてDSRを計算します。
「DSR が0.95を超えたので採用」
DSRが補正するのは、試した数と推定のぶれだけです。Bさんは最終テストでDSR 0.981でしたが、悪化コストの下限と比較対象との差が不合格で「保留」です。コスト、比較対象、置換検定、年別の一貫性、最終テストの合格ラインはすべて別に通します。
「見せる案だけでNを数える」
Nは、採用した案の数でも、公開した案の数でもなく、結果を見て比べた候補の総数です。スキャルEAの成績は、N=3,456 なら0.053、N=1 と申告すれば0.976です。不採用の案や、頭の中で却下した調整も、データを見て選んだなら数えます。
「単位の合わない値を関数に入れる」
年率の Sharpe と取引数を組み合わせる、sr_std=1.0 を固定するなど、単位の合わない入力はDSRを極端に高く、または極端に低くします。Sharpe・T・sr_std は同じ単位(1取引あたり、または1日あたり)でそろえます。
実戦課題
自分のEAか、これから検証するルールを1つ選んで、次の順に作業してください。
- Nを出す:研究ログから、そのルールにたどり着くまでに比べた候補の数を数えます。パラメータの組み合わせに加え、期間・通貨ペア・方向・フィルタの選択も入れます。復元できない分は「少なくともN」と書きます。
- 単位をそろえる:1取引ごとの損益(コスト込み・次の足の始値で約定)から1取引あたりの Sharpe を出し、T を取引数にします。歪度・尖度も一緒に出します。
- DSRを2つ計算する:数えたNと、N=1 の2通りでDSRを計算し、並べて記録します。差が大きいほど、成績の多くが「試した数」で説明できるということです。
- 判定を書く:0.95以上なら「DSRの項目は合格(ほかの項目は別に確認)」、未満なら「不合格」と書きます。0.95未満のときに、Nの数え方を後から小さくしてはいけません。
- 他人の成績を読む:販売EAやSNSの成績を1つ選び、試した数が書かれているかを確認します。書かれていなければ、生の Sharpe を半分以下に割り引いて読み、判断を保留します。
やるべきこと/やるべきでないこと
| やるべきこと | やるべきでないこと |
|---|---|
| 生の Sharpe とDSRを並べ、DSR<0.95 は採用しない | 生の Sharpe だけで採否を決める |
| Nを研究ログの累計から取り、実行する前に更新する | DSRが低かったので、Nの数え方を後から小さくする |
| Sharpe・T・sr_std の単位をそろえる | 年率の Sharpe と取引数を組み合わせる、sr_std=1.0 に固定する |
| コスト込み・次の足の始値で約定した成績でDSRを出す | コスト0の成績のDSRを採用の根拠にする |
| 歪度・尖度を併記し、歪みが大きければ原論文の式で計算し直す | 損益の分布を見ずに最小版のDSRだけを信じる |
| DSRの合格を、ほかの検査と並ぶ1項目として扱う | DSRが0.95を超えたことを「採用」と同じ意味で使う |
| Nが書かれていない他人の成績は、大きく割り引いて読む | 「Sharpe を半分に割れば十分」と一律に割り引いて終える |
チェックリスト
次の回に進む前に、以下が自分の言葉で説明できるか確認してください。
- 試す数が増えるほど、優位がなくても最良の Sharpe が上がる理由
- DSRが補正するもの(試した数・推定のぶれ)と、補正しないもの(コスト・相場の流れ・先読み)
- 「Sharpe を半分に割り引く」経験則が、ぎりぎりの戦略には甘く、強い戦略には厳しい理由
- DSRの関数に入れる Sharpe・T・sr_std の単位をそろえる理由と、sr_std=1.0 に固定しない理由
- スキャルEAの成績が、N=3,456 では0.053、N=1 では0.976になること
- BさんがDSR 0.981でも「保留」である理由
ミニテスト
4問で確認します。不正解なら別の選択肢を選び直せます。正解すると解説が表示されます。
Q1. 値動きに規則のない相場で、試す案の数を1通りから3,456通りに増やすと、最良の案の年率Sharpe はどうなりましたか?
優位がなくても、試す数が増えるほど「偶然の最良値」は上がります。N=10 ですでに0.42で、少しだけ試した段階から偶然の上乗せは入っています。DSRはこの高さを基準線にして成績を評価します。
Q2. 第9回のスキャルEAの学習期間の成績(10,043回、1回 +0.140 pips)は、N=3,456 では0.053、N=1 では0.976でした。ここから言えることは?
成績の数字は同じで、違うのはNの申告だけです。Nを隠すと、3,456通りの中の偶然の1位が、合格ラインを超える成績に見えます。Nが書かれていないDSRやSharpeは信用しません。
Q3. Harvey と Liu の研究から分かる、「Sharpe を一律に半分に割り引く」経験則の問題は?
年率0.4未満の Sharpe はほとんどの条件で50%を超えて割り引かれ、1.0を超える Sharpe の割引は最大でも25%程度でした。試した数が多いほど割引も大きくなります。このコースでは一律の割引ではなく、Nを入れたDSRで判定します。
Q4. DSRを計算するときに、sr_std を1.0に固定してはいけない理由は?
sr_std は観測した Sharpe と同じ単位の「試行間のばらつき」です。省略時は、優位がないときの推定のぶれ sqrt(1/(T−1)) を使います。Sharpe・T・sr_std の単位をそろえることが、最小実装で一番大事な約束です。