从网络中获取债券收益率数据(基础篇)
📘

从网络中获取债券收益率数据(基础篇)

第 1/3 篇

在 MT5 里抓取债券收益率行情

做宏观对冲的交易者常把美债收益率当美元与贵金属的领先变量。MT5 默认品种列表不含债券收益率,但终端本身支持从网络直接拉取外部数据源,不必另开浏览器或第三方软件。 实现思路是用 MQL5 的 WebRequest 向公开接口发请求,把返回的 JSON 或 CSV 解析后写进指标缓冲区。以 10 年期美债收益率为例,数据频率按日更新就够日内波段使用,若做跨资产相关性回测建议至少取 3 年历史。 实际落地时要注意:MT5 的「工具→选项→EA 交易」里必须勾选「允许 WebRequest 访问」,并把目标域名加入白名单,否则代码跑起来只返回 0 长度。外汇与贵金属本身杠杆高、波动受利率预期牵引明显,用收益率曲线斜率辅助判断方向仅提高概率,不构成单边押注依据。

◍ 利率差才是汇率的隐形引擎

自动交易系统大多吃技术指标这碗饭,用历史价格推演未来。但纯技术派容易漏掉一个事实:市场底层的基本面力量,往往让只跑指标的 EA 处在劣势。把基础数据接进决策链,专家顾问的命中逻辑才可能补上短板。 外汇里最硬的基本面锚是利率。央行牌价不动,不代表资金面静止——美国国债收益率、十年期国债在全球盘面里分秒波动,它们提前定价了市场对央行下一步利率路径的预期。债券收益率因此常跑在利率与汇率前面。 对货币对而言,真正可量化的不是绝对利率,而是不同期限之间的利差,尤其是 delta(利差变化量)。图1的每小时 EUR/USD 上,利率差以基点计的变动方向,领先同方向汇率变动——这是一个可肉眼复核的领先现象。 本文后续会拆如何从网络拉取债券收益率,并由利率差及其增量表达式反推所需数据,让 MT5 上的指标不再只靠价格自己骗自己。

「抓取是怎么把网页数字变成数值的」

MT5 之外的行情与基本面数据,很多散落在网页的文件里。一个网页在浏览器里是图文声像的集合,但底层其实是 Web 服务器上多个带 URL 的文件,浏览器按顺序拉取渲染。程序可以只点名其中一个文件,忽略其余,前提是你得知道那个文件的精确地址。 这种只取所需元素的做法就是抓取。它不关心页面排版,只认 URL 和文件里的纯文本。比如某页显示欧元区的 CPI 数字,那个数字背后是某个 HTML 或 JSON 文件里的一段文本,抓取程序下载该文件、定位文本、再转成 double 型数值,就能喂给 EA 做条件判断。 外汇与贵金属受数据跳变影响大、波动快,这类抓取有高风险:源站改版、URL 失效、反爬限流都会让数值断流。实战里建议先把抓取到的原始文本打印到专家日志,确认字段稳定再接策略。

从页面里抠出报价的真实地址

做网页抓取,第一步永远是拿到那个装着目标数据的文件 URL。它可能是页面本身,可能是页面里某个链接,也可能是页面脚本跑完才生成的地址——后一种在 Chrome 的「更多工具」里抓包就能看到,不用真去执行脚本。 以 bond 收益率页面为例,marketwatch 的 10 年美债页把报价直接写进了 HTML 头部的 meta 标签,对浏览器显示毫无影响,但任何下载了 HTML 的文本程序都能读。 实测该页中报价落在 <meta name="price" content="3.066">,距标签起始位置正好 28 个字符,和页面上高亮的数字一致。抓取程序只需搜索 <meta name="price" content=,把命中处索引后移 28 位,再把那段文本转成浮点即可。外汇与贵金属受宏观利率影响大,这类利率数据波动剧烈,使用需自担高风险。

◍ 只拉前 4KB 就能避开 295KB 的浪费

上面那份 HTML 文件从服务器拉下来带了一堆样式表,整包 295 千字节,但我们要的 meta 标记在开头 3 千字节处就出现了。按价格行为辅助抓取的逻辑,每次刷报价只取前 4 千字节最合理,能省掉九成以上流量。 MQL5 自带的 WebRequest() 做不到限流下载。它的接收数组必须是动态数组;你要是塞一个定长静态数组,编译能过,运行直接崩终端。也有人试着在请求里加 Range 头,但多数公网服务器不认,最后还是把整个 HTML 文件拖回来。 更稳的路子是调 Windows 的 wininet.dll。里面的 InternetReadFile() 能指定字节数读取,哪怕服务器不支持 Range、只能从头读,也能只读前 4KB 就停。下面这段脚本就走了 wininet 路线:抓前 4KB、定位 meta、抠出 10 年美债收益率文本转浮点、打印到终端。外汇和贵金属受美债收益率牵引明显,但这种抓取依赖外网稳定性,实盘前务必在 MT5 策略测试器外手动跑脚本验证,高风险品种请控制频率。

「用 MT5 脚本直连抓取美债收益率」

