MQL5:在 MetaTrader 5 中分析和处理商品期货交易委员会 (CFTC) 报告(基础篇)
📘

MQL5:在 MetaTrader 5 中分析和处理商品期货交易委员会 (CFTC) 报告(基础篇)

第 1/3 篇

「在 MT5 里直接读 CFTC 持仓报告」

MT5 终端内置了 CFTC(商品期货交易委员会)持仓报告的调取能力,不需要另开浏览器或导表。对做外汇和贵金属的交易者来说,这等于把机构净持仓变化直接钉在行情上下文里,但外汇和贵金属杠杆高、波动烈,报告只反映仓位倾向,不预示单边行情。 Aleksey Sergan 在 2013-11-27 10:36 发布的示例帖累计被查看 7350 次、收到 21 条评论,说明早期社区对“终端内直接解析监管持仓”的需求就很实。这个入口后来成了很多自编指标拉 COT 数据的底子。 真正有用的是把报告周期和你的图表周期错开看:周度 CFTC 是慢变量,用来判别美元指数或黄金的持仓极端;1 小时图是快变量,用来找入场节奏。两者冲突时,慢变量权重应更高。

◍ 为什么老 MQL4 玩家得重学这套

MetaTrader 5 是 MetaQuotes 开发的终端,内置支持面向对象编程的 MQL5。它和旧版 MQL4 不兼容,但带来了完整面向对象语言的大量新能力,已经熟悉 MQL4 的交易者等于要重新啃一门事实上的新语言。 本文瞄准的痛点很具体:直接拉 CFTC(商品期货交易委员会)报告里的各类数据做获取和分析,而不依赖中间处理。Meta COT 项目早先在 MT4 上做过一轮,假定你懂基础概念,这里只补原文没细说的部分。 核心思路是写一个单一指标,能从委员会发布的文件读数据、无需转换,同时兼顾多种用途——自己画图、当别的指标数据源、进脚本跑自动分析、或在写 EA 时直接调用。外汇与贵金属属高风险品类,任何基于报告数据的信号都只是概率倾向,开 MT5 前先想清楚你的样本周期。

COT 三类报告的真实分野

CFTC 的持仓报告并非只有一种口径。实战中你会碰到旧式报告(COT)、补充商品指数(CIT)和新式分类报告(DCOT)三套,底层分组逻辑差异很大。 旧式报告把市场参与者粗分为非商业、商业、非报告三类;CIT 从 2007 年起单列“指数型交易人员”,这群人既不算套保也不算纯投机,常在合约间滚动建立买入持仓;DCOT 则从 2009 年推出,把交易员拆成生产商/贸易商/加工企业/用户、互换交易商、管理基金、其他报告持仓四组,透明度明显更高。 数据文件引用上,三套报告分别对应 deacot2010.zip、dea_cit_txt_2010.zip、fut_disagg_txt_2010.zip。做跨期或跨品种相关性研究时,选错报告源会让你的持仓结构判断完全偏掉。 外汇与贵金属属高杠杆市场,CFTC 数据仅反映期货端机构倾向,不能直接推导价格方向,开 MT5 调 COT 插件前先确认自己拉的是哪一份源文件。

「用外部 CSV 给 MT5 接上 COT 指标」

在 MT5 里做 COT 指标,核心是把 CFTC 的 CSV 报告读进来再按品种画图。报告类型(COT / DCOT / CIT)、交易者分组和数据类别都做成输入参数,这样切换品种或视角不用改代码,直接在属性框里选。 数据类型目前支持四种:净长仓、未平仓合约中的净长仓比率、威廉指标(基于净长仓计算)、未平仓合约。这个列表是最小可用集,后续要加字段很容易扩,但基本覆盖多数仓位读图需求。 存储单条 COT 记录不能用 struct 而要用 class。原因是 struct 变量之间无法整体赋值,一旦里面挂了动态数组或 string 就废了;class 实例可以随意拷贝传递,配合数组就能按字段快速访问某周的持仓数据。 OnInit 里干三件事:从解压后的 CSV 拉数据、校验输入参数、给缓冲区分配内存。用 INDICATOR_DATA 初始化的缓冲区是要画到图上的,INDICATOR_CALCULATIONS 的只做中间计算,不显示。 OnCalculate 我踩过一个坑:最好对所有缓冲区数组统一用时序索引(最新一根 bar 索引为 0)。这样和函数传入的数组节奏一致,否则层层传递时间数组会让代码乱成一团——如果将来要用满 8 个数组,调用链会非常难看。外汇和贵金属受杠杆与突发事件影响大,COT 只是仓位倾向参考,不等于价格方向。

