Connexus入门(第一部分):如何使用WebRequest函数?(基础篇)
在MT5里用WebRequest拉外部数据
MT5 的 MQL5 提供了 WebRequest 函数,让 EA 或指标能直接向外部 HTTP 接口发请求,把网页端行情、信号或自定义 API 数据拉进终端做处理。对做价格行为结合外部因子的交易者来说,这是把「小布盯盘」类分析接进自动系统的底层入口。 函数原型要求先声明目标域名白名单,否则调用会被终端安全策略拦截。实测在 MetaTrader 5 build 4410 之后,未在「工具→选项→EA交易」里勾选「允许 WebRequest 向以下 URL 列表」并填好域名,函数会直接返回 false,错误码 5400。 下面这段示范如何向一个 JSON 接口取数据并落到变量里,注意头文件与异步标志位:
class="macro">#include <Trade/Trade.mqh> class="type">class="kw">string headers=""; class="type">char result[]; class="type">class="kw">string result_headers; class="type">int timeout=class="num">5000; class="type">class="kw">string url="https:class=class="str">"cmt">//api.example.com/quotes"; class="type">bool ok=WebRequest("GET",url,headers,timeout,result,result_headers); if(!ok) Print("WebRequest failed, error ",GetLastError());
class="macro">#include <Trade/Trade.mqh> class="type">class="kw">string headers=""; class="type">char result[]; class="type">class="kw">string result_headers; class="type">int timeout=class="num">5000; class="type">class="kw">string url="https:class=class="str">"cmt">//api.example.com/quotes"; class="type">bool ok=WebRequest("GET",url,headers,timeout,result,result_headers); if(!ok) Print("WebRequest failed, error ",GetLastError());
「MT5 里 WebRequest 为什么不够用」
在 MT5 里做外部通信,WebRequest 是官方给的唯一原生函数。想让 EA 拉新闻 API、查交易所币种报价、把信号推到第三方服务,都得走它。 但实际用起来很快会卡壳:头部拼错、JSON 格式不对、响应解析异常,任何一处都能让请求静默失败。对新手来说,光搞清 HTTP 协议和系统间握手就够劝退,更别说还要在 EA 里兜底超时和报错。 我们这套系列要做的,是先把 WebRequest 的短板摊开,再逐步攒出一个叫 Connexus 的库,把底层网络细节封掉。目标很直接——你只写策略逻辑,不用再调头部和格式 bug。 后面几篇会碰 API 鉴权、大体积数据、并发请求和响应时间控制。外汇和贵金属本身高杠杆高风险,自动化拉外部数据若延迟或出错,可能放大滑点和错单,验证前务必在模拟盘跑通。
◍ WebRequest 的参数坑比你想的多
MQL5 里跟外部服务器打交道,核心就是 WebRequest。它支持 GET 和 POST 两种请求,能接几乎所有公开 API,但真写起来远没有文档开头那句「发送请求并接收响应」轻松。 函数有两种重载:带 headers 参数的版本把 cookie、referer 拆掉,改由 headers 数组统一传;不带 headers 的版本则保留 cookie 和 referer 独立入参。下面这段是原生声明,注意参数顺序差异。
class="type">int WebRequest( class="kw">const class="type">class="kw">string method, class=class="str">"cmt">// HTTP method class="kw">const class="type">class="kw">string url, class=class="str">"cmt">// URL class="kw">const class="type">class="kw">string cookie, class=class="str">"cmt">// cookie class="kw">const class="type">class="kw">string referer, class=class="str">"cmt">// referer class="type">int timeout, class=class="str">"cmt">// timeout class="kw">const class="type">char &data[], class=class="str">"cmt">// the array of the HTTP message body class="type">int data_size, class=class="str">"cmt">// data[] array size in bytes class="type">char &result[], class=class="str">"cmt">// an array containing server response data class="type">class="kw">string &result_headers class=class="str">"cmt">// headers of server response ); class="type">int WebRequest( class="kw">const class="type">class="kw">string method, class=class="str">"cmt">// HTTP method class="kw">const class="type">class="kw">string url, class=class="str">"cmt">// URL class="kw">const class="type">class="kw">string headers, class=class="str">"cmt">// headers class="type">int timeout, class=class="str">"cmt">// timeout class="kw">const class="type">char &data[], class=class="str">"cmt">// the array of the HTTP message body class="type">char &result[], class=class="str">"cmt">// an array containing server response data class="type">class="kw">string &result_headers class=class="str">"cmt">// headers of server response );
class="type">int WebRequest( class="kw">const class="type">class="kw">string method, class=class="str">"cmt">// HTTP method class="kw">const class="type">class="kw">string url, class=class="str">"cmt">// URL class="kw">const class="type">class="kw">string cookie, class=class="str">"cmt">// cookie class="kw">const class="type">class="kw">string referer, class=class="str">"cmt">// referer class="type">int timeout, class=class="str">"cmt">// timeout class="kw">const class="type">char &data[], class=class="str">"cmt">// the array of the HTTP message body class="type">int data_size, class=class="str">"cmt">// data[] array size in bytes class="type">char &result[], class=class="str">"cmt">// an array containing server response data class="type">class="kw">string &result_headers class=class="str">"cmt">// headers of server response ); class="type">int WebRequest( class="kw">const class="type">class="kw">string method, class=class="str">"cmt">// HTTP method class="kw">const class="type">class="kw">string url, class=class="str">"cmt">// URL class="kw">const class="type">class="kw">string headers, class=class="str">"cmt">// headers class="type">int timeout, class=class="str">"cmt">// timeout class="kw">const class="type">char &data[], class=class="str">"cmt">// the array of the HTTP message body class="type">char &result[], class=class="str">"cmt">// an array containing server response data class="type">class="kw">string &result_headers class=class="str">"cmt">// headers of server response );
用 httpbin 跑通 WebRequest 的 POST 坑点
想在 MT5 里验证 WebRequest 到底怎么发请求,最省事的办法是拿 httpbin.org 当镜子——它开源免费,会把你发过去的内容原样返给你,适合检查头部、正文和状态码。先在终端「工具 → 选项 → 工具」里把 https://httpbin.org 加进允许 URL 列表,否则函数直接被拦。 第一步先发个 GET,状态码回 200 就说明链路通了;接着改 POST,把 JSON 正文丢进请求体。问题来了:httpbin 返回的「data」和「json」字段全是空的,因为没告诉服务器内容类型是 application/json,补上请求头部后才算入门。 真正的坑在 StringToCharArray——它会在末尾塞一个空终止符 \u0000。打印出来能看到字节数组比字符串多 1 位,最后值是 0 而不是 125(即「}」)。不处理掉,服务端就不认你发的 JSON。用 ArrayRemove() 砍掉末位,字符串和数组长度对齐,响应里「json」字段才正常回显。 这套动作暴露出 WebRequest 并不友好:一个终止符就能让 POST 失效。外汇与贵金属 EA 调用外部接口本就带网络与协议风险,实盘前务必在 demo 环境复现上述 200 与字段回显现象。Connexus 这类封装库的价值,就是替你挡住这种底层字节级麻烦。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| WebRequest.mq5 | class=class="str">"cmt">//| Copyright class="num">2023, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2023, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(class="kw">const class="type">int reason) { class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Defining variables