子供が生まれてから、夜中のドル円急変動を寝たまま食らうことが増えた。先月も米CPIの発表前後で1円以上動いて、翌朝ポジションを見て青ざめた。「ボラティリティが高い日だけポジションを小さくする」とか、事前に分かれば対処できるのに——そう思って調べたのがGARCHモデルだ。
GARCHモデルって何?(3行で)
GARCH(Generalized Autoregressive Conditional Heteroskedasticity)は、金融時系列のボラティリティが「大きく動いた後はしばらく大きく動く傾向がある」という性質(ボラティリティ・クラスタリング)をモデル化する統計手法だ。難しい名前だけど、要は「昨日荒れてたら今日も荒れやすい」を数式にしたもの。ドル円みたいにFXに向いてる。
なぜGARCHを調べたか
僕がよくやっていたのは「ATRでポジションサイズを調整する」方法だ(以前の記事で書いた)。でも ATRは過去N日の平均レンジであって、「明日のボラを予測する」モデルじゃない。GARCH なら条件付き分散を1日先予測できるので、「明日は荒れそうだからロット半分」という判断に使えるかもしれない。そういう動機で調べ始めた。
環境準備:archライブラリのインストール
PythonでGARCHを実装するなら arch ライブラリが定番だ。インストールは一行。
pip install arch yfinance pandas numpy matplotlib
ドル円データを取得してGARCH(1,1)を当てはめる
まずyfinanceでドル円の日足データを取得し、対数収益率を計算してGARCH(1,1)モデルに当てはめる。
import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from arch import arch_model
# ドル円日足データ取得(2年分)
ticker = yf.Ticker("JPY=X")
df = ticker.history(period="2y")
# 対数収益率(%スケールにするとGARCHの収束が安定)
df["log_ret"] = np.log(df["Close"] / df["Close"].shift(1)) * 100
df = df.dropna()
print(df["log_ret"].describe())
出力例:
count 502.000000
mean -0.003412
std 0.512834
min -2.847100
25% -0.271903
50% 0.002150
75% 0.280412
max 2.156300
次にGARCH(1,1)モデルを当てはめる。arch_model の p=1, q=1 がGARCH(1,1)の指定だ。
# GARCH(1,1) モデルの定義と推定
model = arch_model(
df["log_ret"],
vol="Garch", # ボラティリティモデル
p=1, # GARCH項のラグ次数
q=1, # ARCH項のラグ次数
dist="normal" # 誤差分布(t分布も試す価値あり)
)
result = model.fit(disp="off") # disp="off" で推定過程の出力を抑制
print(result.summary())
result.summary() の出力にはω(定数項)、α(ARCH係数)、β(GARCH係数)が表示される。α+βが1に近いほど「ボラティリティの持続性が高い」ことを意味する。ドル円は往々にして0.95前後になる。
1日先ボラティリティを予測する
# 1日先の条件付き分散を予測
forecast = result.forecast(horizon=1, reindex=False)
# 予測ボラティリティ(標準偏差、%単位)
pred_vol = np.sqrt(forecast.variance.values[-1, 0])
print(f"明日の予測ボラティリティ: {pred_vol:.4f}%")
# 過去の条件付きボラティリティの推移を可視化
cond_vol = result.conditional_volatility
plt.figure(figsize=(12, 5))
plt.plot(cond_vol.index, cond_vol.values, color="#f87171", linewidth=1)
plt.title("ドル円 条件付きボラティリティ(GARCH推定)")
plt.ylabel("ボラティリティ (%)")
plt.xlabel("日付")
plt.tight_layout()
plt.savefig("usdjpy_garch_vol.png", dpi=150)
plt.show()
予測ボラを使ってポジションサイジングに組み込む
実用的な使い方として、予測ボラティリティをポジションサイズ調整に使う例を示す。
# 過去の中央値ボラを基準にポジション倍率を計算
median_vol = cond_vol.median()
latest_vol = cond_vol.iloc[-1]
position_ratio = median_vol / latest_vol # ボラが高いほど小さくなる
position_ratio = np.clip(position_ratio, 0.25, 1.5) # 最小25%〜最大150%
print(f"基準ボラ(中央値): {median_vol:.4f}%")
print(f"直近ボラ: {latest_vol:.4f}%")
print(f"→ ポジション倍率: {position_ratio:.2f}x")
これで「ボラが平均の2倍→ポジション半分」みたいな機械的なリスク管理ができる。指標発表前後に自動でロットを下げたい僕には、まさに求めていた機能だった。
GARCH(1,1)の限界と注意点
GARCHにはいくつか注意点がある。まず、価格の方向(上か下か)は予測しない——あくまで「どれくらい動くか」の予測だ。また、急激なフラッシュクラッシュには過去データだけでは対応しきれない。誤差分布を正規分布ではなくt分布(dist="t")にすると、テールリスクをより適切にモデル化できるので試してみてほしい。
まとめ
GARCHモデルを使うと、過去のボラティリティの推移から1日先のリスクをある程度定量化できる。実装自体はarchライブラリのおかげで10行程度で済む。個人的には「指標発表日の前日に予測ボラをチェックして、高ければポジション半減」くらいの使い方が現実的だと感じた。次はt分布GARCHとEGARCH(非対称性あり)の比較をやってみたい。

