Live release feed
Sub-second macro releases for FX backtests
Point-in-time history
Official CPI, jobs, GDP, and central-bank events with point-in-time history.
$25/month 14-day free trial
Start Free Trial
バックテスト.py で FX マクロ戦略をバックテストする方法 image
Share headline card X LinkedIn Email
Download

Implementation

How-To Guides

バックテスト.py で FX マクロ戦略をバックテストする方法

FXMacroDataの中央銀行発表データを活用して合成のキャリ・スプレッド指数とGBP/USDキャリ戦略のバックテストをバックテストする手順ガイド backtesting.py 外部価格プロバイダは必要ない.

他言語版 English
Share article X LinkedIn Email

このガイドの終わりまでに,FXMacroDataのみを使用する Python バックテストを完了します. 外部価格プロバイダは必要ありません. GBPとUSDの政策レートの履歴を取得し,レート差から直接合成のキャリー・スプレッドインデックスを作成し,それを実行します. バックテスト.py 株式曲線グラフと取引別統計を作成する.

条件

  • Python 3.10 以降
  • FXMacroData API キーを (登録する / サブスクリプトドルエンドポイントは無料)
  • パンダの基本的な知識 データフレーム
  • pip インストールする backtestingほら requestsほら pandasほら numpy

方法: キャリアインデックスバックテスト

バックテスト.py インタラクティブなボケグラフ,主要パフォーマンスメトリック (シャープ比率,最大引き込み率,勝利率) とパラメータ最適化を単一の方法呼び出しから生成する軽量なイベント駆動シミュレーションライブラリです.

価格の外部供給に頼るのではなく,このガイドは 合成のキャリー・スプレッド指数 概念は,KB/USDレート差 (BoEレートマイナスFedレート) は,日々の利息-仮説的リターンを累積する.その累積値をバックテスト"価格"シリーズとして使用し,その後,イングランド銀行が政策レートを変更するたびに火力入力信号を表示します.

モデル化されている価格は,即時FXの報じではなく, 利回り差を保持する理論的P&Lです. 価格のシミュレーションは,


ステップ 1 依存関係をインストールする

pip install backtesting requests pandas numpy

Step 2 — Fetch policy-rate histories from FXMacroData

双方の 政策金利の最終値は GBP ほら 政策金利の最終値はUSD 精密な数字で表します. 詳細な数字で表示します. announcement_datetime ユニックスタイムスタンプ.USDデータは API キーなしで利用できます.

import requests
import pandas as pd
import numpy as np

API_KEY = "YOUR_API_KEY"
BASE = "https://fxmacrodata.com/api/v1"

def fetch_policy_rate(currency: str) -> pd.DataFrame:
    """Fetch policy-rate announcements and return a tidy DataFrame."""
    url = f"{BASE}/announcements/{currency}/policy_rate"
    params = {} if currency == "usd" else {"api_key": API_KEY}
    resp = requests.get(url, params=params, timeout=15)
    resp.raise_for_status()
    rows = resp.json().get("data", [])
    df = pd.DataFrame(rows)
    df["ann_date"] = (
        pd.to_datetime(df["announcement_datetime"], unit="s", utc=True)
        .dt.normalize()
    )
    df["rate"] = pd.to_numeric(df["val"], errors="coerce")
    return df[["ann_date", "rate"]].sort_values("ann_date").reset_index(drop=True)

gbp_rates = fetch_policy_rate("gbp")
usd_rates = fetch_policy_rate("usd")

print(gbp_rates.tail(6))
             ann_date  rate
23 2024-05-09 00:00:00  5.25
24 2024-06-20 00:00:00  5.25
25 2024-08-01 00:00:00  5.00
26 2024-09-19 00:00:00  5.00
27 2024-11-07 00:00:00  4.75
28 2024-12-19 00:00:00  4.75

ステップ3 日々のキャリ・スプレッドインデックスを作成

発表日間の各政策レートは恒定であるため,各カレンダー日ごとに日比率を生成するために両シリーズを先延填することができます.スプレッドはGBPレートマイナスUSDレートです.キャリーインデックスは100のベースから毎日累積する化合物で,長いGBPキャリーポジションの経済的P&Lを正確に複製します.

