Live release feed
Sub-second macro releases for FX backtests
Point-in-time history
USD 25/month
무료 체험 시작

Implementation

How-To Guides

FXMacroData로 수익률 스프레드 쌍 거래 전략을 만드는 방법

정부 채권 수익률 차이에 의해 주도되는 규칙 기반 FX 전략을 구축하는 완전한 파이썬 워크서브 FXMacroData API를 통해 10년 수익률을 검색하는 것부터 EUR/USD에 대한 스프레드 신호를 백테스팅하는 것까지.

다른 언어로도 제공 English
Share article X LinkedIn Email
FXMacroData로 수익률 스프레드 쌍 거래 전략을 만드는 방법 image

수익률 이 아닌 수익률 간 격차 를 교환

두 경제 사이의 정부 채권 수익률 차이는 외환 시장에서 가장 신뢰할 수있는 구조적 힘 중 하나입니다. 미국 10 년 수익률이 독일 펀드 동등보다 크게 이동하면 자본은 USD 자산으로 흐르는 경향이 있으며 EUR/USD는 지속적인 판매 압력에 직면합니다. 그 스프레드가 압축되면 부자가 회복됩니다. 관계는 기계적이지 않지만 그 주위에 규칙 기반 거래 전략을 구축 할 수있는만큼 지속적입니다.

이 가이드는 FXMacroData API를 사용하여 완전한 수익률 스프레드 쌍 거래 전략을 구축하는 과정을 안내합니다.

  • 를 통해 두 화폐에 대한 정부 채권 수익률 시간 시리즈를 가져옵니다. FXMacroData 채권 수익률 최종 지점
  • 수익률 스프레드와 그 롤링 평균과 표준편차를 계산합니다.
  • Z-점수 평균 회귀를 사용하여 통계적으로 구동 된 긴 / 짧은 FX 신호를 생성합니다.
  • 오픈 포지션을 추적하고 기본적인 위험 통제를 적용하고 입력/출출 경고를 표시합니다.

핵심 논문

이윤 스프레드는 구조적으로 안정된 평형의 중심에서 평균 반전된다. 스프레이드가 최근 평균을 크게 초과할 때 해당 FX 쌍은 통계적으로 과도하게 확장되어 다시 올 가능성이 있다. 스플레드가 정상화 될 때 정의된 출구로 평균 반전의 방향으로 진입하는 것이 이 접근법의 기초이다.

필수 조건

시작 하기 전 다음 과 같은 것 들 을 준비 해 두십시오.

  • 파이썬 3.9+ 모든 단편들은 표준 타입 주석을 사용합니다
  • FXMacroData API 키 등록하세요 / 가입 그리고 계정 대시보드에서 키를 복사
  • 파이썬 패키지 requests pandas numpy
pip install requests pandas numpy

환경 변수로 API 키를 저장합니다.

export FXMACRO_API_KEY="YOUR_API_KEY"

단계 1: 정부 채권 수익률 데이터를 가져오기

이 전략의 기초는 신뢰할 수 있는 채권 수익 시간 시리즈입니다. FXMacroData는 주요 통화 블록에 대한 10년 정부 채권 이산율을 gov_bond_10y 각 관찰은 date, a val (수분율로 표시된 수익률) announcement_datetime 두 번째 레벨의 릴리스 타임 스탬프에 대한

여기서는 10년 USD와 EUR의 수익을 추출하고, 날짜에 맞춰진 하나의 데이터프레임으로 집계합니다.

import os
import requests
import pandas as pd
from datetime import datetime, timedelta

BASE_URL = "https://fxmacrodata.com/api/v1"
API_KEY = os.environ["FXMACRO_API_KEY"]


