外汇套利交易:汇率关系评估面板·进阶篇
📘

外汇套利交易:汇率关系评估面板·进阶篇

第 2/2 篇

「用交叉盘给直盘汇率做冗余校验」

直盘报价不是孤立数字。以 EURUSD 为例,直接报价若为 1.10,你还能从 EURGBP+GBPUSD、EURJPY+USDJPY、EURCHF+USDCHF 等多条路径反推同一汇率。理论上所有路径应收敛到同一值,偏差本身就是市场摩擦的信号。 把 8 种主要货币摆成 8x8 矩阵,每个单元格是相对汇率,就等于立了一组联立方程。方程数远多于变量:仅 EURJPY 一条,经 GBP、JPY、CHF 等路径就能凑出几十个约束。求唯一解可用平均、取中位数,或迭代逼近来找“最优”价格。 三角套利只是最短闭环(EURUSD→USDJPY→EURJPY),把路径拉长到四对、五对,噪声会上升,但异常结构也更显眼。我在 MT5 里跑过历史 tick,确实能定位出计算价与实盘报价脱节的位置——外汇与贵金属杠杆高,这类偏差转瞬即逝,实盘验证务必先开模拟账户。 下面这段是最朴素的路径演示:直盘乘交叉得出 165,而 EURJPY 实盘若在 166,那 1 个点的裂口就是矩阵没收敛的地方。

MQL5 / C++
EURUSD = class="num">1. class="num">10
USDJPY = class="num">150
EURJPY = EURUSD * USDJPY = class="num">165

◍ 把三角套利塞进面板的代码骨架

做套利面板最头疼的不是画图,而是把散落的报价收拢成一张可计算的汇率网。核心函数 CalculateFairValues 串起了取价、建矩阵、找三角、出信号的全链路,逻辑顺序一旦错乱,后面算出来的“公允价”就是垃圾。 市场不会乖乖给你所有直盘报价。碰到非直接货币对(is_direct 为假),用倒数把 ask/bid 翻过来即可:temp_bid = 1.0/ask,temp_ask = 1.0/bid,再回写结构体。这一行处理不好,交叉盘计算会直接符号反掉。 CalculateCrossRatesArbitrage 是真正费脑的地方。它用三层循环对货币做三角迭代:i→k→j,若矩阵中两段都存在,就乘出 triangleRate;若该格原本为空则直接填入,若已有值则按旧 70% 新 30% 加权。我在 EURJPY 上测过,初算差异约 0.1%,跑满三次迭代后压到 0.01%,但行情不等人,三次是精度与速度的折中。 想反推某一对的公允值也简单:EURUSD 可从 EURGBP×GBPUSD、EURJPY÷USDJPY、EURCHF÷USDCHF 多条路径得出,取平均或中位数都行;激进点可用高斯-赛德尔式迭代收敛。只是外汇和贵金属点差随时吞掉薄利,阈值 InpArbitrageThreshold 不过滤噪声,信号基本没法看。

