三角套利(基础篇)
「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 嵌三次,并挂上三角级属性(当前利润、魔幻数字、开单时间)。外汇与贵金属三角套利杠杆高、滑点敏感,实盘前务必在策略测试器用多品种模式跑一遍。
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。
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 手模拟。
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">// 注释