从网络中获取债券收益率数据·综合运用
「用利率差给欧美找方向」
EUR/USD 以美元标价欧元,所以欧元走强、美元走弱都会推升报价,方向相反则压低报价。要把利率差当成方向探针,核心算法就是欧洲复合债券收益率减美国国债收益率,即 f_EU - f_US。 写这段技术说明时,f_EU 实测 1.255、f_US 实测 3.142,利差算出来是 -1.887。若利差从 -1.887 走到 -1.798,属正向扩张,欧美倾向上涨;若滑到 -1.975,属负向加深,欧美可能下跌。外汇与贵金属杠杆高,单看利差不可重仓押注。 指标靠不靠谱,看的是基点位移幅度。从 -1.887 到 -1.975 是负向动 8.8 个基点,在小时图上算强日内波动,可能引出下行。只挪 1~2 个基点基本是噪音,大概率没法指示货币对真实波动。
一次拉回四国债券收益率的抓取脚本
这个脚本的思路是一次性把美、德、法、意四个十年期国债收益率全抓回来,而不是像前一个版本那样每个品种发一次请求。它把四个代码拼进同一个 URL,服务器在一次约 14 KB 的下载里返回连续文本块,终端里能直接算出欧洲综合收益率并打出利率差。 定位数据时,脚本先在缓冲里找票符(Ticker)字符串,再向前搜预设的 JSON 路径片段;任何一段找不到就打印错误并退出,避免脏数据混进后续计算。 注意 MT4 上的同名思路版本用了 WinINet 而不是 WebRequest,在 MT4 环境里网络行为不太稳,真要跑建议直接在 MT5 验证本脚本的 WebRequest 路径。外汇和贵金属受利差驱动明显,但利率差走向只是概率倾向,实操仍属高风险。 下面这段是核心抓取与美债定位的节选,逐行看:char 与 float 全局声明分别管缓冲和利率值;OnStart 里拼好的 stURL 用 id= 参数挂了四个 Bond 代码;WebRequest 的 1024 是超时毫秒级设定,返回的 ch_Buffer 用 ArraySize 打出真实字节数;之后用 StringFind 从 TMUBMUSD10Y 票符偏移再跳 61 字节,取 8 位子串转 double 存进 f_US。
<span class="keyword">class="type">char</span> ch_Buffer[], ch_Data[<span class="number">class="num">16</span>]; <span class="comment">class=class="str">"cmt">// 全局缓冲区</span> <span class="keyword">class="type">float</span> f_US, f_DE, f_FR, f_IT, f_EU; <span class="comment">class=class="str">"cmt">// 用于保存债券利率的全局变量</span> <span class="keyword">class="type">void</span> <span class="functions">OnStart</span>() { <span class="keyword">class="type">int</span> i; <span class="keyword">class="type">class="kw">string</span> stURL = <span class="class="type">class="kw">string">"https:class=class="str">"cmt">//api.wsj.net/api/dylan/quotes/v2/comp/quoteByDialect?dialect=official&needed=CompositeTrading|BluegrassChannels&"</span> <span class="class="type">class="kw">string">"MaxInstrumentMatches=class="num">1&accept=application/json&EntitlementToken=cecc4267a0194af89ca343805a3e57af&ckey=cecc4267a0&"</span> <span class="class="type">class="kw">string">"dialects=Charting&id=Bond-BX-TMUBMUSD10Y,Bond-BX-TMBMKDE-10Y,Bond-BX-TMBMKFR-10Y,Bond-BX-TMBMKIT-10Y"</span>; <span class="comment">class=class="str">"cmt">// 四个品种名称</span> <span class="keyword">class="type">class="kw">string</span> stHdr = <span class="class="type">class="kw">string">"Accept: text/*, User-Agent: Mozilla/class="num">5.0"</span>; <span class="keyword">class="type">class="kw">string</span> stRspHdr; <span class="comment">class=class="str">"cmt">// 回应头</span> i = <span class="functions">WebRequest</span>(<span class="class="type">class="kw">string">"GET"</span>, <span class="comment">class=class="str">"cmt">// class="kw">const class="type">class="kw">string method, HTTP 方法 </span> stURL, <span class="comment">class=class="str">"cmt">// class="kw">const class="type">class="kw">string url, URL </span> stHdr, <span class="comment">class=class="str">"cmt">// class="kw">const class="type">class="kw">string headers, </span> <span class="number">class="num">1024</span>, <span class="comment">class=class="str">"cmt">// class="type">int timeout, </span> ch_Data, <span class="comment">class=class="str">"cmt">// class="kw">const class="type">char &data[], HTTP 消息体的数组</span> ch_Buffer, <span class="comment">class=class="str">"cmt">// class="type">char &result[], 包含服务器回应数据的数组</span> stRspHdr); <span class="comment">class=class="str">"cmt">// class="type">class="kw">string &result_headers </span> <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Server response code: "</span>, i); <span class="keyword">if</span>(i == -<span class="number">class="num">1</span>) {<span class="functions">Print</span>(<span class="class="type">class="kw">string">"GetLastError == "</span>, <span class="functions">GetLastError</span>()); <span class="keyword">class="kw">return</span>;} <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Size of ch_Buffer(bytes downloaded) == "</span>, <span class="functions">ArraySize</span>(ch_Buffer)); <span class="keyword">class="type">class="kw">string</span> stSearch = <span class="class="type">class="kw">string">"\"CompositeTrading\":{\"Last\":{\"Price\":{\"Iso\":\"PERCENT\",\"Value\":"</span>; <span class="comment">class=class="str">"cmt">// Get US class="num">10-year treasury note yield.</span> i = <span class="functions">StringFind</span>(<span class="functions">CharArrayToString</span>(ch_Buffer),<span class="class="type">class="kw">string">"\"Ticker\":\"TMUBMUSD10Y\""</span>, <span class="number">class="num">0</span>); <span class="comment">class=class="str">"cmt">// class="num">0 == 开始搜索的位置 </span> <span class="keyword">if</span>(i == -<span class="number">class="num">1</span>) {<span class="functions">Print</span>(<span class="class="type">class="kw">string">"\"Ticker\":\"TMUBMUSD10Y\" not found."</span>); <span class="keyword">class="kw">return</span>;} i = <span class="functions">StringFind</span>(<span class="functions">CharArrayToString</span>(ch_Buffer), stSearch, i); <span class="comment">class=class="str">"cmt">// i == 开始搜索的位置 </span> <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Offset of "</span>, stSearch, <span class="class="type">class="kw">string">" == "</span>, i); <span class="keyword">if</span>(i == -<span class="number">class="num">1</span>) {<span class="functions">Print</span>(stSearch, <span class="class="type">class="kw">string">" not found."</span>); <span class="keyword">class="kw">return</span>;} i += <span class="number">class="num">61</span>; <span class="comment">class=class="str">"cmt">// 将索引提前到表示债券收益的文本的已知位置。</span> f_US = <span class="functions">StringToDouble</span>(<span class="functions">StringSubstr</span>(<span class="functions">CharArrayToString</span>(ch_Buffer), i, <span class="number">class="num">8</span>)); <span class="functions">Print</span>(<span class="class="type">class="kw">string">"US class="num">10-year T-note yield, stored in variable f_US: "</span>, f_US); <span class="comment">class=class="str">"cmt">// 获得德国10年期政府债券收益率。</span> i = <span class="functions">StringFind</span>(<span class="functions">CharArrayToString</span>(ch_Buffer),<span class="class="type">class="kw">string">"\"Ticker\":\"TMBMKDE-10Y\""</span>, i); <span class="comment">class=class="str">"cmt">// i == 开始搜索的位置 </span> <span class="keyword">if</span>(i == -<span class="number">class="num">1</span>) {<span class="functions">Print</span>(<span class="class="type">class="kw">string">"\"Ticker\":\"TMBMKDE-10Y\" not found."</span>); <span class="keyword">class="kw">return</span>;}
◍ 从网页缓冲里抠出德法意债券收益率
这段逻辑紧接前文把美股收益率算完之后,目标是从同一份网页字符缓冲 ch_Buffer 里再扒出欧洲三国十年期国债收益率。它靠 Ticker 字符串定位,再用固定偏移量跳到数值字段,对外汇和贵金属交易者来说,这种利差数据直接影响 EUR 系货币对和金银比价的波动概率,属于高风险关联变量,动手前先在 MT5 里确认你的缓冲结构和原文一致。 先处理德国:用 StringFind 在缓冲里找 stSearch 标记,找不到就打印未命中并退出;找到后索引前移 61 个字符——这是原文里写死的债券收益文本位置,再用 StringSubstr 截取 8 位转成双精度存进 f_DE。法国和意大利完全复刻这套动作,只是 Ticker 分别换成 TMBMKFR-10Y 和 TMBMKIT-10Y,结果进 f_FR、f_IT。 三国到手后做加权:f_EU = 0.449*f_DE + 0.315*f_FR + 0.236*f_IT,权重加起来正好是 1.0,算是按经济体量粗估的欧洲综合收益率。最后打印 f_EU 以及和前面美国收益率的差额 f_EU-f_US,这个差额扩大时,EURUSD 短线承压的可能性会上升,但绝不是单向结论。 别把 61 当常量抄 原文里 i += 61 是基于特定网页模板的偏移,一旦数据源改版前端结构,这个魔法数字会直接指到垃圾字符。建议你在 OnStart 里先 Print 出截取子串肉眼核对,再决定要不要写死。
i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); class=class="str">"cmt">// i == 开始搜索的位置 Print("Offset of ", stSearch, " == ", i); if(i == -class="num">1) {Print(stSearch, " not found."); class="kw">return;} i += class="num">61; class=class="str">"cmt">// 将索引提前到表示债券收益的文本的已知位置。 f_DE = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, class="num">8)); Print("German class="num">10-year government bond yield, stored in variable f_DE: ", f_DE); class=class="str">"cmt">// 获得法国10年期政府债券收益率。 i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMBMKFR-10Y\"", i); class=class="str">"cmt">// i == 开始搜索的位置 if(i == -class="num">1) {Print("\"Ticker\":\"TMBMKFR-10Y\" not found."); class="kw">return;} i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); class=class="str">"cmt">// i == 开始搜索的位置 Print("Offset of ", stSearch, " == ", i); if(i == -class="num">1) {Print(stSearch, " not found."); class="kw">return;} i += class="num">61; class=class="str">"cmt">// 将索引提前到表示债券收益的文本的已知位置。 f_FR = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, class="num">8)); Print("French class="num">10-year government bond yield, stored in variable f_FR: ", f_FR); class=class="str">"cmt">// 获得意大利10年期政府债券收益率。 i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMBMKIT-10Y\"", i); class=class="str">"cmt">// i == 开始搜索的位置 if(i == -class="num">1) {Print("\"Ticker\":\"TMBMKIT-10Y\" not found."); class="kw">return;} i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); class=class="str">"cmt">// i == 开始搜索的位置 Print("Offset of ", stSearch, " == ", i); if(i == -class="num">1) {Print(stSearch, " not found."); class="kw">return;} i += class="num">61; class=class="str">"cmt">// 将索引提前到表示债券收益的文本的已知位置。 f_IT = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, class="num">8)); Print("Italian class="num">10-year government bond yield, stored in variable f_IT: ", f_IT); class=class="str">"cmt">// 计算欧洲综合债券收益率。 f_EU = class="num">0.449*f_DE + class="num">0.315*f_FR + class="num">0.236*f_IT; Print("European composite bond yield: ", f_EU); class=class="str">"cmt">// 计算利率差额。 Print("Interest rate differential, f_EU-f_US = ", f_EU-f_US); }class=class="str">"cmt">//END class="type">void OnStart()
「利率差的增量比水平更值得盯」
做货币对,利率差异本身常常不是驱动,差异的变化才是。把某个bar收盘时的利差减去上一根bar收盘时的利差,就得到单根 Delta;它为正为负都正常,长期均值贴近零。 在日线以上周期,裸 Delta 还能看;但放到短周期,单根跳动噪声太大,用 Delta 的指数移动平均(EMA)更顺手,因为它把前面多根的变化都卷进来了。递推式是:EMA = a * Delta + (1 - a) * EMAp,其中 EMAp 是上一根算出来的 EMA。 平滑系数 alpha 可以拍脑袋给,也能按周期数反推:a = 2.0 / (n + 1),n 可以是整数也能是分数,正常区间就是 0 < a <= 1。当 a 拉到 1,公式里 EMAp 那项直接消失,EMA 退化成当前 Delta,等于没平滑。 若本地有利差历史库,就能写个指标把利差序列或 Delta 的 EMA 画在货币对图上。MT5 指标不许直连互联网扒数据,但允许读本地文件——你可以另写脚本从网上拽债券收益率落盘,指标再读盘更新。外汇与贵金属杠杆高,利差驱动只是概率倾向,实盘前务必在 MT5 用历史文件跑一遍验证。
把爬虫脚本变成自己的数据前线
文中所附的六个 mq5 与一个 mq4 脚本,核心思路都能直接抄进 EA:用 WebRequest 按 URL 拉取页面,再用字符串函数切出债券收益率。债券波动率远低于汇率,实测每五分钟刷一次已属上限,没必要对着货币对每个分时发请求,否则既拖慢 MT5 也容易被站点限流。 这套从网络取数的方法不绑死某一个财经站,也不限 EURUSD 这类示例品种;哪天对方改了页面结构,报错信息本身就指了路,懂一点 MQL5 字符串处理就能换选择器重修。注意抓取的内容往往不在公共域,别二次分发,只留作本地策略输入。 外汇与贵金属本身高杠杆、高风险,自动收集基础数据只是给了 EA 一个参考维度,能否让系统盈利仍取决于你的风控与执行逻辑。脚本跑通后,先拿 ScraperBot01 在策略测试器外手动跑一遍,确认能落本地文件再谈接入。