报价定位数据告诉你,货币期货市场上最大的投机参与者每周都在用真钱钱.当你将你的交易记录与非商业定位的方向偏见相一致时,你增加了一个有意义的过器,将高概率的设置与与知情机构流量相反的交易分开.
本指南介绍了整个过程:从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入口过器.工作流程由六个步骤组成:
- 获取您正在交易的货币或货币的每周COT记录.
- 计算净仓位为开放利息的百分比,以实现货币间的正常化.
- 在最后一年内排列当前位置以识别极端或中性条件.
- 计算四周的动力, 确认定位是否有利于你.
- 只有当COT对齐与您的方向一致时,将您的交易条目与波器信号相对应.
- 选择性地将其与利率差异检查结合,以获得两因素确认.
作为下一步,考虑将COT波与投机者资金的位置进行配对. 货币膨胀 没有 工作 结局点建立一个宏观得分模型,将所有三个信号加在一起定位,利率差异和增长/通胀势头,以获得更全面的模式图.