为 MetaTrader 5 创建自定义新闻递送(基础篇)
给 MT5 接一套自己的新闻推送
MetaTrader 5 终端默认的新闻流由经纪商统一定制,内容节奏和品种覆盖往往对短线价格行为交易者不够友好。想按自己的关注清单(比如只盯美联储官员讲话、伦敦定盘前后贵金属异动)收新闻,就得在终端里搭一套自定义递送逻辑。 这套思路的早期公开示例出现在 2018 年 3 月 22 日,原帖在社群里累计被查看约 7085 次、收藏 3 次,说明手动改新闻源的需求一直有人在摸索。外汇与贵金属属高杠杆品种,新闻触发瞬间的滑点和点差扩张风险极高,任何新闻策略先在小周期模拟盘验证再上实盘。 实现上不一定要重写终端内核,更轻量的做法是挂一个 EA 或脚本,用 WebRequest 去拉你指定的 RSS / API,再写进终端窗口或推到手机通知。下一段给一个最小可用的 MQL5 请求骨架,你直接抄进 MT5 的脚本里就能跑通联调。
◍ 终端内置新闻的边界在哪
MT5 自带的实时新闻订阅能给出市场背景,但覆盖范围由经纪商决定,不同账户之间差异很大。有些券商接了路透、道琼斯这类渠道,新闻可用度高;有些则干脆不提供,终端里的新闻标签形同虚设。 这意味着你看到的新闻流不是平台统一标准,而是经纪商实施能力的副产品。做外汇或贵金属本来波动就受消息驱动,若依赖终端原生新闻却碰上券商没接源,很容易在关键时段缺背景。 更灵活的做法是绕开这个限制,自己拉取指定类别和来源的新闻。后面会拆一个从外部源取新闻并推到 MT5 的小程序思路,先记住:原生新闻只是‘可能有用’,别把它当唯一信息面。
「用 NewsAPI 替代 RSS 喂新闻」
MT5 里接新闻,最笨的办法是逐个手填 RSS 地址,再在终端选项里开 Web 请求白名单——渠道一多,这件事就会变成纯体力活。 更直接的路是走 web API。NewsAPI 通过一次 HTTP Get 就能拉回 JSON 元数据,覆盖多家媒体源,全部走同一个 URL,不用为每个站点单独配置。 它目前明显的短板是语言结构:内容以美欧媒体为主,非英语地区的覆盖偏弱。对外汇和贵金属交易者而言,这类宏观新闻驱动行情波动,杠杆品种高风险,用之前先确认源的时间区和你的交易时段是否对得上。 若想在 EA 里验证,直接发一个 Get 请求到它的 endpoints,解析 articles 数组里的 title 与 publishedAt,就能把头条时间轴叠到你的 K 线上看反应。
拿到 NewsAPI 密钥才跑得通
想在 MT5 里接 NewsAPI 做事件驱动分析,第一步不是写代码,而是先拿到合法密钥。官方站点提供注册入口,用邮箱登记后系统会下发一组 API Key,没有它任何完整服务请求都会被拒。 外汇与贵金属受新闻冲击极快,这类接口调用属于高风险辅助手段,密钥泄露还可能被限流或封号,建议单独建邮箱并本地加密存储。 拿到密钥后,下一步就是在 EA 或脚本里用 WebRequest 把 key 带进 Header 做验证,这部分参数配错就会直接返回 401。
◍ 抓新闻源要先过这两道 URL
NewsAPI 的访问入口只有两个基础地址,先把它们分清才不会在 MT5 里写错请求。第一个是 https://newsapi.org/v1/sources?,单次请求就能拉回当前 API 上全部可用新闻资源,连同每个资源在后续取标题时要用到的唯一标识符一起返回;这个地址支持用参数限定返回的资源类别,比如只拿特定语言或特定主题的来源。 第二个地址 https://newsapi.org/v1/articles? 才是真正取标题和摘要的地方,但它强制带两个参数:一个是 sources 接口给的资源 ID,另一个是你在官网申请的授权 API 密钥,缺一个都会直接 401。 实际接 MT5 的 WebRequest 时,建议先用 sources 把 ID 缓存到本地文件,再拿 articles 去轮询,避免每根 K 线都重复请求全量源列表。外汇与贵金属受突发新闻影响剧烈,这类接口数据仅作辅助参考,实盘仍需警惕滑点与流动性风险。
「用脚本把 API 响应落盘看个明白」
想摸清一套外部 API 的脾气,最快的办法不是读文档,而是在 MT5 里跑一个能把响应原样存文件的脚本。NewsAPI_test 就是干这个的:它发出 webrequest,把返回的 json 文本写进本地 txt,你打开就能看到结构。 脚本头部用 #define 拼出请求 URL 的几个部件——BASE_URL 是根地址,SRCE 和 ATCLE 分别对应「取新闻源列表」和「取某源文章」两种路径,API_KEY 直接硬编码在末尾。输入参数里 sFilename 决定缓存文件名,Mode 是个枚举,让你在 sources 与 articles 两个主接口间切换;parameters 留作附加的 URL 参数位。 跑起来后建议分三步试:先用默认参数走 sources,打开 sorce.txt 会看到一组 json 对象数组,每个代表一个可订阅新闻渠道;再把 Mode 切到 articles 并填好 错误响应也得亲自撞一次。把 API_KEY 改错,或填一个不存在的 source ID,文件里返回的 json 会带 status:error 和对应的 message 字段——外汇与贵金属行情受新闻驱动的波动大、杠杆风险高,这类异常若在生产 EA 里没接住,可能直接误判信号。 下面这段是脚本前半部分,重点看枚举与 URL 拼装逻辑: #define 定义 BASE_URL 为 "https://newsapi.org/v1/",即请求根域名 #define 定义 SRCE 为 "sources?",用于获取新闻源列表的端点 #define 定义 ATCLE 为 "articles? #define 定义 API_KEY 为 "&apiKey=484c84eb9765418fb58ea936908a47ac",鉴权附加段 enum mode 声明枚举,含 sources 与 articles 两个值,控制请求类型 sFilename 为输入字符串,默认 "sorce.txt",指定响应缓存文件 Mode 为输入枚举,默认 sources,决定走哪条 URL 分支 parameters 为输入字符串,默认空,承载额外 URL 参数 timeout 设 5000 毫秒,约束 WebRequest 等待上限 OnStart 里只调 TestWebRequest,脚本入口极简 TestWebRequest 中声明 cookie、headers、post、result 等缓冲变量 switch(Mode) 判断:case sources 时将 BASE_URL+SRCE+parameters 赋给 _url 并 break
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| NewsAPI_test.mq5 | class=class="str">"cmt">//| 版权所有 class="num">2017, ufranco | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "版权所有 class="num">2017, ufranco" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property script_show_inputs class="macro">#define BASE_URL "https:class=class="str">"cmt">//newsapi.org/v1/" class="macro">#define SRCE "sources?" class="macro">#define ATCLE "articles? class="macro">#define API_KEY "&apiKey=484c84eb9765418fb58ea936908a47ac" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ enum mode { sources, articles }; input class="type">class="kw">string sFilename="sorce.txt"; input mode Mode=sources; input class="type">class="kw">string parameters=""; class="type">int timeout=class="num">5000; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 脚本程序开始函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//--- TestWebRequest(); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| TestWebRequest | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void TestWebRequest(class="type">void) { class="type">class="kw">string cookie=NULL,headers; class="type">char post[],result[]; class="type">int res; class="type">class="kw">string _url; class=class="str">"cmt">//--- class="kw">switch(Mode) { case sources: _url=BASE_URL+SRCE+parameters; class="kw">break;