Live release feed
Sub-second macro releases for FX backtests
Point-in-time history
USD 25/month
Iniciar teste grátis

Implementation

How-To Guides

Como utilizar os dados COT para filtrar as entradas de negociação FX

Guia passo a passo para extrair os dados de posicionamento dos Compromissos da CFTC dos Traders da API FXMacroData, calcular métricas de posicionar a rede e construir um filtro direcional que alinhe as entradas de negociação com o fluxo institucional.

Também disponível em English
Share article X LinkedIn Email
Como utilizar os dados COT para filtrar as entradas de negociação FX image

Os dados de posicionamento COT dizem o que os maiores participantes especulativos nos mercados de futuros de moeda estão fazendo com dinheiro real todas as semanas, sem interpretação.

Este guia percorre o processo completo: extrair dados COT da API FXMacroData, calcular as métricas derivadas da chave, construir um filtro de posicionamento e aplicá-lo ao seu fluxo de trabalho de entrada.

O que você vai construir

  • Uma função Python que recupera dados COT semanais para qualquer uma das oito moedas suportadas
  • Uma métrica de normalização do posicionamento líquido (neto em % do interesse aberto)
  • Filtro de posicionamento multicondição com limiares configuráveis
  • Uma porta de entrada de comércio que retorna um sinal direcional: long- Não . shortOu ... neutral
  • Um passo prático usando o EUR/USD como exemplo de trabalho

Requisitos prévios

  • Chave da API do FXMacroData disponível em / subscreverO ponto final COT está incluído em todos os planos pagos.
  • Python 3.9+ com o ... requests biblioteca instalada (pip install requests)).
  • Familiarização básica com a terminologia dos relatórios COT (longs, shorts, open interest não comerciais). Guia de relatórios COT para operadores de câmbio Abrange os fundamentos.
  • Opcionalmente, pandas para as etapas de manipulação de dados (pip install pandas)).

Passo 1 Obter dados COT da API

O endpoint FXMacroData COT retorna posicionamento semanal não comercial e comercial para futuros de moeda. As moedas suportadas são AUD, CAD, CHF, EUR, GBP, JPY, NZD e USD. Cada registro contém a contagem de contratos longos, curtos e líquidos para participantes não comerciais e comerciais, mais o interesse total aberto.

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

A resposta JSON tem esta estrutura:

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

Em Python, envolva esta chamada em um auxiliar que retorna a lista de dados ordenada cronologicamente:

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

Por que 12 meses de história?

The filter thresholds in Step 3 are expressed as percentile ranks over the trailing year. One year is long enough to capture a full positioning cycle for most major pairs without including regime changes that are too old to be relevant. You can widen the window to 2–3 years for currencies with slower-moving positioning cycles like JPY or CHF.

Passo 2 Calcular métricas de posicionamento derivadas

A duração líquida de 80.000 contratos significa algo muito diferente nos futuros EUR (mercado grande e líquido) versus CHF (interesse aberto menor).

2a. Posição líquida em percentagem de interesse aberto

Dividindo a posição líquida não comercial pelo total dos juros abertos, obtém-se um rácio normalizado entre -1 e +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. Posicionamento do Percentil de Classe

Para saber se o posicionamento atual é extremo, é preciso um contexto histórico. net_pct within the trailing window converts an absolute number into a percentile (0 = most bearish on record, 100 = most bullish). A percentile above 75 indicates a crowded long; below 25 indicates a crowded short.

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

Interpretação de ranques percentais

  • 75o100o percentil: Os não comerciais são lotados de longo, favorece entradas longas enquanto a tendência se mantém, acrescenta risco de reversão se os fundamentos mudarem.
  • 25o75o percentil: Zona neutra, sem vento de contra-volta ou vento de posição forte outros sinais devem conduzir.
  • 0° 25° percentil: Os não comerciais estão lotados de curto, favorecendo entradas curtas enquanto a tendência se mantém, acrescentando risco de compressão em qualquer surpresa de alta.

2c. Impulso de posicionamento

