MQL5:在 MetaTrader 5 中分析和处理商品期货交易委员会 (CFTC) 报告·综合运用
「用 iCustom 把 COT 数据拉进 EA 的坑」
想把 CFTC 的持仓报告接进 MT5 做信号,第一步是调通自定义指标 cot。下面这段函数用 iCustom 按交易者类型、数据维度、报告类型三个枚举去建句柄,再 CopyBuffer 把指定根数塞进数组。
注意 nbars+=10 这一行:它给回溯多留了 10 根缓冲,专门用来算反向值,否则边界柱容易取到空。若 BarsSinh 返回的历史柱少于需求,CheckLoadHistory 会被触发去补数据,补完仍不够就直接退出——外汇与贵金属品种历史缺失是常态,跑之前先确认本地已缓存够周线。
WaitForCalculcateIndicator 是必须的,COT 指标算得慢,不等待就 CopyBuffer 大概率拿到半成品。下面代码里 NBars=150 是 W1 深度,覆盖约三年周线;listsymbols 含七大直盘加 XAUUSD,贵金属同属高杠杆高风险品种,信号仅作概率参考。
``mql5
cot_type_traders type_trader, //交易者群组的 类型
cot_type_data type_data , //指标 类型
cot_type_report type_report, //报告 类型
double& loadto[], //输出数据 数组
int nbars ) //需要的柱形数量
{
int cothandle;
nbars+=10 ; //用于反向
cothandle = iCustom( symbol , timeframe, "cot", type_trader, type_data, type_report );
if( cothandle == INVALID_HANDLE ){
Print("Error in indicator creation for symbol ", symbol );
return(false);
}
int n = BarsSinh( symbol, timeframe );
if( n < nbars ){
Print("Loading history for ", symbol ); //, " 始于 ", loadtm
CheckLoadHistory( symbol ,timeframe, loadtm );
n = BarsSinh( symbol, timeframe );
if( n < nbars ){
Print("Not enough history for the "+symbol, " total ", n, "bars");
return(false);
}
}
if( !WaitForCalculcateIndicator( cothandle ) ){
Print("Timeout for the COT indicator calculation");
return(false);
}
int res = CopyBuffer(cothandle, 0, 0, nbars, loadto );
if( res != nbars ){
Print("Error in obtaining the data, ", MyErrorDescription(_LastError) );
return(false);
}
return(true);
}
class CCOTOutFile
{
private:
string filename;
int handle;
public:
bool Init( string passedname );
void PutString( string symbol, double& probably[] );
void PutHeader( cot_type_statistics& arrheaders[] ) ;
void ~CCOTOutFile(){ FileClose(handle); }
};
input int NBars =150; //历史数据深度 W1
#include <common.mqh>
#include <cot.mqh>
string listsymbols[] = {"EURUSD", "GBPUSD", "USDCHF", "USDCAD", "USDJPY", "AUDUSD", "XAUUSD"};
void OnStart()
{
CCOTOutFile outfile; //结果文件
if( !outfile.Init("cotw1signals.csv") )return;
cot_type_statistics list_statistic[]= // 统计类型列表
{ speculantsign, speculantchange, willamszones };
`
逐行拆关键处:iCustom 第四个参数起对应 cot 指标输入槽,顺序错一位全乱;CopyBuffer 第三参 0 是缓冲区编号,COT 指标主缓冲通常是净头寸;CCOTOutFile 析构里 FileClose 保证 CSV 不残句柄。开 MT5 把这段塞进脚本,先单跑 EURUSD 看 cotw1signals.csv` 是否落盘,再扩到全列表。
cot_type_traders type_trader, class=class="str">"cmt">//交易者群组的 类型 cot_type_data type_data , class=class="str">"cmt">//指标 类型 cot_type_report type_report, class=class="str">"cmt">//报告 类型 class="type">class="kw">double& loadto[], class=class="str">"cmt">//输出数据 数组 class="type">int nbars ) class=class="str">"cmt">//需要的柱形数量 { class="type">int cothandle; nbars+=class="num">10 ; class=class="str">"cmt">//用于反向 cothandle = iCustom( symbol , timeframe, "cot", type_trader, type_data, type_report ); if( cothandle == INVALID_HANDLE ){ Print("Error in indicator creation for symbol ", symbol ); class="kw">return(false); } class="type">int n = BarsSinh( symbol, timeframe ); if( n < nbars ){ Print("Loading history for ", symbol ); class=class="str">"cmt">//, " 始于 ", loadtm CheckLoadHistory( symbol ,timeframe, loadtm ); n = BarsSinh( symbol, timeframe ); if( n < nbars ){ Print("Not enough history for the "+symbol, " total ", n, "bars"); class="kw">return(false); } } if( !WaitForCalculcateIndicator( cothandle ) ){ Print("Timeout for the COT indicator calculation"); class="kw">return(false); } class="type">int res = CopyBuffer(cothandle, class="num">0, class="num">0, nbars, loadto ); if( res != nbars ){ Print("Error in obtaining the data, ", MyErrorDescription(_LastError) ); class="kw">return(false); } class="kw">return(true); } class CCOTOutFile { class="kw">private: class="type">class="kw">string filename; class="type">int handle; class="kw">public: class="type">bool Init( class="type">class="kw">string passedname ); class="type">void PutString( class="type">class="kw">string symbol, class="type">class="kw">double& probably[] ); class="type">void PutHeader( cot_type_statistics& arrheaders[] ) ; class="type">void ~CCOTOutFile(){ FileClose(handle); } }; class="kw">input class="type">int NBars =class="num">150; class=class="str">"cmt">//历史数据深度 W1 class="macro">#include <common.mqh> class="macro">#include <cot.mqh> class="type">class="kw">string listsymbols[] = {"EURUSD", "GBPUSD", "USDCHF", "USDCAD", "USDJPY", "AUDUSD", "XAUUSD"}; class="type">void OnStart() { CCOTOutFile outfile; class=class="str">"cmt">//结果文件 if( !outfile.Init("cotw1signals.csv") )class="kw">return; cot_type_statistics list_statistic[]= class=class="str">"cmt">// 统计类型列表 { speculantsign, speculantchange, willamszones };
正文
outfile.PutHeader( list_statistic ); <span class="comment">//向.csv文件写入头</span> <span class="keyword">for</span>( <span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="functions">ArraySize</span>(listsymbols); i++ ) <span class="comment">//列表中的所有交易品种</span> { <span class="functions">Print</span>( <span class="string">"Analysis for "</span>+listsymbols[i] ); CCOTStatistic stat; stat.Init( listsymbols[i ], list_statistic ); <span class="keyword">double</span> probably[]; <span class="comment"> //一个信号的概率</span> <span class="keyword">if</span>( !stat.Get( probably ) ) { <span class="functions">Print</span>( <span class="string">"Error in statistics calculation for the symbol "</span>, listsymbols[i] ); <span class="keyword">return</span>; } outfile.PutString( listsymbols[i], probably ); <span class="comment"> //向.csv 文件写入字符串</span> } <span class="functions">Print</span>(<span class="string">"Calculation complete."</span>); } [/CODE]
◍ MQL5 实战里的顺手与别扭
把 MQL5 当成交易系统全周期的开发工具来看,它在三件事上确实省事:复杂算法指标能直接拉外部数据源、写好的模块可在指标/脚本/EA 间复用、统计与量化分析能原生落地。面向对象那套模型不是摆设,实测调试阶段的排错时间比面向过程写法少一大截,从 MQL4 迁过来成本也低。 但碰历史数据这块是真别扭。MQL4 里 Time[]、Open[]、Close[] 这种时间序列原生数组在 MQL5 没有对应直取函数,取数前得做一大堆可访问性检查,还得先搞清数据细节。我跑本文这套验证时,光为了拿到一段闭合的日线序列就多写了二十来行防护代码。 调试器也算半个残血:能跑断点,但指标没法单步调,数组和类这类复杂对象在监视窗口里基本看不出内容。外汇和贵金属杠杆高、滑点随机,靠它排错前先留好日志兜底,别全信监视面板。
「部署 COT 工具链要放对路径」
这套 COT 分析工具解包后必须落进 MT5 客户端目录,不能随手丢桌面。从 sources.zip 解压出来的 10 个文件,各自有固定归属路径,错一个类库引用就会编译失败。 具体落点如下:MQL5\Files\unzip.exe 是 Windows 端解压 .zip 用的小程序;MQL5\Include 下塞了 6 个 .mqh,分别是管网络下载的 Cdownloader、管图表进度条的 ClassProgressBar、公用函数 common、COT 数据提取 cot、错误描述 ErrorDescription;MQL5\Indicators 里是 cot.mq5 主指标和拿它当自定义指标的 cotnet.mq5 示例;MQL5\Scripts 下则是负责联网抓档案的 cotdownloader 与做统计的 cotsignals。 实操时先跑 unzip.exe 把档案展开,再开 MT5 的 MQ 编辑器编译 Include 里的类库,最后挂 Indicators 或跑 Scripts。外汇与贵金属属高风险品种,COT 数据仅作持仓结构参考,信号失效概率不低,验证前先用策略测试器跑一遍下载脚本。
COT报告里能直接调的品种清单
做COT持仓分析前,先确认你要盯的品种在报告里有没有覆盖。上面这张表列了132个交易品种,分属芝加哥、纽约商品、ICE等交易所,每个都带交易所ID和客户端ID,例如黄金在商品交易所的客户端ID是 GC,GOLD,XAUUSD,欧元期货是 6E,EURUSD。 表里「出现于CIT中」和「出现于DCOT中」两列标了 x,代表该品种在传统或分类COT里有数据。像小麦-芝加哥(001602)、玉米(002602)、黄金(088691)、欧元(099741)都同时进了两类报告;而明尼阿波利斯小麦(001626)、大豆(005603)只在DCOT里有。 对外汇和贵金属交易者,重点看97~106和93~95行:加元6C、瑞郎6S、英镑6B、日元6J、澳元6A、纽元6N,以及白银SI、黄金XAUUSD、铂金PL、钯金PA。这些都是高杠杆品种,COT机构持仓反转对价格的影响概率偏高,但汇市和金银受央行政策干扰大,高风险,不能单靠持仓面下单。 实际在MT5里接数据,客户端ID就是你在代码或指标里填的标的代号。若你写的脚本报「无法下载」,多半是CFTC官网改了报告路径和文件名——原俄文教程附的ZIP里sources已失效,需要自己重定位URL再跑。
◍ 记住这一条就够了
把简单 SMA 改写成通用数字滤波器只是起点,真正拉开差距的是让系统脱离屏幕:用 HTML 交易报告经 FTP 推到 WWW,再用短信或 ICQ 把事件发到手机,人不在终端也能知道市场状态变了。 MQL5 里这类外发模块的代码量不大,但容错要写好——FTP 地址错、ICQ 协议超时都会让通知静默。外汇与贵金属波动剧烈、杠杆风险高,自动通知只降低盯盘成本,不替你扛回撤。 下次写 EA 时,先留一个 ReportToFTP() 的空函数,等核心逻辑跑顺了再填,比事后补桩省事得多。