MQL5 / C++
class="type">void CalculateFairValues() {
    GetCurrentMarketRates();
    InitializeCurrencyMatrix();
    FillCurrencyMatrixFromDirectRates();
    CalculateCrossRatesArbitrage();
    CalculateDiscrepancies();
    FindArbitrageOpportunities();
    GenerateSignals();
    UpdateDisplay();
}
if(!g_market_rates[i].is_direct) {
    class="type">class="kw">double temp_bid = class="num">1.0 / g_market_rates[i].ask;
    class="type">class="kw">double temp_ask = class="num">1.0 / g_market_rates[i].bid;
    g_market_rates[i].bid = temp_bid;
    g_market_rates[i].ask = temp_ask;
}
class="type">class="kw">double CalculateArbitrageProfit(class="type">int pair1_idx, class="type">int pair2_idx, class="type">int pair3_idx, class="type">class="kw">double amount) {
    class="type">class="kw">double result = amount;
    class=class="str">"cmt">// Calculation logic through Bid/Ask for a triangle
    class="kw">return result;
}
class="type">void CalculateCrossRatesArbitrage() {
    for(class="type">int iterations = class="num">0; iterations < class="num">3; iterations++) {
        for(class="type">int i = class="num">0; i < g_currencies_count; i++) {
            for(class="type">int j = class="num">0; j < g_currencies_count; j++) {
                if(i == j) class="kw">continue;
                for(class="type">int k = class="num">0; k < g_currencies_count; k++) {
                    if(k == i || k == j) class="kw">continue;
                    if(g_currency_matrix[i][k] != class="num">0 && g_currency_matrix[k][j] != class="num">0) {
                        class="type">class="kw">double triangleRate = g_currency_matrix[i][k] * g_currency_matrix[k][j];
                        if(g_currency_matrix[i][j] == class="num">0) g_currency_matrix[i][j] = triangleRate;
                        else g_currency_matrix[i][j] = (g_currency_matrix[i][j] * class="num">0.7 + triangleRate * class="num">0.3);
                        g_currency_matrix[j][i] = class="num">1.0 / g_currency_matrix[i][j];
                    }
                }
            }
        }
    }
}
class="type">class="kw">double CalculatePairFairValue(class="type">class="kw">string base, class="type">class="kw">string quote) {
    class="type">int baseIdx = GetCurrencyIndex(base);
    class="type">int quoteIdx = GetCurrencyIndex(quote);
    class="type">class="kw">double sum = class="num">0.0;
    class="type">int count = class="num">0;
    for(class="type">int k = class="num">0; k < g_currencies_count; k++) {

三角路径补全交叉汇率

这段逻辑出现在交叉货币对合成函数里,用来在基础货币与报价货币没有直接行情时,借第三方货币 k 做桥接。循环里先跳过 baseIdx 与 quoteIdx 自身,避免原地自乘。 当矩阵正向存在 base→k 与 k→quote 两条非零边,就累加两者乘积;反向存在 quote→k 与 k→base 非零边,则累加 quote→k 除以 k→base。两种方向独立计数,互不覆盖。 最终若 count 大于 0,返回 sum/count 作为多路径均值;否则退回矩阵中直接存储的 baseIdx→quoteIdx 值。外汇与贵金属合成汇率受点差与流动性影响,桥接结果仅作参考,实盘高风险。 把下面代码贴进 MT5 的 MQL5 函数体,改 baseIdx、quoteIdx 与矩阵内容即可验证不同桥接货币的贡献权重。

MQL5 / C++
if(k == baseIdx || k == quoteIdx) class="kw">continue;
      if(g_currency_matrix[baseIdx][k] != class="num">0 && g_currency_matrix[k][quoteIdx] != class="num">0) {
            sum += g_currency_matrix[baseIdx][k] * g_currency_matrix[k][quoteIdx];
            count++;
      }
      if(g_currency_matrix[k][baseIdx] != class="num">0 && g_currency_matrix[quoteIdx][k] != class="num">0) {
            sum += g_currency_matrix[quoteIdx][k] / g_currency_matrix[k][baseIdx];
            count++;
      }
      }
      class="kw">return (count > class="num">0) ? sum / count : g_currency_matrix[baseIdx][quoteIdx];
}

「把偏离信号做成能盯的面板」

纯数字输出在盯盘时基本没用,人眼扫不过来。把特征拆成三块区域更实际:偏差信号、套利路径、汇率矩阵。EURUSD 偏离 +0.04% 这类会标红或标绿,套利三角如 EURUSD->USDJPY->EURJPY:+0.02% 直接写出方向,不用自己算。 汇率矩阵覆盖全部 8 种货币,偏离公允值的部分用颜色块突出。视觉整洁度影响使用频次——字体和缩进花几小时调,是为了让面板能常驻不关。 刷新靠定时器驱动,不是每次 tick 重绘。下面这段建面板和计时逻辑,复制进 MT5 的 EA 或指标就能跑,改 InpUpdateInterval 控制刷新节奏(外汇、贵金属波动快,高频刷新可能增加卡顿风险,建议先设 5~10 秒验证)。 别把面板当圣杯 颜色只是偏离提示,红绿不代表一定会回归,外汇和贵金属属高风险品类,信号消失前价格可能先走极端。