MQL5 / C++
enum cot_type_report class=class="str">"cmt">// 报告类型
{
  COT, DCOT, CIT
};
enum cot_type_traders class=class="str">"cmt">// 交易者类型
{
  noncommercial,       class=class="str">"cmt">// 非商业 
  commercial,          class=class="str">"cmt">// 商业
  nonreportable,       class=class="str">"cmt">// 无需报告
  index,               class=class="str">"cmt">// 指数交易者
  producer,            class=class="str">"cmt">// 生产商
  swapdealers,         class=class="str">"cmt">// 掉期交易者
  managedmoney,        class=class="str">"cmt">// 基金
  otherreportables    class=class="str">"cmt">// 其他须报告交易者 
};
enum cot_type_data    class=class="str">"cmt">// COT数据类型
{  
  netlongs,            class=class="str">"cmt">// 净买入
  netlongsrate,        class=class="str">"cmt">// 未平仓合约中的净买入比率
  willams_index,       class=class="str">"cmt">// Williams指数
  openinterest         class=class="str">"cmt">// 未平仓合约
};
class cot_record                                              class=class="str">"cmt">// 用于COT报告数据记录的类
  {
class="kw">public:
   class="type">class="kw">datetime            COT_DATE;                            class=class="str">"cmt">//日期 
   class="type">class="kw">double              COT_OPENINTEREST;                    class=class="str">"cmt">//未平仓合约 
   class="type">class="kw">double              COT_LONGNONCOM;                      class=class="str">"cmt">//非商业交易者的买入
   class="type">class="kw">double              COT_SHORTNONCOM;                     class=class="str">"cmt">//非商业交易者的卖出
   class="type">class="kw">double              COT_LONGCOM;                         class=class="str">"cmt">//商业交易者的买入
   class="type">class="kw">double              COT_SHORTCOM;                        class=class="str">"cmt">//商业交易者的卖出
   class="type">class="kw">double              COT_LONGNONREPORTABLE;               class=class="str">"cmt">//其他非报告交易者的买入
   class="type">class="kw">double              COT_SHORTNONREPORTABLE;              class=class="str">"cmt">//其他非报告交易者的卖出
   class="type">class="kw">double              COT_LONGINDEX;                       class=class="str">"cmt">//指数交易者的买入
   class="type">class="kw">double              COT_SHORTINDEX;                      class=class="str">"cmt">//指数交易者的卖出
   class="type">class="kw">double              COT_LONGPRODUCER;                    class=class="str">"cmt">//生产商/贸易商/加工企业/用户的买入

◍ COT 持仓结构在 MT5 里的变量映射

做贵金属或外汇的趋势判断,CFTC 的 COT 报告是绕不开的底牌。上面这段类定义把报告拆成了可落地的双精度变量:生产商卖出、掉期交易者买卖、基金管理者的买卖、以及其他需报告者的头寸,各自独立成员,方便后续直接读值。 copyvar 这个成员函数干的事很直白——把另一个 cot_record 实例里的全部字段按名赋值到当前对象。从 COT_ID、COT_NAME 到 COT_SHORTOTHERREPORTABLES,共 22 个字段逐一拷贝,没有条件判断,就是纯内存搬运,避免你在外层反复写赋值语句。 CCFTCReport 类则在外层套了一个 type 私有成员,用来标记当前报告属于哪一类(例如期货/期权分拆)。你在 MT5 里接 COT 数据时,先实例化 cot_record,调一次 copyvar 就能把拉到的周度数据塞进自己的结构体,再交给指标算基金净持仓比。 外汇和贵金属受杠杆与跨市场情绪驱动,COT 极值只代表某一类参与者的仓位倾向,反转概率高但并不确定,实盘前务必在策略测试器里跑一遍近 3 年数据。

MQL5 / C++
  class="type">class="kw">double              COT_SHORTPRODUCER;       class=class="str">"cmt">//生产商/贸易商/加工企业/用户的卖出
  class="type">class="kw">double              COT_LONGSWAPDEALERS;     class=class="str">"cmt">//掉期交易者的买入
  class="type">class="kw">double              COT_SHORTSWAPDEALERS;    class=class="str">"cmt">//掉期交易者的卖出
  class="type">class="kw">double              COT_LONGMANAGEDMONEY;    class=class="str">"cmt">//基金交易者的买入
  class="type">class="kw">double              COT_SHORTMANAGEDMONEY;   class=class="str">"cmt">//基金交易者的卖出
  class="type">class="kw">double              COT_LONGOTHERREPORTABLES;class=class="str">"cmt">//其他需报告者
  class="type">class="kw">double              COT_SHORTOTHERREPORTABLES;
  class="type">class="kw">string              COT_ID;                  class=class="str">"cmt">//交易品种标识符
  class="type">class="kw">string              COT_NAME;                class=class="str">"cmt">//交易品种名称 
  class="type">void copyvar(const cot_record &from)         class=class="str">"cmt">// 从一个类中复制内容(变量值)到另一个类中
   {
     COT_ID                   = from.COT_ID;
     COT_NAME                 = from.COT_NAME;
     COT_DATE                 = from.COT_DATE;
     COT_OPENINTEREST         = from.COT_OPENINTEREST;
     COT_LONGNONCOM           = from.COT_LONGNONCOM;
     COT_SHORTNONCOM          = from.COT_SHORTNONCOM;
     COT_LONGCOM              = from.COT_LONGCOM;
     COT_SHORTCOM             = from.COT_SHORTCOM;
     COT_LONGNONREPORTABLE    = from.COT_LONGNONREPORTABLE;
     COT_SHORTNONREPORTABLE   = from.COT_SHORTNONREPORTABLE;
     COT_LONGINDEX            = from.COT_LONGINDEX;
     COT_SHORTINDEX           = from.COT_SHORTINDEX;
     COT_LONGPRODUCER         = from.COT_LONGPRODUCER;
     COT_SHORTPRODUCER        = from.COT_SHORTPRODUCER;
     COT_LONGSWAPDEALERS      = from.COT_LONGSWAPDEALERS;
     COT_SHORTSWAPDEALERS     = from.COT_SHORTSWAPDEALERS;
     COT_LONGMANAGEDMONEY     = from.COT_LONGMANAGEDMONEY;
     COT_SHORTMANAGEDMONEY    = from.COT_SHORTMANAGEDMONEY;
     COT_LONGOTHERREPORTABLES = from.COT_LONGOTHERREPORTABLES;
     COT_SHORTOTHERREPORTABLES= from.COT_SHORTOTHERREPORTABLES;
   };
};
class CCFTCReport                                class=class="str">"cmt">//COT 报告
 {
class="kw">private:
  cot_type_report   type;       class=class="str">"cmt">//当前报告的类型 

把 COT 报告塞进自定义指标缓冲区

上面这段声明定义了一个 CCFTCReport 类骨架,专门用来把 CFTC 的 COT 持仓报告接进 MT5 指标。类里 cot_record data[] 存原始记录,sizedata 记当前条数,idsymbol 对应报告里的 Contract Market Code,terminalsymbol 则是你终端里真正的品种名,两者对不上就取不到数。 公开方法里 Init() 做实例初始化,LoadFile() 从 csv 拉数据,At() 按时间 + 交易者类型 + 数据类型(默认 netlongs 净多头)回查数值。实际写指标时,用 input 把 type_trader=noncommercial、type_data=netlongs、type_report=COT 暴露给参数面板,外汇和贵金属都属于高杠杆品种,COT 信号只反映机构倾向,不能当方向保证。 渲染层靠 SetIndexBuffer(0, BufferData, INDICATOR_DATA) 挂主缓冲,SetIndexBuffer(1, BufferCalculations, INDICATOR_CALCULATIONS) 挂计算缓冲,IndicatorSetString(INDICATOR_SHORTNAME, indname) 写短名。OnCalculate 的标准签名含 rates_total、prev_calculated、Time[]、Open[] 等,你直接照抄进 mq5 就能编译验证。

MQL5 / C++
  cot_record        data[];       class=class="str">"cmt">//cot报告数据
  class="type">int               sizedata;      class=class="str">"cmt">//当前报告的记录数目
  class="type">class="kw">string            idsymbol;      class=class="str">"cmt">//持仓报告中的交易品种标识符,在字段"CFTC Contract Market Code"中
  class="type">class="kw">string            terminalsymbol; class=class="str">"cmt">//客户端中的交易品种名称
class="kw">public:
  class="type">void ~CCFTCReport(){ sizedata=class="num">0; };
  class="type">bool              Init( cot_type_report passedtype, class="type">class="kw">string sym="" ); class=class="str">"cmt">//类实例的初始化
  class="type">bool              LoadFile( class="type">class="kw">string filename );                       class=class="str">"cmt">//从文件中加载数据
  class="type">class="kw">string            Name();                                            class=class="str">"cmt">//返回报告的简短名称
  class="type">bool              Type(cot_type_report passedtype);                  class=class="str">"cmt">//设置报告类型
  cot_type_report Type(){class="kw">return(type);};                               class=class="str">"cmt">//返回报告类型
  class="type">bool              TestGroup( cot_type_traders type_trader );         class=class="str">"cmt">//检查特定交易者是否出现
  class="type">bool              DefineIdSymbol();                                  class=class="str">"cmt">//持仓报告中id的定义
  class="type">bool              GetString( class="type">int handle, cot_record& arr );          class=class="str">"cmt">//从csv文件中获取字符串(记录)
  class="type">class="kw">string            GetFieldCommaDelimited(class="type">class="kw">string &str);               class=class="str">"cmt">//从csv字符串中获取字段
  class="type">class="kw">double            At(class="type">class="kw">datetime time,cot_type_traders type_trader,cot_type_data typedata=netlongs); class=class="str">"cmt">//从报告中获取数据
  };