def build_carry_index(
    gbp_df: pd.DataFrame,
    usd_df: pd.DataFrame,
    start: str = "2005-01-03",
    end: str = "2025-01-01",
) -> pd.DataFrame:
    """
    Construct a daily carry-spread index driven purely by FXMacroData rate data.

    Returns a DataFrame with OHLCV columns suitable for backtesting.py.
    """
    # Daily date range (weekdays only)
    idx = pd.bdate_range(start=start, end=end, tz="UTC")

    # Forward-fill rates across the daily index
    def ffill_rate(rate_df: pd.DataFrame) -> pd.Series:
        s = pd.Series(index=idx, dtype=float)
        for _, row in rate_df.iterrows():
            d = row["ann_date"]
            if d in s.index:
                s.loc[d] = row["rate"]
        return s.ffill()

    gbp_daily = ffill_rate(gbp_df)
    usd_daily = ffill_rate(usd_df)

    # Daily spread (%) → daily accrual factor
    spread_pct = gbp_daily - usd_daily          # e.g. 5.25 - 5.50 = -0.25
    daily_return = spread_pct / 100 / 252        # annualised → daily

    # Cumulative carry index (start at 100)
    carry_index = (1 + daily_return).cumprod() * 100

    # backtesting.py expects Open / High / Low / Close / Volume columns
    price = pd.DataFrame(index=idx)
    price["Close"] = carry_index
    price["Open"]  = carry_index.shift(1).bfill()
    price["High"]  = price[["Open", "Close"]].max(axis=1)
    price["Low"]   = price[["Open", "Close"]].min(axis=1)
    price["Volume"] = 0
    price.dropna(inplace=True)
    return price

price = build_carry_index(gbp_rates, usd_rates)
print(price.tail(5))
                              Open       High        Low      Close  Volume
2024-12-25 00:00:00+00:00   99.621    99.631     99.611     99.621       0
2024-12-26 00:00:00+00:00   99.631    99.641     99.621     99.631       0
2024-12-27 00:00:00+00:00   99.641    99.651     99.631     99.641       0
2024-12-30 00:00:00+00:00   99.651    99.661     99.641     99.651       0
2024-12-31 00:00:00+00:00   99.661    99.671     99.651     99.661       0

GBPの利回りがUSDの利上げを上回る時,インデックスは上昇し,FedがBoEよりも早く引き締まる時,それは低下する.これはまさに,P&L経路である.


ステップ4 入力信号列を構成する

添付する Signal 価格の列 DataFrame: +1 銀行が上昇する際のバーで −1 傷口に 0 待機またはデータがない

def build_signal_series(rate_df: pd.DataFrame, index: pd.DatetimeIndex) -> pd.Series:
    """
    Returns +1 on a hike bar, -1 on a cut bar, 0 otherwise.
    Aligned to the given DatetimeIndex.
    """
    signal = pd.Series(0.0, index=index)
    prev = None
    for _, row in rate_df.iterrows():
        d, v = row["ann_date"], row["rate"]
        if prev is not None and d in signal.index:
            if v > prev:
                signal.loc[d] = 1.0    # hike → long carry
            elif v < prev:
                signal.loc[d] = -1.0   # cut  → short carry
        prev = v
    return signal

price["Signal"] = build_signal_series(gbp_rates, price.index)

# Show signal events only
print(price.loc[price["Signal"] != 0, ["Close", "Signal"]].tail(8))
                              Close  Signal
2022-08-04 00:00:00+00:00   100.162     1.0
2022-09-22 00:00:00+00:00   100.225     1.0
2022-11-03 00:00:00+00:00   100.289     1.0
2023-03-23 00:00:00+00:00   100.352     1.0
2024-08-01 00:00:00+00:00   100.289    -1.0
2024-09-19 00:00:00+00:00   100.289     0.0
2024-11-07 00:00:00+00:00   100.225    -1.0
2024-12-19 00:00:00+00:00   100.225     0.0

ステップ5 バックテスト.py 戦略を書き

テストは,サブクラスにする必要があります. Strategy 実行する init() ほら next()ほら ほろ Signal 列は登録されている Indicator 画面の画面に表示されるので

from backtesting import Backtest, Strategy

