ドル円のトレードを始めたころ、毎回「何ロット入ればいいんだろ」って感覚でやってました。子供が生まれてから相場を見る時間がほぼなくなって、それがかえって良かったのかもしれません。適当にロット数を決めていたのが、ちゃんと計算するようになったので笑。今回はATR(Average True Range)を使ったポジションサイジングをPythonで実装する方法を紹介します。
なぜポジションサイジングが大事なのか
正直、最初はエントリータイミングばかり気にしてました。でも資金管理が甘いと、たとえ勝率60%の戦略でも連敗したときに退場してしまいます。ポジションサイジングとは「1回のトレードでどれだけのリスクを取るか」を事前に計算するプロセスです。FXのドル円では特にボラティリティ(価格変動の大きさ)が日によって全然違うので、固定ロットで入り続けるのは危ないと思います。
ATRとは何か
ATR(Average True Range)は、一定期間の価格変動の平均を示すテクニカル指標です。例えば14日ATRが「0.80円」なら、ここ2週間で平均して1日に0.80円動いているということ。このATRをリスク管理の基準として使います。
計算式のイメージ:
- True Range = max(高値-安値, |高値-前日終値|, |安値-前日終値|)
- ATR = True Rangeの14日移動平均
ポジションサイジングの考え方
基本的な考え方は「1回のトレードで口座残高の何%を失っても許容できるか」を先に決めること。一般的には1〜2%が推奨されています。僕は子供の教育費を考えると怖いので1%で設定しています笑。
計算式はシンプルです:
ロット数 = (口座残高 × リスク許容率) ÷ (ATR × ストップロス係数 × 1pipの価値)
PythonでATRベースのポジションサイジングを実装
まずyfinanceでドル円のデータを取得してATRを計算します。
import yfinance as yf
import pandas as pd
import numpy as np
def calculate_atr(symbol='JPY=X', period='3mo', atr_period=14):
"""ATRを計算する関数"""
df = yf.download(symbol, period=period, interval='1d', auto_adjust=True)
# True Range計算
df['H-L'] = df['High'] - df['Low']
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
# ATR(14日移動平均)
df['ATR'] = df['TR'].rolling(window=atr_period).mean()
latest_atr = df['ATR'].iloc[-1]
latest_price = df['Close'].iloc[-1]
return latest_atr, latest_price, df
def calculate_position_size(
account_balance=500000, # 口座残高(円)
risk_rate=0.01, # リスク許容率(1%)
atr=None,
stop_loss_atr_multiplier=2.0, # ATRの何倍でストップを置くか
lot_unit=10000, # 1ロット = 1万通貨
):
"""ポジションサイジングを計算する"""
if atr is None:
raise ValueError("ATRを指定してください")
# 許容損失額(円)
max_loss_jpy = account_balance * risk_rate
# ストップロス幅(円換算)
# ドル円の場合、1pip = 0.01円
stop_loss_pips = atr * stop_loss_atr_multiplier
stop_loss_jpy_per_lot = stop_loss_pips * lot_unit * 0.01 # 1ロットあたりの損失
# ロット数計算
lots = max_loss_jpy / stop_loss_jpy_per_lot
return {
'account_balance': account_balance,
'risk_rate': risk_rate,
'max_loss_jpy': max_loss_jpy,
'atr': atr,
'stop_loss_pips': stop_loss_pips,
'recommended_lots': round(lots, 2),
'recommended_units': int(lots * lot_unit)
}
# 実行例
atr, price, df = calculate_atr()
print(f"現在のドル円: {price:.2f}円")
print(f"14日ATR: {atr:.3f}円")
result = calculate_position_size(
account_balance=500000,
risk_rate=0.01,
atr=atr,
stop_loss_atr_multiplier=2.0
)
print("
--- ポジションサイジング結果 ---")
print(f"口座残高: {result['account_balance']:,}円")
print(f"リスク許容額: {result['max_loss_jpy']:,.0f}円")
print(f"ストップロス幅: {result['stop_loss_pips']:.3f}円 ({result['stop_loss_pips']*100:.1f}pips)")
print(f"推奨ロット数: {result['recommended_lots']}ロット")
print(f"推奨取引量: {result['recommended_units']:,}通貨")
実行結果のイメージ
現在のドル円: 152.34円
14日ATR: 0.823円
--- ポジションサイジング結果 ---
口座残高: 500,000円
リスク許容額: 5,000円
ストップロス幅: 1.646円 (164.6pips)
推奨ロット数: 0.30ロット
推奨取引量: 3,042通貨
さらに改良:ボラティリティに応じて動的に調整
ATRが高い(ボラが荒い)ときは自動的にロット数を減らす仕組みも作れます。
def dynamic_position_sizing(
account_balance=500000,
risk_rate=0.01,
current_atr=None,
baseline_atr=0.8, # 基準ATR
max_lots=1.0,
min_lots=0.05
):
"""ボラティリティに応じた動的ポジションサイジング"""
base_result = calculate_position_size(account_balance, risk_rate, current_atr)
# ボラティリティ調整係数
vol_adjustment = baseline_atr / current_atr
adjusted_lots = base_result['recommended_lots'] * vol_adjustment
# 上限・下限を設定
adjusted_lots = min(max(adjusted_lots, min_lots), max_lots)
return {
**base_result,
'vol_adjustment': vol_adjustment,
'adjusted_lots': round(adjusted_lots, 2)
}
まとめ
ATRベースのポジションサイジングは、市場のボラティリティに合わせて自動的にリスクを調整してくれるので、固定ロットよりずっと安全です。特にドル円は指標発表や要人発言で急激にATRが上がることがあるので、これを入れておくだけで大きな損失を防げます。
個人的には、このコードを毎朝自動実行して「今日のドル円、何ロットまでOK」をSlackに通知する仕組みを作りたいと思っています。子供が起きてくる前の5分でチェックできるくらい自動化したい笑。次回はその通知システムの実装をやってみます。