想在 MT5 里绕过第三方接口、直接把网页上的数据拉进图表?ScraperBot01 的思路是先 import wininet.dll,把 Windows 原生的 InternetOpenW / InternetOpenUrlW / InternetReadFile 等函数原型化,类型全部对齐 MQL5 规范,这样脚本才能调起系统级网络栈。 全局层用 uc_Buffer[4096] 作静态接收缓冲——WinINet 的 ReadFile 要求缓冲区必须是静态数组,否则运行期直接报错;f_US 则承接从 HTML 里解析出的数值。约定上,类型说明符和变量名之间的下划线专门用来标记全局变量,读代码时能一眼区分作用域。 OnStart 里先拿 InternetCheckConnectionW 探活,传 FLAG_ICC_FORCE_CONNECTION(1) 强制检测;返回非 0 才继续,否则直接 return。随后 InternetOpenW 拿 iNet1 句柄(有效值 >0),再对 marketwatch 的 10 年期美债页发 InternetOpenUrlW,dwFlags 用 0x00080000 即 INTERNET_FLAG_NO_COOKIES,避免会话被重定向。 抓回来的文本在 uc_Buffer 里,搜 meta 标签命中后偏移 +28 定位数字串,StringSubstr 取出、StringToDouble 转浮点;若非数字会返回 0,仅当收益率恰为 0 时歧义。脚本在任何图表运行都会在终端打印进度与最终值,外汇/贵金属交易者需注意:美债收益率跳动会传导至 XAUUSD 波动,此类网络抓取受目标站改版与网络延迟影响,信号可能延迟或失效,属高风险参考。 把下面代码存成 ScraperBot01.mq5 挂任意图表,终端会打出 iNet1/iNet2 句柄值与抓取结果;哪天 marketwatch 改了页面结构,你只需调偏移量和 URL 两个参数就能续命。

MQL5 / C++
class="macro">#class="kw">import "wininet.dll"
  class="type">int InternetCheckConnectionW(class="type">class="kw">string& lpszUrl, class="type">uint dwFlags, class="type">uint dwReserved);
class="type">int InternetOpenW(class="type">class="kw">string& lpszAgent, class="type">uint dwAccessType, class="type">class="kw">string& lpszProxyName, class="type">class="kw">string& lpszProxyBypass, class="type">uint dwFlags);
class="type">int InternetOpenUrlW(class="type">int hInternetSession, class="type">class="kw">string& lpszUrl, class="type">class="kw">string& lpszHeaders, class="type">uint dwHeadersLength, class="type">uint dwFlags, class="type">uint dwContext);
class="type">int InternetReadFile(class="type">int hFile, class="type">uchar& lpBuffer[], class="type">uint dwNumberOfBytesToRead, class="type">uint& lpdwNumberOfBytesRead);
class="type">int InternetCloseHandle(class="type">int hInternet);
class="macro">#class="kw">import
class="type">uchar uc_Buffer[class="num">4096]; class=class="str">"cmt">// InternetReadFile() 需要静态的缓冲区.
class="type">float f_US;
class="type">void OnStart()
{ class="type">bool bResult;  class="type">int i, iNet1, iNet2;  
  class="type">class="kw">string stURL = "http:class=class="str">"cmt">//www.msn.com";
  bResult = InternetCheckConnectionW(stURL, class="num">1, class="num">0); class=class="str">"cmt">// class="num">1 == FLAG_ICC_FORCE_CONNECTION
  Print("InternetCheckConnectionW() returned ", bResult);
  if(!bResult) class="kw">return;
  
  class="type">class="kw">string stAgent = "Mozilla/class="num">5.0", stNull = "";
  iNet1 = InternetOpenW(stAgent, class=class="str">"cmt">// _In_ LPCTSTR lpszAgent 
                        class="num">1,       class=class="str">"cmt">// class="num">1 == INTERNET_OPEN_TYPE_DIRECT
                        stNull,  class=class="str">"cmt">// _In_ LPCTSTR lpszProxyName
                        stNull,  class=class="str">"cmt">// _In_ LPCTSTR lpszProxyBypass
                        NULL);   class=class="str">"cmt">// _In_ DWORD dwFlags
  Print("iNet1 == ", iNet1);
  if(iNet1==class="num">0) class="kw">return;
  stURL = "https:class=class="str">"cmt">//www.marketwatch.com/investing/bond/tmubmusd10y?countrycode=bx";
  class="type">class="kw">string stHdr = "Accept: text/*";
  iNet2 = InternetOpenUrlW(iNet1,            class=class="str">"cmt">// HINTERNET hInternet,
                            stURL,           class=class="str">"cmt">// LPCWSTR   lpszUrl,
                            stHdr,           class=class="str">"cmt">// LPCWSTR   lpszHeaders,
                            StringLen(stHdr), class=class="str">"cmt">// DWORD     dwHeadersLength,
                            0x00080000,      class=class="str">"cmt">// DWORD     dwFlags, 0x00080000 == INTERNET_FLAG_NO_COOKIES
                            NULL);           class=class="str">"cmt">// DWORD_PTR dwContext
  Print("iNet2 == ", iNet2);
  if(iNet2==class="num">0)
  { InternetCloseHandle(iNet1);
    class="kw">return;
  }
  class="type">uint uGet, uGot;
uGet = class="num">4080; class=class="str">"cmt">// 要下载的字节数

常见问题

可用脚本直连公开数据源把收益率拉进行情窗口,作为自定义品种观察,避免来回切换页面。
利率差是汇率的隐形驱动,两国债券收益率拉开差距时,对应货币倾向升值或承压,可重点盯利差变化。
小布可定时抓取关键期限收益率并对比货币对走势,出现明显背离时直接推送提醒,省去手动刷网页。
报价数据通常在页面前部,只拉前4KB就能拿到数值,全页近295KB大多是冗余脚本,纯属浪费流量和延时。
打开浏览器开发者工具看网络请求,筛出返回纯数据的那个接口地址,脚本直连它即可,别抓整个HTML页。