ケリー基準と分数ケリー
ケリー基準は、勝率と損益比が検証済みの売買ルールに対して、1トレードでリスクにさらす口座資金の割合を決めるための考え方です。トレードの期待値を建玉サイズへ変換し、長期の対数成長率を最大化する賭け率を求めます。裁量の思いつきエントリーには向かず、同一ルールで十分なサンプルがある系統的な売買を前提にします。
定義
ケリー基準は、各回の資金を一定割合で賭ける反復ゲームにおいて、長期の期待対数成長率を最大化する賭け率を求める式です。
勝つ確率を 、負ける確率を 、勝ったときに賭け金 1 に対して得る純利益倍率を とします。資金のうち を賭けると、1回後の資金倍率は次になります。
期待対数成長率は、
これを で微分して 0 と置きます。
整理すると、
なので、
同値な形として、
となります。
- のときだけ賭ける
- は期待値がない
- はその方向に賭けてはいけない
- のイーブン勝負では
例として、勝率 、損益比 なら、
つまりフルケリーでは口座資金の 10% をリスクにさらします。これは理論上の最適値であり、実運用では大きすぎます。
FX への置き換え
FX では を「必要証拠金の割合」や「レバレッジ倍率」として扱ってはいけません。 は 損切りにかかったときに失う口座資金の割合 と定義します。
USD/JPY のロングで次の条件を考えます。
- エントリー: 150.00
- 損切り: 149.60
- 利確: 150.50
- ストップ幅: 40 pips
- 利確幅: 50 pips
- 往復コスト、スリッページ見込み: 1 pip
このとき、勝ちの純 pips と負けの純 pips は保守的に次で置きます。
損益比は、
検証済み勝率を 、 とすると、
フルケリーは約 13.7% になります。これは USD/JPY の実運用では過大です。勝率推定の誤差、スプレッド拡大、連敗、経済指標、日銀と財務省関連ヘッドライン、米金利急変を考えると、この値をそのまま使ってはいけません。
分数ケリー
実運用ではフルケリーを縮小します。
- フルケリー:
- ハーフケリー:
- クオーターケリー:
上の例では、
| 方式 | 計算 | リスク |
|---|---|---|
| フルケリー | 13.7% | |
| ハーフケリー | 6.85% | |
| クオーターケリー | 3.43% |
それでも大きい値です。FX ではさらに固定上限を置きます。
実務上は、検証済みシステムでも を 0.25% から 2% 程度に置きます。裁量要素が強いなら 0.25% から 0.5% を上限にします。
ハーフケリーの意味
ハーフケリーは「利益を半分にする」方法ではありません。小さいリターン近似では、期待対数成長率を次で近似できます。
このとき最適比率は、
分数ケリー を代入すると、最大成長率に対する比はおおよそ、
したがって、
| 方式 | 成長率の近似比 | ポジションサイズ |
|---|---|---|
| フルケリー | 100% | 100% |
| ハーフケリー | 75% | 50% |
| クオーターケリー | 43.75% | 25% |
ハーフケリーは、理論上の成長率を大きく残しながら、ドローダウンと推定誤差への感度を下げます。クオーターケリーはさらに保守的で、FX ではこちらを基準にするほうが現実的です。
破産確率
ケリー基準は「フルケリーなら破産しない」という意味ではありません。各回で資金の一部だけを失う設定なら、数学的に資金が完全なゼロへ到達しにくいだけで、実務上の破産は簡単に起きます。
実務上の破産は次で定義します。
- 口座資金が初期資金の 50% を下回る
- 最大ドローダウンが 30% を超える
- 必要証拠金維持率を割る
- 精神的にルールを続けられない損失に達する
固定額ベットの単純なイーブン勝負では、勝率 、破産ラインまで 単位ある場合、究極破産確率は近似的に次で見ます。
ただしこれは USD/JPY の実運用には直接使いません。FX では損益幅が一定でなく、スリッページがあり、取引が独立でなく、同じドル円テーマで連敗が連続します。
より実用的には、検証済みトレード列をブートストラップし、次をモンテカルロで確認します。
- 最大ドローダウン分布
- 連敗長
- 証拠金維持率の最低値
- 破産ライン到達確率
- 月次と年次の損益分布
- スプレッド拡大時の悪化
- 指標前後を除外した場合の変化
USD/JPY での使いどころ
USD/JPY は流動性が高く、BIS 2025年調査でも USD/JPY は主要通貨ペアの一つです。ただし、流動性が高いことは「損失が小さい」ことを意味しません。USD/JPY は米金利、日本国債利回り、日銀政策、財務省の為替介入観測、米雇用統計、CPI、FOMC で急変しやすい通貨ペアです。
ケリー基準を使うなら、次のように限定します。
- 同一ルールで十分なサンプル数がある
- エントリー前に損切り幅と利確幅が決まっている
- 勝率 と損益比 をコスト控除後で推定している
- 東京時間、ロンドン時間、NY時間を分けて検証している
- 指標トレードと通常トレードを混ぜていない
- ロングとショートを分けて集計している
- 介入警戒局面を別 regime として扱っている
USD/JPY のロット計算では、JPY 口座なら次で概算できます。
USD/JPY の 1 pip を 0.01 円とすると、USD 建て通貨数量 の 1 pip 価値は、
ストップ幅を pips とすると、
例として、口座資金 1,000,000 円、使用リスク 、ストップ幅 40 pips なら、
したがって、約 25,000 USD のポジションになります。1万通貨単位なら 2.5 ロット、10万通貨単位なら 0.25 ロットです。
必要証拠金は別に確認します。USD/JPY が 150 円、レバレッジ 25倍なら、25,000 USD の円建て想定元本は、
必要証拠金は、
損失リスクは 10,000 円、必要証拠金は 150,000 円であり、両者は別物です。
Python 実装スケッチ
from __future__ import annotations
import numpy as npimport pandas as pd
def kelly_binary(p: float, b: float) -> float: """ Binary Kelly fraction.
p: win probability after costs. b: net win / net loss, e.g. 49 pips / 41 pips. returns: full Kelly fraction. """ if not 0 <= p <= 1: raise ValueError("p must be in [0, 1]") if b <= 0: raise ValueError("b must be positive")
q = 1.0 - p return (b * p - q) / b
def fractional_kelly( p: float, b: float, fraction: float = 0.25, cap: float = 0.01,) -> float: """ Conservative tradable fraction.
fraction=0.5 is half Kelly. fraction=0.25 is quarter Kelly. cap is the absolute risk cap per trade. """ full = kelly_binary(p, b) scaled = fraction * full return max(0.0, min(scaled, cap))
def estimate_binary_params_from_trades(r_multiples: pd.Series) -> tuple[float, float]: """ Estimate p and b from R-multiple trade results.
Example: +1.2 means +1.2R -1.0 means -1.0R -1.3 means slippage beyond stop
This is a rough binary approximation. For fat-tailed results, optimize expected log growth directly instead. """ wins = r_multiples[r_multiples > 0] losses = r_multiples[r_multiples < 0]
if len(wins) == 0 or len(losses) == 0: raise ValueError("Need both winning and losing trades")
p = len(wins) / len(r_multiples) avg_win = wins.mean() avg_loss = -losses.mean() b = avg_win / avg_loss
return float(p), float(b)
def expected_log_growth(f: float, r_multiples: np.ndarray) -> float: """ Empirical expected log growth for general R-multiple outcomes.
f is the fraction of equity risked per 1R. If a trade returns -1R, equity multiplier is 1 - f. If a trade returns +1.5R, equity multiplier is 1 + 1.5f. """ multipliers = 1.0 + f * r_multiples if np.any(multipliers <= 0): return -np.inf return float(np.mean(np.log(multipliers)))
def kelly_empirical_grid( r_multiples: pd.Series, max_fraction: float = 0.10, steps: int = 10_001,) -> tuple[float, float]: """ Grid-search Kelly fraction from empirical R-multiple distribution.
This avoids forcing every trade into a binary win/loss model. Use out-of-sample and walk-forward validation before trusting it. """ r = r_multiples.dropna().to_numpy(dtype=float)
if len(r) == 0: raise ValueError("No trades")
# Keep f below the level that would make the worst historical loss fatal. worst = r.min() feasible_max = max_fraction if worst < 0: feasible_max = min(feasible_max, 0.999 / abs(worst))
grid = np.linspace(0.0, feasible_max, steps) growth = np.array([expected_log_growth(f, r) for f in grid]) idx = int(np.argmax(growth))
return float(grid[idx]), float(growth[idx])
def usdjpy_units_for_jpy_account( equity_jpy: float, risk_fraction: float, stop_pips: float, pip_size: float = 0.01,) -> float: """ Position size for USD/JPY with a JPY-denominated account.
Returns USD units. For USD/JPY, 1 pip is usually 0.01 JPY. """ if equity_jpy <= 0: raise ValueError("equity_jpy must be positive") if not 0 < risk_fraction < 1: raise ValueError("risk_fraction must be in (0, 1)") if stop_pips <= 0: raise ValueError("stop_pips must be positive")
risk_jpy = equity_jpy * risk_fraction units = risk_jpy / (stop_pips * pip_size) return float(units)
def margin_required_jpy( usdjpy_price: float, usd_units: float, leverage: float,) -> float: """ Approximate margin requirement in JPY. """ if usdjpy_price <= 0 or usd_units <= 0 or leverage <= 0: raise ValueError("inputs must be positive")
notional_jpy = usdjpy_price * usd_units return float(notional_jpy / leverage)
def monte_carlo_ruin_probability( r_multiples: pd.Series, risk_fraction: float, n_trades: int = 300, n_paths: int = 20_000, ruin_level: float = 0.5, seed: int = 42,) -> dict[str, float]: """ Bootstrap trade outcomes and estimate practical ruin/drawdown risk.
ruin_level=0.5 means equity falling to 50% of initial equity. """ rng = np.random.default_rng(seed) r = r_multiples.dropna().to_numpy(dtype=float)
if len(r) == 0: raise ValueError("No trades")
samples = rng.choice(r, size=(n_paths, n_trades), replace=True) multipliers = 1.0 + risk_fraction * samples
# A path with any non-positive multiplier is immediately ruined. invalid = np.any(multipliers <= 0, axis=1)
equity = np.cumprod(np.maximum(multipliers, 1e-12), axis=1) running_peak = np.maximum.accumulate(equity, axis=1) drawdown = 1.0 - equity / running_peak
min_equity = equity.min(axis=1) max_dd = drawdown.max(axis=1)
ruined = invalid | (min_equity <= ruin_level)
return { "ruin_probability": float(np.mean(ruined)), "median_terminal_equity": float(np.median(equity[:, -1])), "p05_terminal_equity": float(np.quantile(equity[:, -1], 0.05)), "p95_terminal_equity": float(np.quantile(equity[:, -1], 0.95)), "median_max_drawdown": float(np.median(max_dd)), "p95_max_drawdown": float(np.quantile(max_dd, 0.95)), }
if __name__ == "__main__": p = 0.53 b = 49 / 41
full = kelly_binary(p, b) half = fractional_kelly(p, b, fraction=0.5, cap=0.02) quarter = fractional_kelly(p, b, fraction=0.25, cap=0.01)
print({"full": full, "half_capped": half, "quarter_capped": quarter})
units = usdjpy_units_for_jpy_account( equity_jpy=1_000_000, risk_fraction=quarter, stop_pips=40, ) margin = margin_required_jpy( usdjpy_price=150.0, usd_units=units, leverage=25.0, )
print({"usd_units": units, "margin_jpy": margin})落とし穴
勝率を過大評価する
ケリー基準は に極端に敏感です。勝率 52% と 55% では推奨リスクが大きく変わります。バックテストの勝率をそのまま使わないようにします。
保守的には、推定勝率を 50% 側へ縮小します。
ここで とします。例えば なら、推定勝率の優位性を半分しか信用しません。
損益比を美化する
利確 50 pips、損切り 40 pips でも、実際の は ではありません。スプレッド、滑り、約定拒否、週明けギャップ、指標直後の飛びを入れます。
平均損失には、通常の損切りだけでなく、滑った損切りを含めます。
トレードが独立していない
ケリー基準の基本形は、同じゲームを独立に繰り返す前提が強いものです。USD/JPY ではこの前提が崩れやすくなります。
- 米金利テーマで同じ方向に連敗する
- 日銀イベント前後で regime が変わる
- 東京時間の逆張りと NY 時間の順張りを混ぜる
- 同じシグナルが短時間に連発する
- クロス円と同時に持つと実質的に JPY リスクが重複する
相関したトレードを独立トレードとして扱うと、破産確率を過小評価します。
証拠金とリスクを混同する
必要証拠金が少ないことは、リスクが小さいことを意味しません。USD/JPY で 25倍レバレッジを使えるとしても、25倍で張る必要はありません。
管理すべき順序は次のとおりです。
- 損切り幅を決める
- 口座資金に対する許容損失 を決める
- 通貨数量を計算する
- 必要証拠金と維持率を確認する
- 指標、週末、流動性低下時の追加リスクを確認する
フルケリーを安全だと誤解する
フルケリーは長期の対数成長率を最大化しますが、短期の最大ドローダウンを最小化しません。ドローダウン制約があるなら、分数ケリーか、明示的なドローダウン制約付き最適化を使います。
破産確率を平均値で隠す
期待値が正でも、連敗で運用停止になるなら実務では失敗です。次の条件を先に決めます。
- 最大許容ドローダウン
- 月間損失停止ライン
- 連敗時の縮小ルール
- 指標前後の取引停止ルール
- スプレッドが通常時の何倍なら停止するか
実運用ルール例
USD/JPY のシステムにケリー基準を使うなら、次の手順に固定します。
- 過去トレードを R 倍率で保存する
- コスト控除後の と を推定する
- 外れ値を消さずに、滑った損失を含める
- ロング、ショート、時間帯、指標有無で分けて推定する
- を保守的に 50% 側へ縮小する
- も保守的に下げる
- クオーターケリーを計算する
- 1トレード上限でさらにキャップする
- モンテカルロで破産確率と最大ドローダウンを確認する
- 実運用後は月次で再推定し、悪化したらサイズを落とす
最終的な使用リスクは次の形にします。
ここで、
- : 保守的な と で計算したフルケリー
- : 1トレードの絶対上限
- : 同時保有ポジション全体の上限
参考
- J. L. Kelly Jr., “A New Interpretation of Information Rate”, Bell System Technical Journal, 1956. https://doi.org/10.1002/j.1538-7305.1956.tb03809.x
- Kelly criterion, Wikipedia. https://en.wikipedia.org/wiki/Kelly_criterion
- Chung-Han Hsieh and B. Ross Barmish, “On Kelly Betting: Some Limitations”, arXiv:1710.01787. https://arxiv.org/abs/1710.01787
- Enzo Busseti, Ernest K. Ryu, Stephen Boyd, “Risk-Constrained Kelly Gambling”, arXiv:1603.06183. https://arxiv.org/abs/1603.06183
- BIS, “Triennial Central Bank Survey 2025: OTC foreign exchange turnover in April 2025”. https://www.bis.org/statistics/rpfx25.htm
- CFTC, “Fraud Advisory: Foreign Currency (Forex) Fraud”. https://www.cftc.gov/LearnAndProtect/AdvisoriesAndArticles/fraudadv_forex.html
- CFTC, “Foreign Currency Trading”. https://www.cftc.gov/LearnAndProtect/AdvisoriesAndArticles/ForeignCurrencyTrading/index.htm