三角套利(基础篇)
📘

三角套利(基础篇)

第 1/3 篇

「MT5 三角套利的基础盘面」

三角套利指在同一交易终端内,利用三种货币对之间的交叉汇率偏差来对冲获利,MetaTrader 5 因其多品种同台报价成为常见验证环境。该思路在 2017 年 12 月初被一位作者以公开帖形式放出,原帖浏览量达到 23156、评论 139 条,说明这类多腿对冲玩法在外汇圈始终有高频关注。 外汇与贵金属属高杠杆品种,三角套利虽不依赖单边方向,但点差滑点可能吞掉微薄价差,实操前务必在 MT5 策略测试器用真实点差回测。 打开 MT5 市场报价窗口同时拉出 EURUSD、GBPUSD、EURGBP 三组tick,若手动算出的交叉价与终端显示偏差持续大于经纪商双边点差,才存在可触发空间。

◍ 三角套利的中立性与实现路径

论坛上常聊的“可靠规律三角套利”,核心在“套利”二字代表行情中立,“三角”指组合由三个金融工具构成。最典型的就是 EURUSD + GBPUSD + EURGBP,靠同时买卖相同敞口赚偏差的钱。 这三个货币对可互相表示:EURUSD=GBPUSD*EURGBP,或 GBPUSD=EURUSD/EURGBP,或 EURGBP=EURUSD/GBPUSD。变体等价,先盯第一个。 买入 EURUSD 用竞卖价,余额增 EUR 减 USD;为对冲需买 GBPUSD(竞卖价)增 GBP 减 USD,再买 EURGBP(竞卖价)增 EUR 减 GBP。合计得到:(竞买价)EURUSD = (竞买价)GBPUSD * (竞买价)EURGBP。 盈利条件只有两种:竞卖价 EURUSD < 竞买价 GBPUSD * 竞买价 EURGBP(便宜买),或竞买价 EURUSD > 竞卖价 GBPUSD * 竞卖价 EURGBP(高价卖)。检测到了就动手。 能即时两边对冲盈利的窗口极少。更常出现的是单边便宜买入却无法同时抛出盈利,这时持仓互抵近乎为零、游离市外,但“近乎”要警惕——手数只舍入到小数点后两位,对策略精度太粗糙。外汇与贵金属杠杆高,微小敞口也可能在极端点差下放大风险。 理论清完,EA 用面向过程风格写,新手和不喜 OOP 的人也能接住。

三角状态机与日志落盘

EA 启动后会枚举所有可组合的三角套利路径,把每条路径的报价与下单所需字段塞进 MxThree 结构数组。数组里每个三角都带一个 status 字段,初始为 0,相当于待命。 需要触发开单时 status 置 1;确认三边全部成交后翻到 2;若只成交了部分边或平仓计时已到,则落到 3;完整平仓成功再回 0。靠这套枚举值,EA 在回测和实盘里都不会把同一个三角重复点火。 所有开平动作都会写进名为 Three Point Arbitrage Control YYYY.DD.MM.csv 的日志,年份日期格式是四位年.两位日.两位月。你可以拿它逐行比对成交时间戳,验证策略有没有在错误时点漏单或重复平单。 测试前要把涉及到的货币对手动加进策略测试器。做法是先以“创建品种文件”模式跑一次 EA 生成列表;若目录下没有该文件,EA 会退化到默认的 EUR+GBP+USD 三角做测试,这时候其它交叉盘不会被覆盖到。

「三角套利机器人的变量与结构骨架」

