FOMCドル円反応をPythonで自動集計!金利発表後の値動きパターンを分析する

Python実装・コード

先月のFOMC(米連邦公開市場委員会)の発表直後、ドル円が一瞬で1円以上動いて、僕が入れていたポジションが一瞬でロスカット。。。「あれ、これって毎回こういう動きするの?」という素朴な疑問から、過去の発表日の値動きをまとめて集計してみた。Pythonでサクッと分析できたので、コードをそのまま公開する。

なぜFOMC発表前後を分析したかったか

ドル円FXをやっていると、月に何度か「なんかいきなり大きく動いたぞ」という場面がある。調べてみると、多くの場合は米国の経済指標や金融政策の発表が原因だ。中でもFOMCは影響が最大級で、「利上げ・据え置き・利下げ」という結果だけでなく、声明文の言葉一つで数十pips動くことがある。

「じゃあ発表前にポジションを閉じれば安全なのか」「発表後の方向感は読めるのか」 → 感覚論でなく、データで確認したくなった。

FOMCの発表日時を取得する

FOMCの発表日時はFRBの公式サイトで公開されているが、スクレイピングが面倒なので、今回は過去の発表日を手動でリストにした。発表時間は米国時間14:00(日本時間で夏時間3:00、冬時間4:00)が多い。

import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg')  # GUIなし環境用

# 過去のFOMC発表日(UTC時間で記載)
# 2024年〜2026年の主要発表日
fomc_dates_utc = [
    "2024-01-31 19:00",
    "2024-03-20 18:00",
    "2024-05-01 18:00",
    "2024-06-12 18:00",
    "2024-07-31 18:00",
    "2024-09-18 18:00",
    "2024-11-07 19:00",
    "2024-12-18 19:00",
    "2025-01-29 19:00",
    "2025-03-19 18:00",
    "2025-05-07 18:00",
    "2025-06-18 18:00",
    "2025-07-30 18:00",
    "2025-09-17 18:00",
    "2025-11-06 19:00",
    "2025-12-17 19:00",
    "2026-01-28 19:00",
    "2026-03-18 18:00",
    "2026-05-06 18:00",
    "2026-06-17 18:00",  # 直近
]

fomc_dt = pd.to_datetime(fomc_dates_utc, utc=True)
print(f"FOMC発表日リスト: {len(fomc_dt)}件")
print(fomc_dt[-3:])

発表前後のドル円変動を集計する

yfinanceでUSD/JPY(ドル円)の1分足データを取得して、各FOMC発表時刻の前後±60分の値動きを集計する。

def get_fomc_reaction(fomc_datetime, window_minutes=60):
    """
    FOMC発表時刻の前後window_minutes分のドル円値動きを取得する。
    返り値: DataFrameまたはNone
    """
    # 発表時刻の前後を取得(yfinanceは最大7日分の1分足)
    start = fomc_datetime - pd.Timedelta(hours=2)
    end = fomc_datetime + pd.Timedelta(hours=2)

    ticker = yf.Ticker("USDJPY=X")
    df = ticker.history(
        start=start.strftime("%Y-%m-%d"),
        end=(end + pd.Timedelta(days=1)).strftime("%Y-%m-%d"),
        interval="1m"
    )

    if df.empty:
        return None

    df.index = pd.to_datetime(df.index, utc=True)

    # 発表時刻付近のデータを切り出す
    mask = (df.index >= start) & (df.index <= end)
    df_window = df[mask].copy()

    if len(df_window) < 10:
        return None

    # 発表時刻に最も近いインデックスを起点にする
    closest_idx = (df_window.index - fomc_datetime).total_seconds().abs().argmin()
    base_price = df_window['Close'].iloc[closest_idx]

    # 発表時刻を0分としたpips変動を計算
    df_window['minutes_from_fomc'] = (
        (df_window.index - fomc_datetime).total_seconds() / 60
    ).round().astype(int)
    df_window['pips'] = (df_window['Close'] - base_price) * 100  # ドル円は0.01=1pips

    return df_window[['minutes_from_fomc', 'pips']]


# 最近6ヶ月分のFOMCについて集計(yfinanceの制限で最近のデータのみ)
recent_fomc = [dt for dt in fomc_dt if dt >= pd.Timestamp.now(tz='UTC') - pd.Timedelta(days=180)]