def fetch_yield(currency: str, tenor: str = "gov_bond_10y", start: str = "2022-01-01") -> pd.Series:
    """Fetch a bond yield series from FXMacroData and return as a dated Series."""
    resp = requests.get(
        f"{BASE_URL}/announcements/{currency}/{tenor}",
        params={"api_key": API_KEY, "start": start},
        timeout=15,
    )
    resp.raise_for_status()
    records = resp.json()["data"]
    if not records:
        raise ValueError(f"No data returned for {currency}/{tenor}")
    series = pd.Series(
        {r["date"]: r["val"] for r in records},
        name=f"{currency.upper()}_10Y",
        dtype=float,
    )
    series.index = pd.to_datetime(series.index)
    return series.sort_index()


# Fetch USD and EUR 10-year yields
usd_10y = fetch_yield("usd")
eur_10y = fetch_yield("eur")

# Align on a shared date index (inner join drops days missing in either series)
yields = pd.DataFrame({"USD_10Y": usd_10y, "EUR_10Y": eur_10y}).dropna()

print(yields.tail())
# Output:
#            USD_10Y  EUR_10Y
# 2025-04-08    4.41     2.71
# 2025-04-09    4.39     2.69
# 2025-04-10    4.49     2.70
# 2025-04-11    4.52     2.73
# 2025-04-14    4.47     2.70

지탱되는 모든 통화 을 사용할 수 있습니다. gov_bond_10y 엔드포인트 유행한 조합은 USD/JPY, AUD/USD, GBP/USD 스프레드입니다.

US vs EUR 10-Year Yield — Illustrative

2022~2024년까지 USD 수익률은 EUR 대금보다 더 빠르게 상승했고, 주기에 걸쳐 EUR/USD에 영향을 미치는 지속적인 폭의 스프레드를 만들었습니다.

단계 2: 수익률 스프레드와 Z 스코어를 계산합니다.

원시 스프레드 (USD 미소 EUR 수익률) 는 자본이 구조적으로 편향된 방향을 알려줍니다. Z 점수는 최근 역사에 대한 스프레이드를 정상화하여 시간 기간과 통화 쌍에 직접 비교 가능한 비차원 신호를 제공합니다.

+1.5 이상의 Z 점수는 스프레드가 비정상적으로 크게 잠재적인 EUR/USD (장 USD) 짧은 설정으로 확대되었다는 것을 나타냅니다. -1.5 이하의 Z 점치는 비정상적인 압축을 나타냅니다 잠재적 인 EUR/ USD 긴 설정.