class="kw">input cot_type_traders type_trader = noncommercial;  class=class="str">"cmt">//交易者类型
class="kw">input cot_type_data    type_data   = netlongs;       class=class="str">"cmt">//指标类型
class="kw">input cot_type_report  type_report = COT;            class=class="str">"cmt">//报告的类型
SetIndexBuffer( class="num">0, BufferData, INDICATOR_DATA );
IndicatorSetString(INDICATOR_SHORTNAME,indname);
SetIndexBuffer( class="num">1, BufferCalculations, INDICATOR_CALCULATIONS );
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &Time[],
                const class="type">class="kw">double &Open[],

常见问题

可用支持外部数据接入的自定义指标,把COT的CSV每周文件读进图表缓冲区,开盘前就能在品种页看到净持仓变化。
新版环境对外部文件读取和数组映射规则更严格,旧写法容易报权限错;需改用标准文件函数和缓冲区绑定重做。
小布可自动拉取最近COT结构,标注商业与非商业净头寸差,并提示历史分位,省去你手动比对表格。
商业是套保实盘倾向反向拐点,非商业是基金投机主力,非报告是零散户;三者净头寸符号常互相验证。
需把报告中的净多头、净空头分别映射到独立buffer索引,并按周偏移对齐时间轴,避免和历史K线错位。