如何使用COT数据过外汇交易条目 banner image

Implementation

How-To Guides

如何使用COT数据过外汇交易条目

步骤指南从FXMacroData API中提取交易者位置数据的CFTC承诺,计算净位置指标,并建立一个将交易条目与机构流量相一致的方向过器.

其他语言版本 English

报价定位数据告诉你,货币期货市场上最大的投机参与者每周都在用真钱钱.当你将你的交易记录与非商业定位的方向偏见相一致时,你增加了一个有意义的过器,将高概率的设置与与知情机构流量相反的交易分开.

本指南介绍了整个过程:从FXMacroData API中提取COT数据,计算关键衍生指标,构建定位过器,并将其应用于您的输入工作流.到最后,您将有一个可用于任何FX策略的基于Python的过程序.

你将要建造什么

  • 一个Python函数,为任何八种支持货币获取每周COT数据
  • 净定位标准化指标 (净占开放利息的百分比)
  • 具有可配置值的多条件定位波器
  • 返回方向信号的交易入口: long没有人知道. short没有 neutral
  • 实际的行程,使用欧元/美元作为工作示例

预先要求

  • 汇率数据API键订阅收费终点包括在所有付费计划中.
  • Python 3.9+ 没有什么. requests 已经安装了图书馆 (pip install requests) 没有.
  • 基本熟悉COT报告术语 (非商业长期,短期,开放式利益). 外国汇交易商的COT报告指南 涵盖了基本的内容.
  • 作为选择, pandas 对于数据操作步骤 (pip install pandas) 没有.

步骤1 从API获取COT数据

FXMacroData COT终点返回货币期货的每周非商业和商业定位.支持货币是AUD,CAD,CHF,EUR,GBP,JPY,NZD和USD.每个记录都包含非商用和商用参与者的长,短和净合约数量,加上总开放利息.

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

响应JSON的结构是这样的:

{
  "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
    }
  ]
}

在Python中,将此调用包装在一个帮助程序中,

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])

为什么要花12个月的时间?

步骤3中的波值表达为后续一年的百分位数.一年足以捕捉大多数主要货币对的完整定位周期,而不包括过于老的制度变化.您可以将窗口扩大到23年,例如日元或瑞郎等货币的定位循环较慢.

步骤2 计算衍生定位指标

对于欧元期货 (大型流动市场) 和瑞士法郎 (较小的开放利息) 来说,净长度为80,000合约意味着非常不同的东西.两个衍生指标解决了这个问题.

净资产占开放性利息的百分比

除非商业净仓库的净额和开放利息总额,就产生了 -1 到 +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 定位百分位数

为了知道当前的定位是否极端,你需要历史背景. net_pct 在后期窗口内将绝对数转换为百分位数 (0 =记录中最低迷,100 =最). 75以上的百分点表示拥挤的长期; 25以下表示拥拥挤短期.

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")

解释百分位数

  • 第75第100个百分点: 长期交易是非商业交易,在趋势保持下,有利于长期入口,如果基本面发生变化,则增加逆转风险.
  • 第25第75百分点: 没有强势的定位后风或对风其他信号应该导致.
  • 排名第0第25个百分点: 其他交易者则会被挤入空期, 趋势持续下去, 则会增加任何势惊喜的压缩风险.

定位动力

趋势方向与当前水平一样重要. 增长的净长是与已经平稳或开始收缩的净長不同的信号. 计算net_pct的4周变化以捕获动力:

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}")

步骤3 建立入口过器

通过这些三种指标,你可以构建一个过函数, 返回任何货币的方向信号.逻辑将当前水平,百分位背景和动量方向结合到一个门.

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)

样本输出当EUR非商业运行拥挤长时间并添加到它:

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

步骤4 应用过器到交易条目

过函数返回三个信号中的一个 long没有人知道. short没有 neutral预期使用是作为一个门前的主要入口信号:只有在COT波器表示时进行长设置 long (或是 neutral 如果您更有攻击性,只需要在COT波器显示 short现在我们要做什么?

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()}")

执行说明:COT是一个每周的信号

截至前周二,COT数据每周五都会发布.这使得它成为一个低频信号,适合过每周或每日偏差,而不是日内条目.在周五下午3:30的ET发布后,每周一次重新运行过器,缓存结果,并将其作为下周所有条目的静态偏差网. 使用 机器人使用的终点 为了验证释放时间.

步骤5 扩展到多货币仪表板

通过同时运行所有八种支持货币的过器,您可以获得每周的定位仪表板. 这对于识别哪些外汇对具有最明显的投机者驱动的尾风,以及哪些是应该避免的,因为定位是违背您的方向的.

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}")

样本每周产出:

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

阅读此快照:非商业期货是长期欧元,澳元,瑞郎和新西兰元期货;短期日元和美元期货,对CAD和英期货中立.考虑欧元/日元期权的交易者会发现,这两条腿都得到投机者流的证实.考虑美元/CAD期权的一位交易者将面临美元的COT逆风和CAD的中立背景.

步骤6 将COT与宏观确认层结合起来

最稳健的设置将COT定位与至少一个支持同一个方向论点的宏观基本面结合起来.利率差异是自然的补充:如果投机者持长欧元,而欧洲央行与美联储的利率区别正在有利于欧元扩大,则定位和基本面情况是一致的.

使用 政策利率终点 为了查询每种货币的最新汇率,并计算差值:

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"])

当COT和宏观不同意时

当定位非常拥挤的一侧,但宏观基本面正在向其转移时 (例如,大型短期日元期货但日本银行开始收紧),该制度可能正在过渡. 这些设置产生最快和最大的动作,通常是迫使短覆盖或长清算的方向.在这种情况下,单独的COT过器不足;监控 中央银行政策利率历史 对于任何可能引发定位放松的转移,

总结

现在您有一个基于现实FXMacroData API数据构建的完整的COT入口过器.工作流程由六个步骤组成:

  1. 获取您正在交易的货币或货币的每周COT记录.
  2. 计算净仓位为开放利息的百分比,以实现货币间的正常化.
  3. 在最后一年内排列当前位置以识别极端或中性条件.
  4. 计算四周的动力, 确认定位是否有利于你.
  5. 只有当COT对齐与您的方向一致时,将您的交易条目与波器信号相对应.
  6. 选择性地将其与利率差异检查结合,以获得两因素确认.

作为下一步,考虑将COT波与投机者资金的位置进行配对. 货币膨胀 没有 工作 结局点建立一个宏观得分模型,将所有三个信号加在一起定位,利率差异和增长/通胀势头,以获得更全面的模式图.

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