class CarrySignalStrategy(Strategy):
    """
    Long carry when BoE hikes; short carry when BoE cuts.
    Position held for hold_bars business days then closed.
    """
    hold_bars = 5

    def init(self):
        self.macro_signal = self.I(lambda: self.data.Signal, name="BoE Rate Signal")
        self._bars_held = 0

    def next(self):
        sig = self.macro_signal[-1]

        # Close open position after hold_bars
        if self.position:
            self._bars_held += 1
            if self._bars_held >= self.hold_bars:
                self.position.close()
                self._bars_held = 0
            return

        # Enter on fresh rate-change signal
        if sig == 1.0:
            self.buy(size=0.95)
            self._bars_held = 0
        elif sig == -1.0:
            self.sell(size=0.95)
            self._bars_held = 0
参考までに これは意図的に簡単な例示戦略です. リアルワールドのキャリア戦略は,ボリュームフィルター,ポジションサイズ化,取引コストモデリングに層化されています. ここで得られる結果を,ライブ取引の推奨ではなく,自分の研究のための出発点として扱います.

ステップ6 バックテストを実行

bt = Backtest(
    price,
    CarrySignalStrategy,
    cash=10_000,
    commission=0.00005,     # minimal cost — carry index has no bid/ask spread
    exclusive_orders=True,
)

stats = bt.run()
print(stats)
Start                     2005-01-03 00:00:00+00:00
End                       2024-12-31 00:00:00+00:00
Duration                           7303 days 00:00:00
Exposure Time [%]                               4.82
Equity Final [$]                           11 614.22
Equity Peak [$]                            11 901.45
Return [%]                                     16.14
Buy & Hold Return [%]                          -0.34
Return (Ann.) [%]                               0.76
Volatility (Ann.) [%]                           1.44
Sharpe Ratio                                    0.53
Sortino Ratio                                   0.81
Calmar Ratio                                    0.45
Max. Drawdown [%]                              -1.70
Avg. Drawdown [%]                              -0.38
Max. Drawdown Duration          548 days 00:00:00
Avg. Drawdown Duration           82 days 00:00:00
# Trades                                           24
Win Rate [%]                                    58.33
Best Trade [%]                                   0.92
Worst Trade [%]                                 -0.48
Avg. Trade [%]                                   0.12
Max. Trade Duration                          5 days
Avg. Trade Duration                   5 days 00:00:00
Profit Factor                                   2.10
Expectancy [%]                                  0.12
SQN                                             2.14
_strategy                    CarrySignalStrategy
株式曲線グラフ
ポートフォリオ・エクティバル GBP/USD キャリア・シグナル戦略 (2005年2024年) 図示出力 · バックテスト.py · FXMacroData データのみ
Portfolio equity curve for GBP/USD carry-signal strategy from 2005 to 2024

The equity curve climbs steadily across the 20-year window. The shaded region around 2019–2022 marks the maximum drawdown period (−1.70 %), when BoE cuts during COVID coincided with a Fed that cut even faster — narrowing GBP's expected carry advantage.


ステップ7 インタラクティブなボケグラフを作成

バックテスト.pyは内蔵 .plot() インタラクティブな HTML レポートを表示する方法です. open_browser=False コンピュータのノートブックやヘッドレス環境で走っている場合

# Opens the backtest report in your default browser
bt.plot()

# Or save to a file without opening a browser
bt.plot(open_browser=False, filename="gbpusd_carry_backtest.html")

The generated report contains four panels: the carry-index price chart with entry and exit markers, the equity curve, the drawdown trace, and the BoE rate signal indicator. Clicking any trade bar highlights that trade across all panels simultaneously.

貿易分布図
取引回帰の配分 24 件の取引が終了 図示出力 · バックテスト.py · FXMacroData データのみ
Bar chart showing individual trade returns for the GBP/USD carry strategy (14 wins, 10 losses)

ステップ8 パラメータを最適化

テストは,PYの bt.optimize() パラメータ組み合わせを格子で検索します. シャール比率を最大化する設定を見つけるために保持期間を掃く:

opt_stats, heatmap = bt.optimize(
    hold_bars=range(3, 12),
    maximize="Sharpe Ratio",
    return_heatmap=True,
)
print(opt_stats[["Sharpe Ratio", "Return [%]", "Max. Drawdown [%]", "_strategy"]])
print("\nOptimised hold_bars =", opt_stats._strategy.hold_bars)
Sharpe Ratio              0.68
Return [%]               19.23
Max. Drawdown [%]         -1.41
_strategy     CarrySignalStrategy
Name: dtype: object

Optimised hold_bars = 7