写 MT5 多币种套利 EA 时,头文件层层 include 是基本盘。除标准库外,每个自写包含文件都以 head.mqh 起头,这样 IntelliSense 才能跨文件补全实体名,不必死记所有函数与类名。 测试器要跑多品种,必须在全局区用 #property tester_file 声明落地文件,否则策略测试器加载不到符号列表。这一步放错位置会直接编译报错。 变量定义集中放在 var.mqh,其中两个输入参数值得先看:inMaxThree 控制同时持仓的三角数量,设为 2 就意味着最多两组三角同开,0 表示不限制;inProfit 存佣金值,用来修正净利差。 三角由三个货币对拼成,所以先写 stSmb 描述单品种规格——交易量上限、_Digits、_Point、实时开单价等,再写 stThree 把 stSmb 嵌三次,并挂上三角级属性(当前利润、魔幻数字、开单时间)。外汇与贵金属三角套利杠杆高、滑点敏感,实盘前务必在策略测试器用多品种模式跑一遍。

MQL5 / C++
class="macro">#include <Trade\Trade.mqh>
class="macro">#include <Trade\SymbolInfo.mqh>  
class="macro">#include <Trade\TerminalInfo.mqh>

class="macro">#include "var.mqh"
class="macro">#include "fnWarning.mqh"
class="macro">#include "fnSetThree.mqh"
class="macro">#include "fnSmbCheck.mqh"
class="macro">#include "fnChangeThree.mqh"
class="macro">#include "fnSmbLoad.mqh"
class="macro">#include "fnCalcDelta.mqh"
class="macro">#include "fnMagicGet.mqh"
class="macro">#include "fnOpenCheck.mqh"
class="macro">#include "fnCalcPL.mqh"
class="macro">#include "fnCreateFileSymbols.mqh"
class="macro">#include "fnControlFile.mqh"
class="macro">#include "fnCloseThree.mqh"
class="macro">#include "fnCloseCheck.mqh"
class="macro">#include "fnCmnt.mqh"
class="macro">#include "fnRestart.mqh"
class="macro">#include "fnOpen.mqh"
class="macro">#class="kw">property tester_file FILENAME
class=class="str">"cmt">// 宏定义
class="macro">#define DEVIATION          class="num">3                                                          class=class="str">"cmt">// 最大可能的滑点
class="macro">#define FILENAME           "Three Point Arbitrage.csv"                                class=class="str">"cmt">// 操作品种存储在这里
class="macro">#define FILELOG            "Three Point Arbitrage Control "                             class=class="str">"cmt">// 日志文件名称部分
class="macro">#define FILEOPENWRITE(nm)  FileOpen(nm,FILE_UNICODE|FILE_WRITE|FILE_SHARE_READ|FILE_CSV)  class=class="str">"cmt">// 打开文件写入
class="macro">#define FILEOPENREAD(nm)   FileOpen(nm,FILE_UNICODE|FILE_READ|FILE_SHARE_READ|FILE_CSV)   class=class="str">"cmt">// 打开文件读取
class="macro">#define CF                 class="num">1.2                                                          class=class="str">"cmt">// 提高保证金比例
class="macro">#define MAGIC              class="num">200                                                          class=class="str">"cmt">// 应用的魔幻数字范围
class="macro">#define MAXTIMEWAIT        class="num">3                                                            class=class="str">"cmt">// 三角开单后的最长等待时间, 以秒为单位
class=class="str">"cmt">// 货币对结构
class="kw">struct stSmb
  {
    class="type">class="kw">string            name;            class=class="str">"cmt">// 货币对

◍ 三角套利里的结构体字段怎么排

做跨品种三角套利时,先把每个货币对的状态塞进一个结构体,比在全局变量里散着写要干净得多。下面这段定义把报价精度、手数限制、保证金、点差成本都绑在 stSmb 里,对冲账户还能顺手存订单票号 tkt。 stSmb 的构造函数 stSmb(){price=0;tkt=0;mrg=0;} 把净持仓价格、票号和保证金清零,避免上一次循环残留值污染新报价。Rpoint 存的是 1/point 而不是 point 本身,后面算价格偏差时直接乘,少一次除法调用。 三角整体用 stThree 包三层 stSmb,外加 lot_min、lot_max 约束整组手数,magic 区分不同策略实例,status 用 0~3 标记生命周期:0 空闲、1 已发开单、2 开单成交、3 已发平单。你在 MT5 里接 SymbolInfoInteger 填 digits 和 digits_lot,再用 SymbolInfoDouble 抓 lot_min / lot_step,就能直接套这个骨架跑回测。 外汇与贵金属三角套利杠杆高、滑点可能吞掉理论利润,实盘前务必用历史 tick 验证 status 状态机不会卡在 1 或 3。

MQL5 / C++
class="type">int               digits;             class=class="str">"cmt">// 报价中的小数位数
class="type">uchar             digits_lot;         class=class="str">"cmt">// 手数的四舍五入小数位数
class="type">int               Rpoint;             class=class="str">"cmt">// class="num">1/point, 以便在方程中乘以 (而不是除以) 该值
class="type">class="kw">double            dev;                class=class="str">"cmt">// 可能的滑点。一次性转换成点数
class="type">class="kw">double            lot;                class=class="str">"cmt">// 货币对的交易量
class="type">class="kw">double            lot_min;            class=class="str">"cmt">// 最小交易量
class="type">class="kw">double            lot_max;            class=class="str">"cmt">// 最大交易量
class="type">class="kw">double            lot_step;           class=class="str">"cmt">// 手数增量
class="type">class="kw">double            contract;           class=class="str">"cmt">// 合约大小
class="type">class="kw">double            price;              class=class="str">"cmt">// 在三角中的货币对开单价。净持模式需要
class="type">class="kw">ulong             tkt;                class=class="str">"cmt">// 交易开单所用的订单票号。对冲账户所需
class="type">MqlTick           tick;               class=class="str">"cmt">// 当前货币对价格
class="type">class="kw">double            tv;                 class=class="str">"cmt">// 当前分笔报价
class="type">class="kw">double            mrg;                class=class="str">"cmt">// 当前用于开单的保证金
class="type">class="kw">double            sppoint;            class=class="str">"cmt">// 点差, 单位为点数的整数值
class="type">class="kw">double            spcost;             class=class="str">"cmt">// 当前开单的每手点差, 以资金为单位
stSmb(){price=class="num">0;tkt=class="num">0;mrg=class="num">0;}  
 };