A direção da tendência é tão importante quanto o nível atual. Um longo líquido que está crescendo é um sinal diferente de um longo líquidos que está estagnado ou começou a encolher. Calcule a mudança de 4 semanas no net_pct para capturar o impulso:

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

Passo 3 Construir o filtro de entrada

Com as três métricas em mãos, você pode construir uma função de filtro que retorna um sinal direcional para qualquer moeda.

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)

Produto da amostra quando EUR não comerciais estão a executar um longo lotado e adicionar a ele:

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

Passo 4 Aplicar o filtro às entradas de transacção

A função de filtro retorna um dos três sinais long- Não . shortOu ... neutralO uso pretendido é como um portão à frente do seu sinal de entrada primário: só tomar configurações longas quando o filtro COT diz long (ou neutral Se for mais agressivo), e só faça configurações curtas quando o filtro COT disser short- Não .

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

Nota de execução: O sinal COT é semanal

COT data is released every Friday for positions as of the prior Tuesday. That makes it a low-frequency signal — appropriate for filtering weekly or daily bias, not intraday entries. Re-run the filter once per week after Friday's 3:30 pm ET release, cache the result, and use it as a static bias gate for all entries in the following week. Use the Documentação do ponto final do COT para verificar o calendário de liberação.

Passo 5 Extender para um painel de instrumentos de várias moedas

A execução do filtro em todas as oito moedas suportadas ao mesmo tempo dá-lhe um painel de posicionamento semanal.

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

Produto semanal da amostra:

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

A posição de um trader que considera longs EUR/JPY seria confirmada pelo fluxo de especuladores. Um trader que pensa em longs USD/CAD enfrentaria um vento contrário COT no USD e um pano de fundo neutro no CAD uma configuração mais fraca do ponto de vista do posicionamento.

Passo 6 Combinar COT com uma camada de confirmação macro

As configurações mais robustas combinam o posicionamento COT com pelo menos um fundamental macro que apoia a mesma tese direcional. Os diferenciais de taxas são o complemento natural: se os especuladores estão longos no EUR e o diferencial de taxas BCE/Fed está a alargar-se em favor do EUR, o posizionamento e o caso fundamental estão alinhados.

Usa o ... Ponto final da taxa de juro Para obter a taxa mais recente para cada moeda e calcular o diferencial:

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

Quando a COT e a macro discordam

Quando o posicionamento está extremamente lotado em um lado, mas o fundamental macro está mudando contra ele (por exemplo, grandes futuros curtos do JPY, mas a Banco do Japão está começando a apertar), o regime pode estar em transição. Estas são as configurações que produzem os movimentos mais rápidos e maiores muitas vezes na direção que força a cobertura curta ou a liquidação longa. Histórico de taxas de juro de política do banco central A partir de agora, a Comissão deverá proceder a uma análise dos resultados do trabalho realizado.

Resumo

Agora você tem um filtro de entrada baseado em COT completo construído em dados da API FXMacroData ao vivo.

  1. Obter registos semanais de COT para a moeda ou moedas que está a negociar.
  2. Calcular a posição líquida em percentagem do juro aberto para normalizar em todas as moedas.
  3. Classificar o posicionamento atual no ano anterior para identificar condições extremas ou neutras.
  4. Calcule o momento de 4 semanas para confirmar se o posicionamento está a evoluir a seu favor.
  5. A porta de entrada das suas entradas de negociação contra o sinal do filtro só deve ser colocada quando o alinhamento COT corresponder à sua direção.
  6. Combinar opcionalmente com uma verificação de diferencial de taxa para uma confirmação de dois fatores.

O painel de instrumentos multi-moeda completo dá-lhe um instantâneo semanal de onde o dinheiro dos especuladores está posicionado, para que você entre em negociações com o fluxo institucional em vez de contra ele. inflação Ou ... emprego Os resultados do estudo foram apresentados em conjunto com os resultados de um estudo de avaliação de risco e de um relatório de avaliação do impacto do mercado.

Blogroll

AI Answer-Ready

Key Facts

Page
How To COT Data FX Trade Filter
Section
Articles
Canonical URL
https://fxmacrodata.com/pt/artigos/how-to-cot-data-fx-trade-filter
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 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.