MQL5-RPC来自 MQL5 的远程过程调用:针对乐趣及获利的网络服务访问及 XML-RPC 自动交易锦标赛分析程序(基础篇)
◍ 用 MQL5 直接拉取 XML-RPC 做锦标赛分析
MQL5 环境里可以通过 WebRequest 发起 XML-RPC 调用,把远程自动交易锦标赛的数据拉回 MT5 本地做统计。对做价格行为研究的人来说,这等于把线上赛的数据源变成了可复算的样本库,而不是只看排行榜截图。
- 年 5 月那篇原始示例里,作者 investeo 就用这套办法访问了当时锦标赛的远程接口,累计被社区查看 2749 次、评论 17 条,说明这类玩法在早期就有明确需求。外汇与贵金属品种波动大、杠杆高,用历史赛果做样本推算时务必当作高风险参考,别直接当实盘信号。
本质上就是让 EA 或脚本替你跑远程过程调用:传参、收 XML、本地解析。下面这段是当时示例里最关键的请求骨架,注意 User-Agent 和 Content-Type 必须按服务端要求带。
class="type">class="kw">string endpoint="http:class=class="str">"cmt">// championship.mql5.com/rpc"; class="type">class="kw">string post="<?xml version=\"class="num">1.0\"?><methodCall><methodName>competition.results</methodName><params></params></methodCall>"; class="type">char post_data[],result[];class="type">class="kw">string hdr="User-Agent: MT5\r\nContent-Type: text/xml\r\n"; class="type">int res=WebRequest("POST",endpoint,hdr,class="num">3000,post_data,result);
「MQL5-RPC 框架是什么」
最近几周搭建的 MQL5-RPC 框架,核心由三部分组成:XML-RPC 访问基础、MQL5 端实施说明,以及两个可直接跑的真实用例。 第一个用例是对外部 Forex 网站网络服务的远程过程调用,第二个则是连到自建 XML-RPC 服务器,专门解析并分析 2011 年自动交易锦标赛的赛果数据。 如果你想知道怎么在 MT5 里实时拉取并拆解那届锦标赛的多维统计,这套框架能省掉大量重复造轮子的工作。外汇与贵金属自动化分析属高风险操作,回测与实盘表现可能存在显著偏差。
先搞清 XML-RPC 是哪路协议
XML-RPC 全名是 XML Remote Procedure Call,本质是一套用 XML 给参数做编解码、从而远程调用外部方法的网络协议。它跑在 HTTP 之上,传输层就是普通 web 请求,这一点决定了它在 MT5 里走的是 80/443 端口,不需要额外开防火墙策略。 所谓外部方法,指的是另一台机器或同机另一个进程里暴露出来的远程过程,只要调用方也实现了 XML-RPC 协议栈、且网络可达,任何语言都能发起请求。 一个值得记下的点:它不仅能跨机器,也能在同机调用另一种语言写的服务。后面第二部分会专门拆同机异语言调用的做法,本文先只把协议边界说清。
◍ XML-RPC 的数据类型怎么塞进 MT5 通信
XML-RPC 只定义了六种基础类型加两种复合类型,基础类是 int(32 位整数,范围 -2,147,483,648 到 2,147,483,647)、double、boolean、string、datetime.iso8601 与 base64;复合类则是 array 和 struct。做 MT5 客户端时,你发出的请求体和收到的响应体都得严格落在这套类型里,否则远端服务会直接拒收。 array 不要求元素同型,外层是 value 包 array,array 里再套 data,data 下挂多个 value。下面这段代码就是一个四整数数组加一个五字符串数组的实例,注意 -3456 这种负值也照常走 int 标签。 struct 用来传名称-值对,相当于关联数组或对象属性:value 内放 struct,struct 内放若干 member,每个 member 由 name 和 value 组成。行情推送里若想带「品种名+买价+卖价」这类字段,用 struct 比纯 array 更不易解析错位。 熟悉这套数据模型后,下一步就是把它拼成请求与响应结构——那才是 MQL5 写 XML-RPC 客户端的落地起点。外汇与贵金属接口调用存在断连、滑点等高风险,参数序列化前建议先在本地打印报文核对类型。
<span class="tag"><<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">array</span><span>></span></span> <span class="tag"><<span class="title">data</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">int</span><span>></span></span>class="num">111<span class="tag"></<span class="title">class="type">int</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">int</span><span>></span></span>class="num">222<span class="tag"></<span class="title">class="type">int</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">int</span><span>></span></span>-class="num">3456<span class="tag"></<span class="title">class="type">int</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">int</span><span>></span></span>class="num">666<span class="tag"></<span class="title">class="type">int</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"></<span class="title">data</span><span>></span></span> <span class="tag"></<span class="title">array</span><span>></span></span> <span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">array</span><span>></span></span> <span class="tag"><<span class="title">data</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">class="kw">string</span><span>></span></span>MQL5<span class="tag"></<span class="title">class="type">class="kw">string</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">class="kw">string</span><span>></span></span>is <span class="tag"></<span class="title">class="type">class="kw">string</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">class="kw">string</span><span>></span></span>a<span class="tag"></<span class="title">class="type">class="kw">string</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">class="kw">string</span><span>></span></span>great<span class="tag"></<span class="title">class="type">class="kw">string</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span><span class="tag"><<span class="title">class="type">class="kw">string</span><span>></span></span>language.<span class="tag"></<span class="title">class="type">class="kw">string</span><span>></span></span><span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"></<span class="title">data</span><span>></span></span> <span class="tag"></<span class="title">array</span><span>></span></span> <span class="tag"></<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">value</span><span>></span></span> <span class="tag"><<span class="title">class="kw">struct</span><span>></span></span> <span class="tag"><<span class="title">member</span><span>></span></span>
「把账户画像塞进 XML 结构」
MQL5 的序列化机制允许把自定义 struct 直接写成 XML 节点,每个字段对应一个 member 块。下面这段片段演示了三个基础类型的落地方式:字符串、整型、双精度浮点。 AccountHolder 字段用 string 承载,值为 John Doe;Age 用 int 写入 77;Equity 用 double 记录 1000000.0。这种写法在把交易账户元数据导出给外部分析脚本时很实用,节点名即字段名,类型标签决定了解析端的强类型还原。 开 MT5 建个同构 struct 跑 Serialize 看输出,能确认你本地编译器生成的 XML 缩进与标签顺序是否和这段一致。外汇与贵金属交易含高杠杆风险,这类序列化只解决数据传输,不暗示任何仓位安全性。
<member>
<name>AccountHolder</name>
<value><class="type">class="kw">string>John Doe</class="type">class="kw">string></value>
</member>
<member>
<name>Age</name>
<value><class="type">int>class="num">77</class="type">int></value>
</member>
<member>
<name>Equity</name>
<value><class="type">class="kw">double>class="num">1000000.0</class="type">class="kw">double></value>
</member>
</class="kw">struct>
</value>XML-RPC 报头与有效负荷的拼装方式
一次 XML-RPC 调用分两层:HTTP 报头 + XML 有效负荷。报头里必须写死 POST 方法、相对路径(如 /xmlrpc)、HTTP 1.1、User-Agent、Host、Content-Type: text/xml,以及以字节计数的 Content-Length。上面例子里 Content-Length 是 188,少算一个换行服务器就会拒收。 有效负荷的根节点只能是 methodCall,里面挂 methodName 和 params。methodName 填服务端暴露的函数名,params 下每个 param 包一个 value,类型按 double / int / string 等标签显式声明。例子中 multiply 传了两个 double:8654.41 和 7234.00,服务端算完原样回 XML-RPC 响应。 在 MT5 里用 WebRequest 发这种请求时,自己拼字符串最容易在 Content-Length 上翻车——建议先算 UTF-8 字节数再填,别照抄例子里的 188,否则换台机器就可能报 400。
POST /xmlrpc HTTP class="num">1.1 User-Agent: mql5-rpc/class="num">1.0 Host: class="num">10.12.class="num">10.10 Content-Type: text/xml Content-Length: class="num">188 <?xml version="class="num">1.0"?> <methodCall> <methodName>multiply</methodName> <params> <param> <value><class="type">class="kw">double>class="num">8654.41</class="type">class="kw">double></value> </param> <param> <value><class="type">class="kw">double>class="num">7234.00</class="type">class="kw">double></value> </param> </params> </methodCall>