从头开始开发智能交易系统(第 15 部分):访问 web 上的数据(I)(基础篇)
「让EA直连web拿外部行情」
在 MT5 里写 EA,很多人卡在一点:策略要用到网页上的实时数据,但终端默认只认本地历史与实时报价。MQL5 从早期版本就提供了 WebRequest 接口,允许 EA 在可控前提下向外部 HTTP 服务发起请求,把网页数据拉回本地参与计算。 这套能力不是默认开启的。要在 MT5 客户端里勾选「允许 WebRequest 访问 URL 列表」,把目标域名加白,否则 EA 调用会直接返回失败。这是 2022 年官方文档里就明确的权限边界,很多回测能跑、实盘报错的情况,根子都在这里。 下面这段是最小可验证的访问示例,先在客户端配好白名单,再把代码挂到 EA 的 OnTick 里,就能看到终端日志打出网页返回的状态码。外汇与贵金属品种波动受外部消息影响大,接 web 数据有概率改善信号质量,但外部服务延迟或宕机也会放大交易风险。
class="type">class="kw">string cookie=NULL, headers=NULL, result=NULL; class="type">int timeout=class="num">5000; class="type">char post[class="num">0]; class="type">class="kw">string url="https:class=class="str">"cmt">//www.example.com/data.json"; class="type">int res=WebRequest("GET", url, cookie, NULL, timeout, post, class="num">0, result, headers); if(res==class="num">200) Print("Web data received, length=", ArraySize(result)); else Print("Request failed, code=", res);
◍ 为什么 MQL5 值得交易者去碰代码
很多老交易者把 MT5 只当看图和下单的壳,其实它底层的 MQL5 语法贴近 C/C++,这意味着你能写的逻辑深度远超指标拖拽。普通不会编程的人,上限就是平台给的现成功能;而懂一点 MQL5,就能把外部数据拉进策略里。 盘面只是局部。真正影响贵金属或外汇短线方向的,往往是跨市场的新闻、利率预期、流动性变化——这些信息散在网页上。用人眼盯多个显示器去筛,效率低且容易漏掉关键项,外汇和贵金属的高杠杆特性还会放大这种滞后带来的风险。 MQL5 的价值就在这:它允许你直接联网抓取、过滤、做计算,把原本靠人脑并行不了的信息处理交给程序。同样一份数据,程序在秒级完成归类,你大概率比手动刷浏览器的交易者更早做出反应。
先把信息源定下来
做自动化分析前,第一步不是写代码,而是确认你要喂给 MQL5 的数据从哪来。这一步没法抄别人的作业——做欧盘突破的交易者盯 tick 级价差就够,做中线贵金属的可能只要日线收盘价和 CFTC 持仓。选错源,后面所有指标都是垃圾进垃圾出。 本文用行情信息网页当作示例源,把从取数到落地的完整链路走一遍。MQL5 自带的方法能覆盖绝大多数取数和计算需求,不依赖任何外部程序也能跑通,适合只想在 MT5 里闭环的人。 你照着这套流程走完,再按自己的品种和周期改参数就行。外汇和贵金属杠杆高、跳空频繁,源数据若带隔夜缺口,回测和实盘偏差会明显放大,取数时要先确认时间轴对齐。
「让 MT5 替你抓外网数据」
想做跨源数据分析,第一步是让 MT5 脚本直接拉取网页内容,而不是靠人手在浏览器里复制。下面这段脚本只做一件事:向指定地址发 GET 请求,把返回的字节流存成 url.txt。 脚本里高亮写死的地址是 https://tradingeconomics.com/stocks,超时参数默认 750 毫秒。WebRequest 返回 -1 就说明请求失败,常见原因是平台没给这个站点授权,而不是代码本身有错。 在 MT5 里直接编译运行没用,必须先允许平台访问目标站。路径要填站点根地址,不是具体页面。授权成功后,配置会写进 common.ini,完整位置是 C:\Users\<USER NAME>\AppData\Roaming\MetaQuotes\Terminal\<CODE PERSONAL>\config\common.ini。重装系统前备份这个文件,能省掉反复授权的麻烦,目前这套机制仅限 Windows 环境。 第一次裸跑会弹拒绝访问的提示,补完授权再跑,日志会打出 File saved successfully...,说明数据已落盘。外汇与贵金属行情受宏观事件冲击大、杠杆风险高,外网数据仅作辅助参考,别拿它当下单唯一依据。想深挖通信细节,直接查 WebRequest 及同族网络函数的文档,比反复试错省事。
class="macro">#class="kw">property copyright "Daniel Jose" class="macro">#class="kw">property version "class="num">1.00" class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { Print(GetDataURL("https:class=class="str">"cmt">//tradingeconomics.com/stocks")); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">string GetDataURL(class="kw">const class="type">class="kw">string url, class="kw">const class="type">int timeout = class="num">750) { class="type">class="kw">string headers; class="type">char post[], charResultPage[]; class="type">int handle; if (WebRequest("GET", url, NULL, NULL, timeout, post, class="num">0, charResultPage, headers) == -class="num">1) class="kw">return "Bad class="kw">return"; if ((handle = FileOpen("url.txt", FILE_WRITE | FILE_BIN)) != INVALID_HANDLE) { FileWriteArray(handle, charResultPage, class="num">0, ArraySize(charResultPage)); FileClose(handle); }else class="kw">return "Error saving file ..."; class="kw">return "File saved successfully..."; }