Wie kann man COT-Daten zur Filterung von FX-Handelsdaten verwenden? banner image

Implementation

How-To Guides

Wie kann man COT-Daten zur Filterung von FX-Handelsdaten verwenden?

Schritt für Schritt Anleitung zum Abrufen von CFTC-Verpflichtungen von Positionsdaten von Tradern aus der FXMacroData API, Berechnung von Netto-Positionierungsmetriken und Erstellung eines Richtungsfilters, der Handelsdaten mit institutionellem Fluss abgestimmt.

Auch verfügbar auf English

COT-Positionierungsdaten zeigen Ihnen, was die größten spekulativen Teilnehmer an den Devisen-Futures-Märkten jede Woche mit echtem Geld tun, ohne Interpretation.

Dieser Leitfaden führt Sie durch den gesamten Prozess: COT-Daten aus der FXMacroData API ziehen, die abgeleiteten Schlüsselmetriken berechnen, einen Positionierungsfilter erstellen und ihn auf Ihren Eingabe-Workflow anwenden. Am Ende haben Sie einen funktionierenden Python-basierten Filter, den Sie in jede beliebige FX-Strategie einfügen können.

Was du bauen wirst

  • Eine Python-Funktion, die wöchentliche COT-Daten für eine der acht unterstützten Währungen abruft
  • Eine Normungskennzahl für die Nettoposition (netto als % der offenen Beteiligung)
  • Ein mehrkonditionierter Positionierungsfilter mit konfigurierbaren Schwellenwerten
  • Ein Handels-Eingangstor, das ein Richtungssignal zurückgibt: long- Ich weiß . shortOder ... neutral
  • Ein praktischer Durchgang mit EUR/USD als Beispiel

Voraussetzungen

  • FXMacroData-API-Schlüssel verfügbar unter /abonnierenDer COT-Endpunkt ist in allen bezahlten Plänen enthalten.
  • Python 3.9+ Mit dem ... requests Bibliothek installiert (pip install requests)
  • Grundlegende Kenntnisse der COT-Berichtterminologie (nichtkommerzielle Longs, Shorts, Open Interest). COT-Berichtführer für Devisenhändler Die Kommission hat die Kommission aufgefordert,
  • Optional, pandas für die Datenmanipulation (pip install pandas)

Schritt 1 COT-Daten aus der API abrufen

Der FXMacroData COT Endpunkt gibt wöchentliche nicht-kommerzielle und kommerzielle Positionierung für Währungstermine zurück. Unterstützte Währungen sind AUD, CAD, CHF, EUR, GBP, JPY, NZD und USD. Jeder Datensatz enthält die lange, kurze und Netto-Kontraktzahl für nicht-kommerzielle Teilnehmer und kommerzische Teilnehmer sowie das Gesamt-offene Interesse.

curl "https://fxmacrodata.com/api/v1/cot/eur?api_key=YOUR_API_KEY&start=2023-01-01"

Die Antwort JSON hat folgende Struktur:

{
  "currency": "eur",
  "data": [
    {
      "date": "2025-03-25",
      "noncommercial_long": 198432,
      "noncommercial_short": 61840,
      "noncommercial_net": 136592,
      "commercial_long": 68230,
      "commercial_short": 201860,
      "open_interest": 591400
    },
    {
      "date": "2025-03-18",
      "noncommercial_long": 185710,
      "noncommercial_short": 66320,
      "noncommercial_net": 119390,
      "commercial_long": 72140,
      "commercial_short": 189430,
      "open_interest": 578200
    }
  ]
}

In Python wickeln Sie diesen Aufruf in einen Helfer ein, der die chronologisch sortierte Datenliste zurückgibt:

import requests
from datetime import date, timedelta

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


def fetch_cot(currency: str, lookback_days: int = 365) -> list[dict]:
    """Return COT weekly records for *currency* over the last *lookback_days* days."""
    start = (date.today() - timedelta(days=lookback_days)).isoformat()
    resp = requests.get(
        f"{BASE_URL}/cot/{currency.lower()}",
        params={"api_key": API_KEY, "start": start},
        timeout=15,
    )
    resp.raise_for_status()
    payload = resp.json()
    return sorted(payload["data"], key=lambda r: r["date"])