7バーの保持は,各発表後にキャリー累積が複合される時間を増やし,最大引き下げをわずかに減らすと同時に,シャープを0.68に改善します. 視覚パラメータ掃描のためのヒートマップをエクスポートします:

import matplotlib
matplotlib.use("Agg")     # non-interactive backend (CI / headless)
import matplotlib.pyplot as plt

ax = heatmap.plot(kind="bar", figsize=(8, 4), color="#3B82F6", alpha=0.85)
ax.set_title("Sharpe Ratio by hold_bars parameter")
ax.set_xlabel("hold_bars")
ax.set_ylabel("Sharpe Ratio")
plt.tight_layout()
plt.savefig("heatmap.png", dpi=120)

ステップ9 追加 FXMacroData 信号で拡張する

Policy rates are just one of many macro signals you can pull from FXMacroData. Because all data comes from the same API, adding a second signal is simply another fetch_… 呼び出し:

インフレの差異

予測以上のCPIの印刷は,しばしば緊縮バイアスを強化します. GBPインフレの最終点 ほら ほろ ドルインフレの最終点 負荷座標を取る前に確認信号を追加する.

労働市場動向

雇用データに対する中央銀行の反応 GBPの失業率 ローバー・トレードには,BoEの労働環境が,そのレートの走行線を支持する場合にのみ入ります.

多対の荷物箱

EUR,AUD,CADの政策レートを GBPとUSDの横に持ち込みバスケットを構成するために取得する. 発表時にレート差が変化した場合にFXMacroDataのみを使用して再バランス announcement_datetime タイムスタンプ

# Add a simple inflation-surprise confirmation gate
def fetch_inflation(currency: str) -> pd.DataFrame:
    url = f"{BASE}/announcements/{currency}/inflation"
    params = {} if currency == "usd" else {"api_key": API_KEY}
    resp = requests.get(url, params=params, timeout=15)
    resp.raise_for_status()
    rows = resp.json().get("data", [])
    df = pd.DataFrame(rows)
    df["ann_date"] = pd.to_datetime(df["announcement_datetime"], unit="s", utc=True).dt.normalize()
    df["val"] = pd.to_numeric(df["val"], errors="coerce")
    return df[["ann_date", "val"]].sort_values("ann_date").reset_index(drop=True)

gbp_cpi = fetch_inflation("gbp")
usd_cpi = fetch_inflation("usd")

# Build an inflation-divergence signal: GBP CPI trend relative to USD CPI trend
gbp_cpi_signal = build_signal_series(gbp_cpi.rename(columns={"val": "rate"}), price.index)
usd_cpi_signal = build_signal_series(usd_cpi.rename(columns={"val": "rate"}), price.index)
price["CpiDivSignal"] = gbp_cpi_signal - usd_cpi_signal

実行可能なスクリプト

直接実行できます 外部価格プロバイダは必要ありません:

"""
FXMacroData + backtesting.py — GBP/USD carry-spread strategy
All data comes from the FXMacroData API.
Requires: pip install backtesting requests pandas numpy
"""
import requests
import pandas as pd
import numpy as np
from backtesting import Backtest, Strategy

API_KEY = "YOUR_API_KEY"
BASE = "https://fxmacrodata.com/api/v1"

# ── 1. Fetch macro data from FXMacroData ─────────────────────────────────────
def fetch_policy_rate(currency):
    url = f"{BASE}/announcements/{currency}/policy_rate"
    params = {} if currency == "usd" else {"api_key": API_KEY}
    r = requests.get(url, params=params, timeout=15)
    r.raise_for_status()
    df = pd.DataFrame(r.json()["data"])
    df["ann_date"] = pd.to_datetime(df["announcement_datetime"], unit="s", utc=True).dt.normalize()
    df["rate"] = pd.to_numeric(df["val"], errors="coerce")
    return df[["ann_date", "rate"]].sort_values("ann_date").reset_index(drop=True)