print(f"分析対象のFOMC発表: {len(recent_fomc)}件")
results = []
for dt in recent_fomc:
    reaction = get_fomc_reaction(dt)
    if reaction is not None:
        reaction['fomc_date'] = dt.strftime("%Y-%m-%d")
        results.append(reaction)
        print(f"✓ {dt.strftime('%Y-%m-%d %H:%M')} UTC - データ取得OK")
    else:
        print(f"✗ {dt.strftime('%Y-%m-%d %H:%M')} UTC - データなし")

if results:
    df_all = pd.concat(results)
    print(f"\n合計レコード数: {len(df_all)}")

値動きをグラフで可視化する

各FOMC発表後の値動きパターンをまとめてプロットしてみる。

if results:
    fig, axes = plt.subplots(1, 2, figsize=(14, 5))

    # 左: 各発表の値動きを重ね描き
    ax = axes[0]
    for r in results:
        date_label = r['fomc_date'].iloc[0]
        pivot = r[(-30 <= r['minutes_from_fomc']) & (r['minutes_from_fomc'] <= 60)]
        ax.plot(pivot['minutes_from_fomc'], pivot['pips'],
                alpha=0.6, linewidth=1.2, label=date_label)

    ax.axvline(x=0, color='red', linestyle='--', linewidth=1.5, label='FOMC発表')
    ax.axhline(y=0, color='gray', linestyle='-', linewidth=0.5)
    ax.set_xlabel('発表からの経過分数')
    ax.set_ylabel('pips変動(発表時点を0基準)')
    ax.set_title('FOMC発表前後のドル円変動')
    ax.legend(fontsize=8, loc='upper left')
    ax.grid(True, alpha=0.3)

    # 右: 平均的な値動きパターン
    ax2 = axes[1]
    df_pivot = df_all.groupby('minutes_from_fomc')['pips'].agg(['mean', 'std'])
    mask = (-30 <= df_pivot.index) & (df_pivot.index <= 60)
    df_pivot = df_pivot[mask]

    ax2.fill_between(df_pivot.index,
                     df_pivot['mean'] - df_pivot['std'],
                     df_pivot['mean'] + df_pivot['std'],
                     alpha=0.2, color='blue', label='±1σ範囲')
    ax2.plot(df_pivot.index, df_pivot['mean'], color='blue',
             linewidth=2, label='平均変動')
    ax2.axvline(x=0, color='red', linestyle='--', linewidth=1.5, label='FOMC発表')
    ax2.axhline(y=0, color='gray', linestyle='-', linewidth=0.5)
    ax2.set_xlabel('発表からの経過分数')
    ax2.set_ylabel('pips変動(平均)')
    ax2.set_title('FOMC発表後のドル円平均パターン')
    ax2.legend()
    ax2.grid(True, alpha=0.3)

    plt.tight_layout()
    plt.savefig('fomc_usdjpy_analysis.png', dpi=150, bbox_inches='tight')
    print("グラフを保存: fomc_usdjpy_analysis.png")

分析してわかったこと

実際に動かしてみてわかったことをまとめる(yfinanceの制限で直近数回分のデータのみでの結果):

①発表直後5分以内の変動が最大
発表から0〜5分の間に最も大きな動きが出る。この時間帯はスプレッドが拡大していることも多く、個人投資家が飛び込むのは非常にリスクが高い。

②30分後には落ち着く傾向
方向感が定まったとしても、発表後30分以降は比較的落ち着いてくる。「発表直後は触らず、30分後に方向感を確認してからエントリー」という戦略の方が安全かもしれない。

③利上げ・据え置き・利下げで方向性は全然違う
当然だけど、サプライズがあるかどうかで値動きの方向が逆になる。「今回は利上げ」でも「市場予想より小さかった」場合はドル安になることがある。発表内容だけでなく「市場予想との差」が重要だ。

まとめ+個人的な感想

Pythonを使えば「なんとなく怖い」だったFOMC前後の値動きを、データで客観的に見られるようになった。これは意外と精神的に楽になる効果があって、「怖いから何もしない」ではなく「データを見て判断する」という姿勢に変わってきた気がする。

次は「発表前30分と発表後30分のボラティリティ比較」と「利上げ/据え置き/利下げ別のパターン分類」をやってみたい。FOMCの分析を深めれば、ドル円のポジション管理がもう少し合理的にできるんじゃないかと思っている。。。

タイトルとURLをコピーしました