records = fetch_cot("eur")
print(f"Loaded {len(records)} COT records for EUR")
print("Latest:", records[-1])

Warum 12 Monate Geschichte?

Die Filterschwellen in Schritt 3 werden als Perzentilrangen über das letzte Jahr ausgedrückt. Ein Jahr ist lang genug, um einen vollständigen Positionierungszyklus für die meisten wichtigen Paare zu erfassen, ohne Regimeänderungen einzubeziehen, die zu alt sind, um relevant zu sein. Sie können das Fenster auf 23 Jahre für Währungen mit langsameren Positionisationszyklen wie JPY oder CHF erweitern.

Schritt 2 Berechnung abgeleiteter Positionierungsmetriken

Die Anzahl der Rohkontrakte ist schwierig, über Währungen und Zeit hinweg zu vergleichen. Eine Nettolänge von 80.000 Kontrakte bedeutet etwas ganz anderes in EUR-Futures (großer, liquider Markt) gegenüber CHF (kleinerer offener Zinssatz).

2a. Nettoposition als Prozentsatz der offenen Beteiligung

Die Dividierung der Nettoposition nichtkommerzieller Positionen durch die Gesamtzahl der offenen Zinsen ergibt ein normalisiertes Verhältnis zwischen -1 und +1.

def net_pct_oi(records: list[dict]) -> list[dict]:
    """Add 'net_pct' field = noncommercial_net / open_interest to each record."""
    enriched = []
    for r in records:
        oi = r.get("open_interest") or 1  # guard against zero
        enriched.append({**r, "net_pct": r["noncommercial_net"] / oi})
    return enriched


records = net_pct_oi(records)
latest  = records[-1]
print(f"EUR net % OI: {latest['net_pct']:.3f}  ({latest['date']})")

2b. Positionierung des Perzentilranges

Um zu wissen, ob die aktuelle Positionierung extrem ist, braucht man einen historischen Kontext. net_pct Ein Perzentil über 75 zeigt einen vollen Long an; unter 25 zeigt einen vollen Short an.

def percentile_rank(series: list[float], value: float) -> float:
    """Return the percentile rank of *value* within *series* (0–100)."""
    below = sum(1 for x in series if x < value)
    return below / len(series) * 100


net_series     = [r["net_pct"] for r in records]
current_net    = records[-1]["net_pct"]
pct_rank       = percentile_rank(net_series, current_net)

print(f"EUR positioning percentile: {pct_rank:.1f}th")

Interpretation der Perzentilrangen

  • 75° 100° Perzentil: Nichtkommerzielle sind lang überfüllt, bevorzugen lange Eintritte, während der Trend anhält, erhöhen das Umkehrrisiko, wenn sich die Fundamentaldaten ändern.
  • 25. 75. Perzentil: Keine starken Positionswinde oder Gegenwindssignale sollten führen.
  • 0° 25° Perzentil: Nicht-kommerzielle Aktien sind kurz gefüllt, bevorzugen kurzfristige Eintritte, während der Trend anhält, und erhöhen das Risiko einer Überraschung durch Aufwärtsbewegung.

2c. Positionierungsmomentum

Die Trendrichtung ist genauso wichtig wie das aktuelle Niveau. Eine wachsende Netto-Lange ist ein anderes Signal als eine Netto lange, die sich stabilisiert oder zu schrumpfen begann. Berechnen Sie die 4-wöchige Veränderung in net_pct, um die Dynamik zu erfassen:

def positioning_momentum(records: list[dict], periods: int = 4) -> float:
    """Return the change in net_pct over the last *periods* weeks."""
    if len(records) < periods + 1:
        return 0.0
    return records[-1]["net_pct"] - records[-(periods + 1)]["net_pct"]