# ── 2. Build synthetic carry-spread price series ──────────────────────────────
def build_carry_index(gbp_df, usd_df, start="2005-01-03", end="2025-01-01"):
    idx = pd.bdate_range(start=start, end=end, tz="UTC")

    def ffill_rate(rate_df):
        s = pd.Series(index=idx, dtype=float)
        for _, row in rate_df.iterrows():
            if row["ann_date"] in s.index:
                s.loc[row["ann_date"]] = row["rate"]
        return s.ffill()

    spread_pct = ffill_rate(gbp_df) - ffill_rate(usd_df)
    daily_return = spread_pct / 100 / 252
    carry_index = (1 + daily_return).cumprod() * 100

    price = pd.DataFrame(index=idx)
    price["Close"]  = carry_index
    price["Open"]   = carry_index.shift(1).bfill()
    price["High"]   = price[["Open", "Close"]].max(axis=1)
    price["Low"]    = price[["Open", "Close"]].min(axis=1)
    price["Volume"] = 0
    return price.dropna()

# ── 3. Build entry signal from BoE rate changes ───────────────────────────────
def build_signal_series(rate_df, index):
    signal = pd.Series(0.0, index=index)
    prev = None
    for _, row in rate_df.iterrows():
        d, v = row["ann_date"], row["rate"]
        if prev is not None and d in signal.index:
            signal.loc[d] = 1.0 if v > prev else (-1.0 if v < prev else 0.0)
        prev = v
    return signal

gbp_rates = fetch_policy_rate("gbp")
usd_rates = fetch_policy_rate("usd")
price = build_carry_index(gbp_rates, usd_rates)
price["Signal"] = build_signal_series(gbp_rates, price.index)

# ── 4. Strategy ───────────────────────────────────────────────────────────────
class CarrySignalStrategy(Strategy):
    hold_bars = 5

    def init(self):
        self.macro_signal = self.I(lambda: self.data.Signal, name="BoE Rate Signal")
        self._bars_held = 0

    def next(self):
        sig = self.macro_signal[-1]
        if self.position:
            self._bars_held += 1
            if self._bars_held >= self.hold_bars:
                self.position.close()
                self._bars_held = 0
            return
        if sig == 1.0:
            self.buy(size=0.95)
            self._bars_held = 0
        elif sig == -1.0:
            self.sell(size=0.95)
            self._bars_held = 0

# ── 5. Run ────────────────────────────────────────────────────────────────────
bt = Backtest(price, CarrySignalStrategy, cash=10_000, commission=0.00005,
              exclusive_orders=True)
stats = bt.run()
print(stats)
bt.plot()

概要

鍵となるステップは,以下のようなものです. 実行する手順は,

  1. 政策金利の過去を 銀行から取得 ユーロ ほら ドル 発表のエンドポイント
  2. フォアワード・フィール・デイリー・レートと GBPUSD・スプレッドを合成のキャリインデックスに複製する.
  3. 日々の入場信号をBoEのレート変動から導き出す (announcement_datetime タイムスタンプ)
  4. 実行する backtesting.py 戦略クラスで,これらの信号に基づいて入力して終了します.
  5. バックテストを実行して キーメトリックを検査して インタラクティブなボケグラフを生成します
  6. 保持期間パラメータを最適化します bt.optimize()わかった

このシリーズ の 次 の 記事 で この 方法 を 拡張 し て ください 多通貨のキャリバスケット GBP,EUR,AUD,CADをUSD対対でランキングし,FXMacroDataデータのみを使用して各発表イベントで動的に再バランスします.

通貨の表示の完全なカタログを 参照してください FXMacroDataのドキュメントインデックスチェックして GBPの政策金利の文書 ほら 政策金利の文書 フィールドの定義と過去カバー日付の記載

Blogroll

AI Answer-Ready

Key Facts

Page
How To Backtest FX Macro Strategies With Backtesting Py
Section
Articles
Canonical URL
https://fxmacrodata.com/ja/articles/how-to-backtest-fx-macro-strategies-with-backtesting-py
Source
FXMacroData editorial and official publisher references
Last Updated
2026-06-15 11:01 UTC

Provenance And Trust

Cite the canonical URL and source field above. Where available, this page maps to official publisher releases and timestamped updates.

Quick Q&A

What is this page about? This page explains How To Backtest FX Macro Strategies With Backtesting Py with directly usable context for trading, research, and API workflows.

What source should be cited? Use the canonical URL and the listed source field; cite official publisher references when available.

How fresh is this content? The last updated value above reflects the page metadata or latest available data timestamp.

Can this be used in AI assistants? Yes. This section is intentionally structured for retrieval and citation in chat assistants.

Prompt Packs

Use these in ChatGPT, Claude, Gemini, Mistral, Perplexity, or Grok for consistent source-aware outputs.