class=class="str">"cmt">// 三角结构
class="kw">struct stThree
  {
    stSmb             smb1;
    stSmb             smb2;
    stSmb             smb3;
    class="type">class="kw">double            lot_min;          class=class="str">"cmt">// 整个三角的最小交易量
    class="type">class="kw">double            lot_max;          class=class="str">"cmt">// 整个三角的最大交易量
    class="type">class="kw">ulong             magic;            class=class="str">"cmt">// 三角的魔幻数字
    class="type">uchar             status;           class=class="str">"cmt">// 三角状态。class="num">0 - 未使用。class="num">1 - 发送开单。class="num">2 - 成功开单。class="num">3 - 发送平单

三角套利 EA 的结构化字段与模式枚举

三角套利 EA 的核心数据用结构体 stThree 承载,每个三角记录盈利、开单时间、买卖双向潜在利润以及三点差总成本(含佣金)。初始化时 status 与 magic 置 0,意味着新三角默认未激活、未绑定订单标识。 操作模式由枚举 enMode 控制:0 为市场观察窗口内的标准品种,1 为读取外部品种文件,2 为给测试器或实盘生成品种文件。注释里被划掉的 3 和 4 本是“只平不开”的退出模式,当前版本未启用。 全局数组 MxThree 存放所有运行中三角及附加数据,CTrade、CSymbolInfo、CTerminalInfo 三个标准库类分别管下单、品种属性和终端信息。glAccountsType 区分对冲与净持仓账户,glFileLog 持有日志句柄。 输入参数里 inProfit 默认 0 表示未计入佣金,inLot 默认 1 手,inMagic 默认 300 用作订单过滤,inCmnt 默认 "R " 方便在成交注释里辨认。把 inMaxThree 改成非零值,EA 才会限制同时持有的三角数量,否则可能无上限开三角——外汇与贵金属三角套利点差跳变频繁,属高风险策略,建议在 MT5 策略测试器先跑 0 手模拟。

MQL5 / C++
  class="type">class="kw">double             pl;                class=class="str">"cmt">// 三角盈利
  class="type">class="kw">datetime            timeopen;          class=class="str">"cmt">// 发送三角开单的时间
  class="type">class="kw">double              PLBuy;             class=class="str">"cmt">// 买入三角时的潜在利润
  class="type">class="kw">double              PLSell;            class=class="str">"cmt">// 抛售三角时的潜在利润
  class="type">class="kw">double              spread;            class=class="str">"cmt">// 所有三个点差的总价 (含佣金!)
   stThree(){status=class="num">0;magic=class="num">0;}
  };