def compute_spread_signal(
    yields_df: pd.DataFrame,
    base_col: str,
    quote_col: str,
    lookback: int = 60,
    entry_z: float = 1.5,
    exit_z: float = 0.3,
) -> pd.DataFrame:
    """
    Compute yield spread, rolling Z-score, and directional signals.

    A positive spread means base currency yields are higher → base currency
    is structurally favoured → signal to be long base / short quote FX pair.

    Mean reversion: enter when Z-score is extreme, exit when it normalises.
    """
    df = yields_df.copy()
    df["spread"] = df[base_col] - df[quote_col]

    # Rolling statistics over the lookback window
    roll = df["spread"].rolling(lookback, min_periods=lookback // 2)
    df["spread_mean"] = roll.mean()
    df["spread_std"]  = roll.std()

    # Z-score: how many standard deviations from the rolling mean
    df["zscore"] = (df["spread"] - df["spread_mean"]) / df["spread_std"].replace(0, float("nan"))

    # Signal: +1 = long base/short quote, -1 = short base/long quote, 0 = flat
    df["signal"] = 0
    df.loc[df["zscore"] >  entry_z, "signal"] = -1   # spread too wide → expect compression → short base pair
    df.loc[df["zscore"] < -entry_z, "signal"] = +1   # spread too tight → expect widening → long base pair
    # Exit (override) when Z-score returns toward zero
    df.loc[df["zscore"].abs() < exit_z, "signal"] = 0

    return df.dropna(subset=["zscore"])


analysis = compute_spread_signal(yields, base_col="USD_10Y", quote_col="EUR_10Y")

print(analysis[["spread", "spread_mean", "zscore", "signal"]].tail(10))

USD–EUR 10Y Spread and Z-Score — Illustrative

Z 점수는 ±1.5 이상으로 확산이 너무 빨리 진행되어 다음 주 동안 평균 역행 경향이있는 역사적으로 표시 된 에피소드입니다.

단계 3: 여러 쌍으로 확장

EUR/USD의 단일 스프레드 전략은 유용하지만, 여러 쌍을 동시에 동일한 논리를 실행할 때 실제 힘은 나타납니다. USD/JPY, AUD/USD, GBP/USD 스프레이드 신호를 결합하면 각 포지션이 독립적으로 크기가있는 다양화된 거시적으로 구동되는 포트폴리오를 제공합니다.

또한 짧은 텐어 을 사용할 수 있습니다. gov_bond_2y 이 종점은 정책금리 기대에 특히 민감하여 10년 연대와 비교하면 선도적 지표입니다.

PAIRS = [
    # (base_currency, quote_currency, fx_pair_label)
    ("usd", "eur", "EUR/USD"),
    ("usd", "jpy", "USD/JPY"),
    ("aud", "usd", "AUD/USD"),
    ("gbp", "usd", "GBP/USD"),
]

TENOR = "gov_bond_10y"   # swap for gov_bond_2y for rate-expectation signals

results = {}
for base_ccy, quote_ccy, fx_label in PAIRS:
    try:
        base_series  = fetch_yield(base_ccy, tenor=TENOR)
        quote_series = fetch_yield(quote_ccy, tenor=TENOR)
        df = pd.DataFrame({
            f"{base_ccy.upper()}_10Y":  base_series,
            f"{quote_ccy.upper()}_10Y": quote_series,
        }).dropna()
        signal_df = compute_spread_signal(
            df,
            base_col=f"{base_ccy.upper()}_10Y",
            quote_col=f"{quote_ccy.upper()}_10Y",
        )
        latest = signal_df.iloc[-1]
        results[fx_label] = {
            "spread_pct": round(latest["spread"], 3),
            "zscore":     round(latest["zscore"], 2),
            "signal":     int(latest["signal"]),
        }
        print(f"{fx_label}: spread={latest['spread']:.3f}%, z={latest['zscore']:+.2f}, signal={int(latest['signal']):+d}")
    except Exception as exc:
        print(f"{fx_label}: skipped — {exc}")

# Example output:
# EUR/USD: spread=1.770%, z=+1.21, signal=0
# USD/JPY: spread=4.050%, z=+2.18, signal=-1
# AUD/USD: spread=0.340%, z=-0.55, signal=0
# GBP/USD: spread=0.890%, z=-1.62, signal=+1

신호 참조

  • + 1: 스프레드는 너무 압축되어 있습니다. 확대될 것으로 예상됩니다.
  • -1: 스프레드는 너무 넓다 압축을 예상한다 기본 통화 단축 (예를 들어, USD/JPY 단축은 JPY 길다)
  • 0: 정상 범위 내에서 퍼져있어요 방향 가장자리가 없네요 평평하게 유지하세요

단계 4: 2년 대 10년 경사 부피를 추가합니다.

이산화 곡선의 형태는 전략에 두 번째 차원을 추가합니다. 절단 곡선 (장단기 수익률이 단기보다 더 빨리 상승) 은 일반적으로 성장 기대를 개선하고 통화를 지원하는 신호입니다. 역전 또는 평평화 곡선은 종종 둔화와 중앙 은행 회전보다 앞서 있습니다.

두쪽 다 2년 그리고 10년 기울기를 계산하고, 그 기울기를 기전 필터로 사용한다: 오직 주식 통화 곡선 기울기와 정렬된 방향으로 스프레드 신호를 가져야 한다.

def fetch_curve_slope(currency: str, start: str = "2022-01-01") -> pd.Series:
    """Return the 10Y–2Y slope for a currency (positive = normal/steep, negative = inverted)."""
    y10 = fetch_yield(currency, tenor="gov_bond_10y", start=start)
    y2  = fetch_yield(currency, tenor="gov_bond_2y",  start=start)
    slope = (y10 - y2).dropna()
    slope.name = f"{currency.upper()}_slope"
    return slope


def apply_curve_filter(
    signal_df: pd.DataFrame,
    base_slope: pd.Series,
    quote_slope: pd.Series,
) -> pd.DataFrame:
    """
    Suppress signals that contradict the curve-slope regime.

    Long base / short quote (signal=+1) is only taken when:
      - base curve is steep (positive slope) AND
      - quote curve is flat or inverted (slope < base_slope)

    Short base / long quote (signal=-1) is only taken when:
      - quote curve is steep relative to base
    """
    df = signal_df.copy()
    df = df.join(base_slope.rename("base_slope"), how="left")
    df = df.join(quote_slope.rename("quote_slope"), how="left")
    df[["base_slope", "quote_slope"]] = df[["base_slope", "quote_slope"]].ffill()

    # Slope differential: positive → base is steeper → supportive for base
    df["slope_diff"] = df["base_slope"] - df["quote_slope"]

    # Filter: suppress longs when slope_diff is negative (quote steeper)
    df.loc[(df["signal"] == +1) & (df["slope_diff"] < 0), "signal"] = 0
    # Filter: suppress shorts when slope_diff is positive (base steeper)
    df.loc[(df["signal"] == -1) & (df["slope_diff"] > 0), "signal"] = 0

    return df


# Example for EUR/USD
usd_slope = fetch_curve_slope("usd")
eur_slope = fetch_curve_slope("eur")

analysis_filtered = apply_curve_filter(analysis, base_slope=usd_slope, quote_slope=eur_slope)
print(analysis_filtered[["zscore", "signal", "slope_diff"]].tail(8))

USD and EUR Curve Slope (10Y–2Y) — Illustrative

Both curves inverted in 2022–2023; the relative slope differential still provided a tradeable signal even when absolute slopes were negative.

단계 5: 알림을 생성하고 실시간 모니터를 구축

마지막 단계는 신호 논리를 모니터로 집어넣고 일정 (일일 폐쇄, 시간, 또는 을 통해 채권 수익 발표 직후 발동) 에 실행할 수 있습니다. FXMacroData 발매 달력새로운 신호가 발사되면 모니터에서 구조화된 알림을 인쇄하여 Slack, 이메일 또는 거래 웹 으로 이동할 수 있습니다.

from dataclasses import dataclass
from typing import Literal

SignalType = Literal["LONG", "SHORT", "EXIT", "HOLD"]


@dataclass
class SpreadAlert:
    fx_pair:     str
    signal:      SignalType
    spread_pct:  float
    zscore:      float
    slope_diff:  float
    timestamp:   str


def latest_signal(
    base_ccy: str,
    quote_ccy: str,
    fx_pair:   str,
    tenor:     str = "gov_bond_10y",
    lookback:  int = 60,
) -> SpreadAlert:
    base_yields  = fetch_yield(base_ccy,  tenor=tenor)
    quote_yields = fetch_yield(quote_ccy, tenor=tenor)
    df = pd.DataFrame({
        "base":  base_yields,
        "quote": quote_yields,
    }).dropna()

    base_col, quote_col = "base", "quote"
    df = compute_spread_signal(
        df.rename(columns={"base": base_col, "quote": quote_col}),
        base_col=base_col,
        quote_col=quote_col,
        lookback=lookback,
    )

    # Curve filter
    base_slope  = fetch_curve_slope(base_ccy)
    quote_slope = fetch_curve_slope(quote_ccy)
    df = apply_curve_filter(df, base_slope, quote_slope)

    row = df.iloc[-1]
    sig_map = {1: "LONG", -1: "SHORT", 0: "HOLD"}

    return SpreadAlert(
        fx_pair=fx_pair,
        signal=sig_map[int(row["signal"])],
        spread_pct=round(float(row["spread"]), 3),
        zscore=round(float(row["zscore"]), 2),
        slope_diff=round(float(row.get("slope_diff", float("nan"))), 3),
        timestamp=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
    )


# Run for all pairs
for base_ccy, quote_ccy, fx_label in PAIRS:
    try:
        alert = latest_signal(base_ccy, quote_ccy, fx_label)
        print(
            f"[{alert.timestamp}] {alert.fx_pair:8s} | {alert.signal:5s} | "
            f"spread={alert.spread_pct:+.3f}%  z={alert.zscore:+.2f}  slope_diff={alert.slope_diff:+.3f}"
        )
    except Exception as exc:
        print(f"{fx_label}: error — {exc}")

# Example output:
# [2025-04-14T08:32:11Z] EUR/USD   | HOLD  | spread=+1.770%  z=+1.21  slope_diff=+0.210
# [2025-04-14T08:32:14Z] USD/JPY   | SHORT | spread=+4.050%  z=+2.18  slope_diff=+0.580
# [2025-04-14T08:32:17Z] AUD/USD   | HOLD  | spread=+0.340%  z=-0.55  slope_diff=-0.120
# [2025-04-14T08:32:20Z] GBP/USD   | LONG  | spread=+0.890%  z=-1.62  slope_diff=-0.340

스케줄링 팁

채권 수익률 데이터는 정부가 새로운 발행 결과를 발표하고 중앙 은행이 정책 결정을 발표 할 때 업데이트됩니다. 고정 타임러에 대한 설문 조사 대신 FXMacroData 발매 달력 다음 예정된 채권 경매나 정책 발표를 찾아서 그 사건이 발사된 직후 신호 업데이트를 시작하세요.

쌍들 사이 신호 분포 예시적

60일 분기 창에서 Z 점수 임계값이 ±1.5인 경우, 상당수의 날이 평평한 영역에 떨어지며, 자본 투입이 높은 확신을 가진 세트업에 집중됩니다.

요약 및 다음 단계

이제 당신은 완전한 수익률 스프레드 쌍 거래 프레임워크를 가지고 있습니다. 주요 구성 블록은:

  1. 채권 수익률 /announcements/{currency}/gov_bond_10y 그리고 /announcements/{currency}/gov_bond_2y 원자재에 두 번째 레벨의 발표 시간표를 공급합니다.
  2. 스프레드와 Z-스코어 60일 분기 창 주위의 평균 역전으로 하나의 임계값에 곡선을 맞추지 않고 객관적인 입출입수준을 생성합니다.
  3. 곡선 기울기 필터 10Y2Y 이차는 각 통화 자체 수익률 곡선의 구조적 편향에 반대하는 신호를 억제하는 레지엄 게이트 역할을 합니다.
  4. 실시간 경고 구조화 SpreadAlert 출력은 어떤 알림, 로깅 또는 실행 파이프라인으로 쉽게 이동할 수 있습니다.

자연적인 확장은 수익률 스프레드를 정책금리차기 그리고 CPI 차이는 복합 매크로 점수를 얻거나 부진율 인플레이션 조정된 포지셔닝을 위한 명목 수익률 스프레드에서 실제 수익률으로 전환하기 위해서입니다.

모든 사용 가능한 수익률 및 비율 최종 지점에 대한 완전한 문서는 /api- 참조API 키를 받으려면 / 가입- 그래요

Blogroll

AI Answer-Ready

Key Facts

Page
How To Yield Spread Pair Trading
Section
Articles
Canonical URL
https://fxmacrodata.com/ko/articles/how-to-yield-spread-pair-trading
Source
FXMacroData editorial and official publisher references
Last Updated
2026-06-15 11:06 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 Yield Spread Pair Trading 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.