【保存版】バックテスト結果の正しい見方|8つの評価指標を徹底解説
バックテスト、勝率だけ見てない?
「勝率70%!これは勝てるEAだ!」
...ちょっと待ってください。
バックテスト結果を勝率と総利益だけで評価していませんか?それ、かなり危険です。
この記事では、プロトレーダーやクオンツが使う8つの評価指標を解説します。これを知ると、バックテストの見方が180度変わります。
参考: バックテストの評価指標|あいさき
1. 期待利得(Expected Value)
定義
期待利得 = 総損益 ÷ 取引回数1回のトレードで平均いくら稼げるかを示す最も基本的な指標。
見方
- プラスなら利益が出るシステム
- スプレッドやスリッページを引いた後で計算すること
- 取引回数が少ないと信頼性が低い
例
総利益: 100万円取引回数: 500回期待利得: 100万 ÷ 500 = 2,000円/回注意: 期待利得がプラスでも、ドローダウンで退場する可能性はある。
2. プロフィットファクター(PF)
定義
PF = 総利益 ÷ 総損失利益と損失の比率を示す。最もポピュラーな指標。
見方
| PF | 評価 |
|---|---|
| 1.0未満 | 負けシステム |
| 1.0〜1.3 | 微妙 |
| 1.3〜2.0 | 良好 |
| 2.0以上 | 優秀(過剰最適化の可能性も) |
計算例
# Pythonでの計算wins = trades[trades['pips'] > 0]['pips'].sum()losses = abs(trades[trades['pips'] < 0]['pips'].sum())pf = wins / losses if losses > 0 else float('inf')注意: PFが高すぎる(3.0以上)場合は過剰最適化を疑え。
3. 悲観的リターンレシオ(PRR)
定義
PRR = (勝ちトレード数 - √勝ちトレード数) × 平均利益 ÷ (負けトレード数 + √負けトレード数) × 平均損失PFをサンプルサイズで補正した指標。取引回数が少ないほど厳しく評価される。
なぜ重要か
- PFは取引回数を考慮しない
- 10回のバックテストと1000回のバックテストを同じPFで比較するのは危険
- PRRは「たまたま」の可能性を織り込む
見方
| PRR | 評価 |
|---|---|
| 1.0未満 | 信頼性低い |
| 1.0〜1.5 | 要検証 |
| 1.5以上 | 信頼性あり |
import numpy as np
def calc_prr(trades): wins = trades[trades['pips'] > 0] losses = trades[trades['pips'] < 0]
n_wins = len(wins) n_losses = len(losses) avg_win = wins['pips'].mean() if n_wins > 0 else 0 avg_loss = abs(losses['pips'].mean()) if n_losses > 0 else 0
numerator = (n_wins - np.sqrt(n_wins)) * avg_win denominator = (n_losses + np.sqrt(n_losses)) * avg_loss
return numerator / denominator if denominator > 0 else 04. GHPR(Geometric Holding Period Return)
定義
GHPR = (最終資産 / 初期資産) ^ (1/取引回数)複利運用での1トレードあたり平均成長率。
なぜ重要か
- 単純な期待利得は「足し算」の世界
- 実際の運用は「掛け算」(複利)の世界
- 大きな損失があると復帰が困難
見方
- GHPR > 1.0 なら資産は増加傾向
- GHPR < 1.0 なら資産は減少傾向
- 1.001でも長期では大きな差になる
def calc_ghpr(trades, initial_capital=1000000): capital = initial_capital for pips in trades['pips']: # 1pips = 1000円として計算 capital += pips * 1000
n_trades = len(trades) ghpr = (capital / initial_capital) ** (1 / n_trades) return ghpr5. 最大ドローダウン(Max Drawdown)
定義
最大DD = 最高資産額からの最大下落幅過去の最悪の資産減少を示す。
重要な注意点
「単一バックテストの最大DDはほぼ無意味」
なぜか?
- 過去に起きた「たまたま」の最悪値にすぎない
- 将来はもっと大きなDDが起きる可能性がある
- モンテカルロシミュレーションで複数回検証すべき
見方
- 最大DDの2〜3倍は覚悟すべき
- 資金の50%以上のDDは精神的に耐えられない
- DDから回復するには時間がかかる
def calc_max_drawdown(trades, initial_capital=1000000): capital = initial_capital peak = initial_capital max_dd = 0
for pips in trades['pips']: capital += pips * 1000 peak = max(peak, capital) dd = (peak - capital) / peak * 100 max_dd = max(max_dd, dd)
return max_dd # パーセント6. リカバリファクター(Recovery Factor)
定義
リカバリファクター = 純利益 ÷ 最大ドローダウンDDからの回復力を示す。
見方
| RF | 評価 |
|---|---|
| 1未満 | 回復困難 |
| 1〜3 | 普通 |
| 3〜5 | 良好 |
| 5以上 | 優秀 |
なぜ重要か
- 利益が大きくてもDDが大きければ危険
- 「100万円稼いで50万円のDD」より「50万円稼いで10万円のDD」の方が健全
def calc_recovery_factor(trades, initial_capital=1000000): total_profit = trades['pips'].sum() * 1000 max_dd = calc_max_drawdown(trades, initial_capital) max_dd_amount = initial_capital * max_dd / 100
return total_profit / max_dd_amount if max_dd_amount > 0 else 07. シャープレシオ(Sharpe Ratio)
定義
シャープレシオ = 平均リターン ÷ リターンの標準偏差リスク(バラつき)あたりのリターンを示す。
なぜ重要か
- 同じ利益でも、安定して稼ぐのと乱高下して稼ぐのは違う
- 損益のバラツキ = リスクという考え方
- 機関投資家が重視する指標
見方
| シャープレシオ | 評価 |
|---|---|
| 0.5未満 | 低い |
| 0.5〜1.0 | 普通 |
| 1.0〜2.0 | 良好 |
| 2.0以上 | 優秀 |
def calc_sharpe_ratio(trades): returns = trades['pips'] return returns.mean() / returns.std() if returns.std() > 0 else 08. ソルティノレシオ(Sortino Ratio)
定義
ソルティノレシオ = 平均リターン ÷ 下方偏差シャープレシオの改良版。損失方向のリスクのみを考慮。
なぜ重要か
- 上方向のバラつき(大勝ち)はリスクではない
- 下方向のバラつき(大負け)だけがリスク
- より実践的なリスク評価
見方
- シャープレシオより高くなるのが普通
- 極端に低い場合は大負けトレードがある証拠
def calc_sortino_ratio(trades): returns = trades['pips'] negative_returns = returns[returns < 0] downside_std = negative_returns.std() if len(negative_returns) > 0 else 0
return returns.mean() / downside_std if downside_std > 0 else 0実践:指標を使った評価例
先日検証した指標後遅延エントリー戦略を8指標で評価してみましょう。
NFP逆張り(15分遅延→240分決済)
| 指標 | 値 | 評価 |
|---|---|---|
| 期待利得 | +10.3pips | ○ |
| 勝率 | 61.9% | ○ |
| PF | 1.42 | ○ |
| PRR | 1.18 | △(取引回数少ない) |
| シャープレシオ | 0.31 | △ |
| 取引回数 | 21回 | △(要追加検証) |
結論: 期待利得とPFは良好だが、取引回数が少なすぎて信頼性に欠ける。
まとめ:バックテスト評価チェックリスト
最低限見るべき指標
- 期待利得 > 0(スプレッド込み)
- PF > 1.3
- 最大DD < 許容範囲
- 取引回数 > 100回(できれば500回以上)
より深く評価する指標
- PRR > 1.0(サンプルサイズ補正)
- リカバリファクター > 3
- シャープレシオ > 0.5
- ソルティノレシオ > シャープレシオ
注意点
- 単一指標だけで判断しない
- 過剰最適化に注意(PF > 3.0は疑え)
- モンテカルロシミュレーションで堅牢性を確認
- フォワードテストで最終確認
Pythonで一括計算
import pandas as pdimport numpy as np
def evaluate_backtest(trades, initial_capital=1000000): """ バックテスト結果を8指標で評価 trades: 'pips'カラムを持つDataFrame """ results = {}
# 基本統計 results['取引回数'] = len(trades) results['勝率'] = (trades['pips'] > 0).mean() * 100 results['期待利得'] = trades['pips'].mean()
# PF wins = trades[trades['pips'] > 0]['pips'].sum() losses = abs(trades[trades['pips'] < 0]['pips'].sum()) results['PF'] = wins / losses if losses > 0 else float('inf')
# PRR n_wins = len(trades[trades['pips'] > 0]) n_losses = len(trades[trades['pips'] < 0]) avg_win = trades[trades['pips'] > 0]['pips'].mean() if n_wins > 0 else 0 avg_loss = abs(trades[trades['pips'] < 0]['pips'].mean()) if n_losses > 0 else 0
num = (n_wins - np.sqrt(n_wins)) * avg_win den = (n_losses + np.sqrt(n_losses)) * avg_loss results['PRR'] = num / den if den > 0 else 0
# 最大DD capital = initial_capital peak = initial_capital max_dd = 0 for pips in trades['pips']: capital += pips * 1000 peak = max(peak, capital) dd = (peak - capital) / peak * 100 max_dd = max(max_dd, dd) results['最大DD%'] = max_dd
# リカバリファクター total_profit = trades['pips'].sum() * 1000 max_dd_amount = initial_capital * max_dd / 100 results['RF'] = total_profit / max_dd_amount if max_dd_amount > 0 else 0
# シャープレシオ results['シャープ'] = trades['pips'].mean() / trades['pips'].std() if trades['pips'].std() > 0 else 0
# ソルティノレシオ neg = trades[trades['pips'] < 0]['pips'] down_std = neg.std() if len(neg) > 0 else 0 results['ソルティノ'] = trades['pips'].mean() / down_std if down_std > 0 else 0
return results
# 使用例# results = evaluate_backtest(trades_df)# for k, v in results.items():# print(f"{k}: {v:.2f}")参考文献:
質問・リクエストがあればコメントください! 次回はモンテカルロシミュレーションの実装も解説予定です 📊
🎁おすすめツール・サービス
※上記リンクにはプロモーション(広告)が含まれています
量子相場謀略|ホソノP
ブログでは書けない本音のトレード戦略とEA開発の裏側を公開。 データに基づいた検証で、再現性のある手法だけをお届けします。