class=class="str">"cmt">// EA 操作模式
enum enMode
  {
    STANDART_MODE   =  class="num">0, class=class="str">"cmt">/*Symbols from Market Watch*/                  class=class="str">"cmt">// 标准操作模式。市场观察品种
    USE_FILE        =  class="num">1, class=class="str">"cmt">/*Symbols from file*/                          class=class="str">"cmt">// 使用品种文件
    CREATE_FILE     =  class="num">2, class=class="str">"cmt">/*Create file with symbols*/                   class=class="str">"cmt">// 为测试器或操作创建文件
    class=class="str">"cmt">//END_ADN_CLOSE   =  class="num">3, class=class="str">"cmt">/*Not open, wait profit, close & exit*/       // 您的所有交易平单并结束操作
    class=class="str">"cmt">//CLOSE_ONLY      =  class="num">4  class=class="str">"cmt">/*Not open, not wait profit, close & exit*/
  };
stThree   MxThree[];                 class=class="str">"cmt">// 主数组存储正在操作的三角和所有必要的附加数据
CTrade       ctrade;                class=class="str">"cmt">// 标准库的 CTrade 类
CSymbolInfo  csmb;                  class=class="str">"cmt">// 标准库的 CSymbolInfo 类
CTerminalInfo  cterm;               class=class="str">"cmt">// 标准库的 CTerminalInfo 类
class="type">int     glAccountsType=class="num">0; class=class="str">"cmt">// 账户类型: 对冲或净持
class="type">int     glFileLog=class="num">0;      class=class="str">"cmt">// 日志文件句柄
class=class="str">"cmt">// 输入
sinput    enMode     inMode=     class="num">0;          class=class="str">"cmt">// 操作模式
class="kw">input     class="type">class="kw">double     inProfit=  class="num">0;          class=class="str">"cmt">// 佣金
class="kw">input     class="type">class="kw">double     inLot=      class="num">1;          class=class="str">"cmt">// 交易量
class="kw">input     class="type">class="kw">ushort     inMaxThree= class="num">0;          class=class="str">"cmt">// 三角已开单
sinput    class="type">class="kw">ulong      inMagic=    class="num">300;        class=class="str">"cmt">// EA 魔幻数字
sinput    class="type">class="kw">string     inCmnt=     "R ";       class=class="str">"cmt">// 注释

常见问题

找两两交叉能拼回基础币的环,例如 EUR/USD、USD/JPY、EUR/JPY 三者报价互乘应近似为1,偏差超点差才值得盯。
同时吃三边成交,组合头寸净敞口近似零,不赌单边;但滑点和单边未成交会让中性破功,属高风险操作。
可以,小布能按你选的三个货币对实时算环差,偏离阈值就弹提醒,不用你自己盯盘算乘积。
至少落盘时间、三边价、理论环差、实际成交价与滑点,用结构体存比散变量好查。
常见为闲置、询价、发单、对账、撤单五态,用枚举切换避免重复发单和鬼畜撤单。