momentum = positioning_momentum(records)
print(f"EUR 4-week positioning change: {momentum:+.3f}")

Schritt 3 Erstellen Sie den Eingabefilter

Mit den drei Metriken in der Hand, können Sie eine Filterfunktion konstruieren, die ein Richtungssignal für jede Währung zurückgibt.

def cot_entry_filter(
    currency: str,
    lookback_days: int = 365,
    long_pct_threshold: float = 55.0,
    short_pct_threshold: float = 45.0,
    momentum_min: float = 0.005,
) -> dict:
    """
    Return a COT positioning signal for *currency*.

    Parameters
    ----------
    currency            : ISO currency code (AUD, CAD, CHF, EUR, GBP, JPY, NZD, USD)
    lookback_days       : history window for percentile calculation
    long_pct_threshold  : minimum percentile to confirm a long bias
    short_pct_threshold : maximum percentile to confirm a short bias
    momentum_min        : minimum absolute 4-week change to confirm momentum

    Returns
    -------
    dict with keys: currency, signal, net_pct, percentile, momentum, date
    """
    records  = fetch_cot(currency, lookback_days)
    records  = net_pct_oi(records)
    latest   = records[-1]

    net_series = [r["net_pct"] for r in records]
    pct_rank   = percentile_rank(net_series, latest["net_pct"])
    momentum   = positioning_momentum(records)

    if pct_rank >= long_pct_threshold and momentum >= momentum_min:
        signal = "long"
    elif pct_rank <= short_pct_threshold and momentum <= -momentum_min:
        signal = "short"
    else:
        signal = "neutral"

    return {
        "currency"   : currency.upper(),
        "signal"     : signal,
        "net_pct"    : round(latest["net_pct"], 4),
        "percentile" : round(pct_rank, 1),
        "momentum"   : round(momentum, 4),
        "date"       : latest["date"],
    }


result = cot_entry_filter("eur")
print(result)

Die Stichprobenproduktion, wenn EUR-Nicht-Geschäftsaufträge eine überfüllte Zeit verfolgen und dazu hinzufügen:

{
  "currency"  : "EUR",
  "signal"    : "long",
  "net_pct"   : 0.231,
  "percentile": 82.4,
  "momentum"  : 0.018,
  "date"      : "2025-03-25"
}

Schritt 4 Filter auf Transaktionspositionen anwenden