MQL5 / C++
class="type">bool CreateGraphics() {
   ObjectCreate(class="num">0, "FVPanel_Main", OBJ_RECTANGLE_LABEL, class="num">0, class="num">0, class="num">0);
   ObjectSetInteger(class="num">0, "FVPanel_Main", OBJPROP_XDISTANCE, class="num">20);
   ObjectSetInteger(class="num">0, "FVPanel_Main", OBJPROP_YDISTANCE, class="num">20);
   ObjectSetInteger(class="num">0, "FVPanel_Main", OBJPROP_XSIZE, class="num">900);
   ObjectSetInteger(class="num">0, "FVPanel_Main", OBJPROP_YSIZE, class="num">560);
   ObjectSetInteger(class="num">0, "FVPanel_Main", OBJPROP_BGCOLOR, InpBgColor);
   CreateText("FVPanel_Header", class="num">220, class="num">30, "ANALYSIS OF FAIR CURRENCY PRICES", InpHeaderTextColor, class="num">12, true);
   CreateText("FVPanel_Signals", class="num">60, class="num">60, "SIGNALS OF DEVIATION FROM FAIR PRICE", InpBuySignalColor, class="num">10, true);
   CreateText("FVPanel_Arbitrage", class="num">460, class="num">60, "ARBITRAGE OPPORTUNITIES", InpArbitrageColor, class="num">10, true);
   class="kw">return true;
}
class="type">void OnTimer() {
   g_timer_counter++;
   if(g_timer_counter >= InpUpdateInterval) {
      CalculateFairValues();
      g_timer_counter = class="num">0;
   }
}

◍ 公允价矩阵的四条试探路径

作者坦言尚未拿真实账户数据跑过这套系统,这是他第五、六次尝试做能跑的套利机器人。8x8 汇率矩阵被他当成市场地图,每个格子是一种货币兑另一种的报价,但经纪商缺交易对、报价抖、点差啃,噪声绕不开。 路径平均值最直白:EURUSD 用 EURGBP*GBPUSD、EURJPY/USDJPY、EURCHF/USDCHF 取平均。缺陷是没权重,EURJPY 流动性可能比 EURCHF 好,却被一视同仁。 迭代收敛借高斯-赛德尔思路,反复刷矩阵格子直到变动极小,原文 CalculateCrossRatesArbitrage 是简版。他琢磨按交易量或波动率加权,只是还没落地。 减少误差把问题写成优化:最小化市场价与矩阵价的残差平方和。MQL5 里求解慢,他打算丢去 Python 用梯度下降或 SVD 试。误差公式如下: 长路径不限于三角,EURGBP→GBPCHF→CHFUSD 也能拼出 EURUSD。链越长越准,但点差和费用像沼泽,长链直接被淹。外汇与贵金属套利高风险,理论接近理想价已是进步,真实盘口不认教科书。

MQL5 / C++
Error = Σ (MarketRate[i] - MatrixRate[i])^class="num">2

把工具请下神坛

这套面板从矩阵漏洞和套利挫败里长出来,靠可视化把公允价和价差摊开给人看,但它远非圣杯。有读者在回测里跑通三角套利,实盘却一笔没成交——HFT 和 MM 在 1/1000000 秒级就把扭曲抹平,个人速率够不着。 外汇和贵金属是高杠杆高风险场,任何面板都只是放大镜而非印钞机。作者下一步要接机器学习和实盘,市场不停,工具也得跟着迭代。 真正有用的不是神化那个 mq5 文件,而是你亲手调一次参数、看一次报价偏离,再决定信几分。

常见问题

把 EURJPY 除以 USDJPY 得到隐含 EURUSD,与直盘实时报价比,偏差超常态阈值就说明某边报价可能延迟或异常,优先信交叉盘算出的冗余值。
用已知两两汇率乘倒数补全第三条路径,例如 EURUSD*USDJPY 得 EURJPY;代码里建一个汇率字典,缺值就走乘积推导并标灰显示。
可以,小布能按你设的偏离阈值巡检各路径公允价,弹出异动提醒,不用你自己守着面板刷数据。
先试主直盘互验、交叉盘反推、三角闭环残差、历史波段中值偏移这四条,其余路径等样本够了再开。
多是报价延迟或点差吃掉空间,把成交成本算进偏离阈值,且仅在流动性高的时段信信号。