Die Filterfunktion gibt eines von drei Signalen zurück long- Ich weiß . shortOder ... neutralDie Verwendung ist als Tor vor dem primären Eingangssignal vorgesehen: nur lange Einstellungen, wenn der COT-Filter sagt long (oder neutral Wenn Sie aggressiver sind, und nur kurze Einstellungen machen, wenn der COT-Filter sagt short- Ich weiß .

def should_enter_trade(
    currency: str,
    proposed_direction: str,
    allow_neutral: bool = False,
) -> bool:
    """
    Return True if COT positioning supports *proposed_direction* for *currency*.

    Parameters
    ----------
    currency           : ISO currency code
    proposed_direction : 'long' or 'short'
    allow_neutral      : if True, a 'neutral' COT signal does not block entry
    """
    cot = cot_entry_filter(currency)
    if cot["signal"] == proposed_direction:
        return True
    if allow_neutral and cot["signal"] == "neutral":
        return True
    return False


# Example: checking whether to enter a EUR/USD long
currency = "eur"   # base currency of the pair
direction = "long"

if should_enter_trade(currency, direction):
    print(f"COT confirms {direction} bias for {currency.upper()} — proceed to entry check")
else:
    print(f"COT filter blocked {direction} entry for {currency.upper()}")

Anmerkung zur Durchführung: COT ist ein wöchentliches Signal

Die COT-Daten werden jeden Freitag für Positionen ab dem vorherigen Dienstag veröffentlicht. Dies macht es zu einem Niederfrequenzsignal , das für die Filterung wöchentlicher oder täglicher Verzerrungen geeignet ist, nicht für Intraday-Einträge. Führen Sie den Filter einmal pro Woche nach Freitag 15:30 Uhr ET-Veröffentlichung erneut durch, speichern Sie das Ergebnis und verwenden Sie es als statisches Bias-Gate für alle Einträge in der folgenden Woche. COT-Endpunktdokumente zur Überprüfung des Zeitplans der Freigabe.

Schritt 5 Erweitern Sie auf ein Multi-Währungs-Dashboard

Wenn Sie den Filter auf allen acht unterstützten Währungen gleichzeitig ausführen, erhalten Sie ein wöchentliches Positions-Dashboard. Dies ist nützlich, um zu identifizieren, welche Devisenpaare die klarsten spekulativ getriebenen Nachwinde haben und welche zu vermeiden sind, da die Positionierung gegen Ihre Richtung wirkt.

CURRENCIES = ["aud", "cad", "chf", "eur", "gbp", "jpy", "nzd", "usd"]

def cot_dashboard() -> list[dict]:
    """Return COT positioning signals for all supported currencies."""
    results = []
    for ccy in CURRENCIES:
        try:
            result = cot_entry_filter(ccy)
            results.append(result)
        except Exception as exc:
            print(f"Warning: could not load {ccy.upper()} COT data — {exc}")
    return results


dashboard = cot_dashboard()
for row in dashboard:
    bar = "▲" if row["signal"] == "long" else ("▼" if row["signal"] == "short" else "–")
    print(f"{row['currency']:4s}  {bar} {row['signal']:8s}  pct={row['percentile']:5.1f}  mom={row['momentum']:+.3f}")

Wöchentliche Stichprobenproduktion:

AUD   ▲ long      pct= 71.2  mom=+0.012
CAD   – neutral   pct= 53.8  mom=-0.004
CHF   ▲ long      pct= 68.4  mom=+0.008
EUR   ▲ long      pct= 82.4  mom=+0.018
GBP   – neutral   pct= 48.1  mom=-0.002
JPY   ▼ short     pct= 19.6  mom=-0.022
NZD   ▲ long      pct= 63.0  mom=+0.007
USD   ▼ short     pct= 22.1  mom=-0.015

Die Position der nicht-kommerziellen Futures ist lang EUR, AUD, CHF und NZD; kurz JPY und USD; und neutral gegenüber CAD und GBP. Ein Händler, der EUR/JPY-Längen in Betracht zieht, würde beide Beine durch Spekulantenströme bestätigt finden. Ein Trader, der USD/CAD-Länger in Betreff zieht würde einen COT-Hirnwind auf USD und einen neutralen Hintergrund auf CAD ein schwächeres Setup aus Positionierungsperspektive sehen.

Schritt 6 COT mit einer Makrokonfirmierungsschicht kombinieren

Die meisten robusten Konzepte kombinieren die COT-Positionierung mit mindestens einem Makro-Fundamentalsatz, der die gleiche Richtungstheorie unterstützt.

- Verwenden Sie die ... Endpunkt für die Leitzinssätze um den jüngsten Kurs für jede Währung zu ermitteln und die Differenz zu berechnen:

def fetch_latest_rate(currency: str) -> float | None:
    """Return the most recent policy rate for *currency* as a float."""
    resp = requests.get(
        f"{BASE_URL}/announcements/{currency.lower()}/policy_rate",
        params={"api_key": API_KEY, "limit": 1},
        timeout=15,
    )
    if resp.status_code != 200:
        return None
    data = resp.json().get("data", [])
    return data[0]["val"] if data else None


def rate_differential(base_ccy: str, quote_ccy: str) -> float | None:
    """Return base_rate − quote_rate, or None if either rate is unavailable."""
    base_rate  = fetch_latest_rate(base_ccy)
    quote_rate = fetch_latest_rate(quote_ccy)
    if base_rate is None or quote_rate is None:
        return None
    return base_rate - quote_rate


def combined_filter(base_ccy: str, quote_ccy: str, direction: str) -> dict:
    """
    Return a combined COT + rate-differential signal for a currency pair.

    direction : 'long' (buy base) or 'short' (sell base)
    """
    cot_base   = cot_entry_filter(base_ccy)
    cot_quote  = cot_entry_filter(quote_ccy)
    diff       = rate_differential(base_ccy, quote_ccy)

    # For a long (buy base): we want long bias on base AND short/neutral on quote
    if direction == "long":
        cot_ok   = cot_base["signal"] == "long" and cot_quote["signal"] != "long"
        macro_ok = diff is not None and diff > 0
    else:
        cot_ok   = cot_base["signal"] == "short" and cot_quote["signal"] != "short"
        macro_ok = diff is not None and diff < 0

    return {
        "pair"       : f"{base_ccy.upper()}/{quote_ccy.upper()}",
        "direction"  : direction,
        "cot_ok"     : cot_ok,
        "macro_ok"   : macro_ok,
        "confirmed"  : cot_ok and macro_ok,
        "cot_base"   : cot_base,
        "cot_quote"  : cot_quote,
        "rate_diff"  : round(diff, 4) if diff is not None else None,
    }


signal = combined_filter("eur", "jpy", "long")
print("Confirmed:", signal["confirmed"])
print("COT base :", signal["cot_base"]["signal"], "| COT quote:", signal["cot_quote"]["signal"])
print("Rate diff :", signal["rate_diff"])

Wenn COT und Makro nicht übereinstimmen

Wenn die Positionierung extrem auf einer Seite überfüllt ist, aber das Makro-Fundamental sich dagegen verschiebt (z. B. große kurze JPY-Futures, aber die Bank von Japan beginnt zu straffen), kann das Regime in einer Übergangsphase sein. Dies sind die Setups, die die schnellsten und größten Bewegungen oft in die Richtung erzeugen, die Short-Cover oder Long-Liquidation zwingt. In solchen Fällen ist der COT-Filter allein nicht ausreichend; überwachen Sie die Zinspolitik der Zentralbanken Die Position wird von der Positionsausrichtung abgeschaltet.

Zusammenfassung

Sie haben nun einen vollständigen COT-basierten Eingabefilter, der auf Live-FXMacroData API-Daten basiert.

  1. Holen Sie sich wöchentliche COT-Daten für die Währung oder Währungen, mit denen Sie handeln.
  2. Berechnung der Nettoposition als Prozentsatz der offenen Zinsen zur Normalisierung über Währungen hinweg.
  3. Die aktuelle Position innerhalb des letzten Jahres zu klassifizieren, um extreme oder neutrale Bedingungen zu identifizieren.
  4. Berechnen Sie die 4-wöchige Dynamik, um zu bestätigen, ob die Positionierung zu Ihren Gunsten läuft.
  5. Sie müssen Ihre Handelsmeldungen nur dann gegen das Filtersignal schalten, wenn die COT-Ausrichtung Ihrer Richtung entspricht.
  6. Optional mit einer Rate-Differential-Prüfung für eine Zweifaktorbestätigung kombiniert.

Das vollständige Multi-Währungs-Dashboard gibt Ihnen eine wöchentliche Momentaufnahme, wo Spekulantengeld positioniert ist, so dass Sie Trades mit institutionellen Fluss statt gegen es eingeben. Inflation Oder ... Beschäftigung Die Kommission hat die Kommission aufgefordert, die Ergebnisse der Analyse zu überprüfen, um ein Makroscoring-Modell zu erstellen, das alle drei Signale zusammen abwägt Positionierung, Zinsdifferenzen und Wachstums-/Inflationdynamik für ein vollständigeres Bild des Regimes.

AI Answer-Ready

Key Facts

Page
How To COT Data FX Trade Filter
Section
Articles
Canonical URL
https://fxmacrodata.com/articles/how-to-cot-data-fx-trade-filter
Source
FXMacroData editorial and official publisher references
Last Updated
2026-04-22 12:36 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 COT Data FX Trade Filter 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.

Blogroll