English Русский Español Português
preview
外汇套利交易:一款轻松上手的简单合成做市商机器人

外汇套利交易:一款轻松上手的简单合成做市商机器人

MetaTrader 5交易系统 |
64 17
Yevgeniy Koshtenko
Yevgeniy Koshtenko

引言:从散户交易者到具备机构思维

经常有人问我,我是如何开发出TrisWeb_Optimized的。故事要从2016年说起,那时我初次踏入外汇世界,带着新手的天真和对指标交易的笃信。当时,我仍坚信交易存在“圣杯”——一种据说能将1000美元在一年内变成百万美元的神奇指标组合。

2017年,我的思维发生了革命性的转变。在一系列惨痛的亏损之后,我开始研究大机构实际的交易方式。我所说的并非那些在YouTube上大谈“百万美元收益”的人,而是真正的机构——银行、对冲基金和自营交易公司。

我发现:他们并不使用那些花哨的指标策略。他们运用数学原理、风险管理、套利、做市以及其他基于对市场机制深刻理解的方法。就在那时,我做出了决定:要么像大机构一样交易,要么干脆不交易。

接下来的三年时间里,我潜心研究机构交易方法。我沉浸在跨市场相关性、统计套利和算法交易的世界中。我尝试使用Python和MQL,创建了一些原型系统,这些系统模仿了大型市场参与者的方法,但针对散户交易者在资金和技术方面的限制进行了调整。

2020年1月,在金融市场历史上最为动荡的时期之一来临前夕,Tris_Optimized诞生了——这是我对“散户交易者如何应用机构策略”这一问题的回答。

这款EA并不试图预测市场走势,不依赖技术分析指标,也不需要“直觉”。相反,它通过数学计算,找出三种相关货币对之间潜在的失衡情况,并布置一系列订单,准备在失衡出现时捕捉机会。

在真实市场条件下连续运行五年多,Tris_Optimized已证明其可行性。它经历了疫情、通胀飙升、利率变动和地缘政治危机——并持续产生稳定的利润(在我真正操作交易而非通宵钻研代码构思和实际代码的少数时候)。这并非一个承诺超高回报的神奇系统,而是一款基于机构交易基本原则的既可靠又实用的工具。

如今,这种基于机构思维的交易理念,让我得以在各类市场中成功交易。近年来,我虽专注于机器学习策略,但套利方法始终是我交易策略库中的重要组成部分。将机器学习的统计方法与机构交易者所利用的基本市场模式相结合,让我获得了显著优势。我甚至受邀加入了一家鲜为人知的小型对冲基金。除了我,基金里只有一名风险经理和一名管理员,而我们正准备推出基于MetaTrader 5的对冲基金基础设施

几周前,我在整理云存储时,偶然发现了一个存放着我旧交易机器人的存档。其中就包括Triss_Optimized,这是我的首批项目之一。尽管与现代机器学习系统相比,它显得“简单”,但仍在运行并产生收益。我在一个模拟账户上运行它,结果令人惊讶——即使没有针对当前市场条件进行优化,它也展示出了积极的结果。

于是,我决定将这段代码分享到社区。并非因为它是什么革命性的系统,能让您在一个月内成为百万富翁,而是因为这段代码是一个很好的范例,展示了作为散户交易者,如何将机构交易方法应用于交易之中。它就像一座桥梁,连接着两个世界,能帮助您完成我曾经经历过的转变。

在本文中,我将揭示TrisWeb_Optimized的运作机制,解释其架构,并分享我在设置和优化方面的经验。准备好进入专业算法交易的世界了吗?让我们开始吧。


外汇三币套利:EURUSD-GBPUSD-EURJPY三角套利

我们先从外汇三角套利说起,这简直就像一场捉鬼游戏。想象一下这样的场景:您同时监控着欧元兑美元(EURUSD)、英镑兑美元(GBPUSD)和欧元兑日元(EURJPY),试图捕捉价格短暂失衡的瞬间——即当EUR→USD→GBP→EUR的闭环交易能让您至少净赚几个点时。但事实是,纯粹的套利机会就像莫斯科市中心的独角兽一样罕见。机构凭借其高频算法和直接获取流动性的渠道,眨眼间就能将这些机会一扫而空。

正因如此,我开发了TrisWeb_Optimized——这款EA并不坐等理想条件出现,而是构建一个三维订单网络,随时准备捕捉自然市场波动带来的利润。从学术意义上讲,这并非经典的套利策略——而是一种散户交易者的游击战术,利用三种货币对之间的数学关系进行套利。


MQL5中的合成货币对:通往套利的秘密之门

什么是合成货币对?它是一种幻影,一种我们通过实际交易工具构建的数学抽象。例如,根据EURUSD和GBPUSD的报价,我们可以计算出一个合成EURGBP,理论上,这个合成汇率应与实际的EURGBP完全一致。但在现实世界中,始终存在偏差,这正是我们的“日常经历”。

TrisWeb_Optimized并未显式创建合成货币对,而是巧妙地利用了它们背后的逻辑。我们通过以下代码段获取各货币对的当前价格——这是捕捉失衡情况的第一步:

// Get the current prices for each symbol
double priceSymbol1 = GetCurrentPrice(Symbol1);
double priceSymbol2 = GetCurrentPrice(Symbol2);
double priceSymbol3 = GetCurrentPrice(Symbol3);

这三行代码是踏入多维可能空间的入口,在那里,哪怕最细微的差异都能转化为实实在在的资金。


TrisWeb_Optimized架构:历经疫情考验的交易工具

2020年1月,当我写下TrisWeb_Optimized的第一行代码时,世界正站在疫情爆发、市场动荡和极端波动的边缘。没人能预料到,这个简单的EA竟会在几十年来最极端的市场环境中接受严峻考验。您知道结果如何吗?它居然挺过来了。不仅如此,还蓬勃发展。

系统的核心在于OnTick()函数——每当价格变动时,该函数就会被触发,同时从三个维度分析整体市场情况:

void OnTick()
{
   // Calculate orders and profits
   int ordersCount1 = 0, ordersCount2 = 0, ordersCount3 = 0;
   double profit1 = 0, profit2 = 0, profit3 = 0;
   
   // Count pending orders
   CountPendingOrders(ordersCount1, ordersCount2, ordersCount3);
   
   // Calculate open positions and their profit
   CountOpenPositions(ordersCount1, ordersCount2, ordersCount3, profit1, profit2, profit3);
   
   // ... rest of the code
}

这段代码看似平平无奇。然而,在这些代码行的背后,隐藏着一个精炼的模块化架构——系统的每个方面都被隔离成独立的功能,就像一个协调良好的有机体中的各个器官一样。没有混乱,没有无序——只有明确的职责划分。


网格参数调整:与波动性共舞

外汇市场就像一片海洋——EURUSD的走势缓慢而庄严,犹如深层的洋流;而EURJPY则可能如突如其来的海啸般剧烈波动。试图用相同的参数交易这些货币对,注定会令人失望。正因如此,TrisWeb_Optimized允许为每个交易工具自定义网格参数:

input group "Step Settings"
input int Step01_Symbol1 = 40;      // Initial step for Symbol1 (in points)
input int Step02_Symbol1 = 60;      // Step between orders for Symbol1 (in points)
input int Step01_Symbol2 = 40;      // Initial step for Symbol2 (in points)
input int Step02_Symbol2 = 60;      // Step between orders for Symbol2 (in points)
input int Step01_Symbol3 = 40;      // Initial step for Symbol3 (in points)
input int Step02_Symbol3 = 60;      // Step between orders for Symbol3 (in points)

在运用这套系统的五年时间里,我形成了一套独特的操作习惯:对于像EURUSD这样走势平稳的货币对,我采用40点和60点的标准步长;而对于波动剧烈的日元交叉盘,我会将步长增至50点和80点。这就好比根据不同鱼种调整鱼竿的灵敏度——用同样的方法,要么什么都能钓到,要么一无所获。


手数规模优化:自适应系统的核心基因

固定手数是新手才会采用的方式。资深专业人士深知:交易量必须随账户余额的变化而灵活调整。借助CalculateOptimalLotSize()函数,TrisWeb_Optimized实现了这一功能,这堪称我的得意之作:

double CalculateOptimalLotSize(string symbol, double baseSize)
{
   if(!AutoLotOptimization)
      return baseSize;
      
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   // ... the rest of the calculation code
}
该功能堪称真正的瑞士军刀。它会综合考量当前账户余额、设定的风险百分比、特定交易品种的点值、经纪商对最小手数和手数增量的限制,而且——这也是我尤为自豪之处——还能针对小众货币自动调整计算方式:
// Adjustment for pairs with JPY and other exotic currencies
string quoteCurrency = StringSubstr(symbol, 3, 3);
if(quoteCurrency == "JPY" || quoteCurrency == "XAU" || quoteCurrency == "XAG")
   pointCost *= 100.0;

对于刚入行的交易者来说,日元货币对的点值是主要货币对的百分之一。如果忽略这一调整,您的交易机器人要么会以极微小的手数进行交易,要么会在一场交易中让您血本无归。


EA运行时间管理:昼夜节律算法

外汇市场全天候24小时运作,但这并不意味着您的EA也应该如此。有些时候,最好还是按兵不动——比如夜间交易时段,其点差较大且走势异常,往往带来的问题多于机会。TrisWeb_Optimized通过IsWorkTime()函数内置了“昼夜节律”机制:

bool IsWorkTime()
{
   MqlDateTime currentTime;
   TimeToStruct(TimeLocal(), currentTime);
   
   datetime currentTimeSeconds = HoursMinutesToSeconds(currentTime.hour, currentTime.min);
   datetime startTimeSeconds = HoursMinutesToSeconds(StartTimeHour, StartTimeMin);
   datetime endTimeSeconds = HoursMinutesToSeconds(EndTimeHour, EndTimeMin);
   
   return (startTimeSeconds <= currentTimeSeconds && currentTimeSeconds <= endTimeSeconds);
}
CheckNewDayAndWorkTime()函数为这款EA赋予了另一项类似人类的特质——即具备“每日重新开始、从零做起”的能力:
void CheckNewDayAndWorkTime()
{
   if(IsNewDay && IsNewDayReset && IsWorkTime())
   {
      DeleteAllOrders();
      IsNewDay = false;
   }
   
   if(!IsWorkTime())
   {
      IsNewDay = true;
   }
}

从长远来看,这一特性尤为宝贵——系统不会累积积压的过期订单,而是会根据当前市场状况持续更新交易网格。


平仓算法:及时离场的艺术

在交易中,正如在生活中一样,重要的不仅是在恰当的时机入场,更要在恰当的时机离场。TrisWeb_Optimized采用了一个简单而高效的平仓标准——达到既定的总盈利水平:

// Total number of orders
int totalOrders = ordersCount1 + ordersCount2 + ordersCount3;
double totalProfit = profit1 + profit2 + profit3;

// If there are no orders, create them; if there are, check for profit.
if(totalOrders == 0)
{
   if(IsWorkTime())
   {
      PlaceInitialOrders();
   }
}
else if(totalProfit > Profit)
{
   DeleteAllOrders();
}
但正如人们常说——细节决定成败。该系统不仅考量“纯”利润,还会综合计算包含隔夜利息和交易佣金在内的总收益:
double swap = PositionGetDouble(POSITION_SWAP);
double profit = PositionGetDouble(POSITION_PROFIT);
double commission = PositionGetDouble(POSITION_COMMISSION);
double totalProfitForPosition = profit + swap + commission;

这对于长期交易表现而言至关重要,尤其是当您持有头寸过夜并产生隔夜利息费用时。否则,系统可能会忽略原本盈利的交易组合,或者相反,将那些因负隔夜利息而实际亏损的组合视为盈利。


订单执行微调:与市场魔鬼的较量

在高频交易的世界里,执行质量可能决定盈亏成败。TrisWeb_Optimized采用底层MQL5结构,实现对订单下达和执行过程的极致控制:

bool OpenBuyStop(string symbol, double volume, double openPrice)
{
   MqlTradeRequest request = {};
   MqlTradeResult result = {};
   
   request.action = TRADE_ACTION_PENDING;
   request.symbol = symbol;
   request.volume = volume;
   request.type = ORDER_TYPE_BUY_STOP;
   request.price = openPrice;
   request.deviation = Deviation;
   request.magic = EXPERT_MAGIC;
   
   if(UseCommentsInOrders)
      request.comment = OrderComment;
   
   if(!OrderSend(request, result))
   {
      Print("OrderSend error ", GetLastError(), " retcode: ", result.retcode);
      return false;
   }
   
   return true;
}
需要特别关注的是“偏差”参数——它决定了订单可在请求价格之外多少范围内成交:
input int Deviation = 3;          // Acceptable price deviation

这相当于您与市场魔鬼达成的协议:“我愿意接受比我请求价格差3个点的成交价,但不能再多了。”在市场剧烈波动时期,这可能决定订单是成交还是错失良机。如果偏差值设置过小,订单会因报价变动而被拒绝;反之设置过大,则可能以意外糟糕的价格成交。


实时信息展示与分析:交易者的耳目

在开发TrisWeb_Optimized之初,我就意识到许多EA的一个关键问题在于它们像“黑箱”一样运作,让交易者无法理解其内部逻辑。因此,我通过DisplayInfo()函数添加了详细信息的输出功能:

void DisplayInfo(int totalOrders, double totalProfit, 
                double profit1, double profit2, double profit3,
                int count1, int count2, int count3)
{
   string info = "";
   
   if(AutoLotOptimization)
   {
      double lot1 = CalculateOptimalLotSize(Symbol1, Lot_Symbol1);
      double lot2 = CalculateOptimalLotSize(Symbol2, Lot_Symbol2);
      double lot3 = CalculateOptimalLotSize(Symbol3, Lot_Symbol3);
      
      info += "Auto Lot: " + Symbol1 + "=" + DoubleToString(lot1, 2) + 
              ", " + Symbol2 + "=" + DoubleToString(lot2, 2) + 
              ", " + Symbol3 + "=" + DoubleToString(lot3, 2) + "\n";
   }
   
   // ... the rest of the information generation code
   
   Comment(info);
}
您可以选择基本显示模式(适合极简主义者),也可以选择包含各货币对详细分析的标准模式:
input bool DisplayDetailedInfo = false;  // Show detailed information

这就像老式汽车的基本仪表盘(只有速度表和油量表)与现代驾驶舱(有几十个仪表和显示屏)的区别——选择取决于您的驾驶风格。

以下是旧版本系统其中一套策略的表现:

 


系统扩展:从简单机器人到交易帝国

TrisWeb_Optimized不仅是一个现成的EA,更是构建您自己的套利帝国的基石。在其五年的发展历程中,我不断地对其进行修改,添加新功能并优化现有功能。以下是您可以进一步开发系统的几个方向:

与Python集成,为相关性分析和机器学习方法的应用开辟了巨大可能性。想象一下,您不仅能分析当前报价,还能解析三个货币对之间历史互动模式,预测最有可能出现的失衡情况。

通过Telegram API发送通知,为您的交易策略增添了灵活性——即使您不在交易终端前,也能随时了解重要事件。当EA在远程虚拟专用服务器(VPS)上运行时,这一点尤其有用。

扩展到更多货币对,使TrisWeb成为一个成熟的套利平台。既然您可以创建一个由数十个相互关联的货币对组成的网络,追踪数百个潜在的套利机会,为何还要局限于三个交易工具呢?

所有这些修改只需对现有代码进行最小程度的更改,同时保持其基本结构和运行逻辑。这就像在现有房屋上扩建房间——地基已经打好,只需扩大居住空间即可。


结语

五年前,当TrisWeb_Optimized的第一个版本发布时,我从未想过后续会走上这样的道路。它经历了市场风暴、极端波动和相对平静的时期。它已经从一个简单的脚本发展成为一个成熟的交易系统。但最重要的是,它从未停止过盈利。

在本文的下一部分,我们将深入探讨TrisWeb_Optimized的实战设置,考察系统运行的实际案例,并分享针对各种市场条件优化参数的秘诀。敬请期待——最精彩的部分还在后面!

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/17424

附加的文件 |
Triss_Optimized.mq5 (40.02 KB)
最近评论 | 前往讨论 (17)
Maxim Kuznetsov
Maxim Kuznetsov | 19 1月 2026 在 18:33
MrBrooklin #:
在文章中发表或在 CodeBase 中发布的智能交易系统无法盈利。

盈利与否是交易者和技术手段(包括智能交易系统)共同作用的结果。

文章和代码库中有很多合理的建议,但越往后,错误的建议就越多,这对交易者和开发者都没有任何帮助。

MrBrooklin
MrBrooklin | 20 1月 2026 在 05:30
Maxim Kuznetsov #:

盈利与否是交易者和技术手段(包括顾问)共同作用的结果。

在文章和代码库中有很多合理的建议,但越往后,错误的建议就越多,这对交易者和开发者都没有任何帮助。 货币合成套利就是其中之一。

关键词是 "曾经"!但现在不是了。
弗拉基米尔
MrBrooklin
MrBrooklin | 21 1月 2026 在 07:13
Kenneth Michael Chambers #:
...我把它编入了 EA...

你好,非常有趣,你在 EA 中编了什么程序?我想知道详情。

敬上,弗拉基米尔

Zhang Yi
Zhang Yi | 3 2月 2026 在 13:45

我不得不说,这家伙是乎一无所知


double commission = PositionGetDouble(POSITION_COMMISSION);

这个值永远是 0, 从这里就可以看出,他是来骗稿费的 😂😂😂😂

Arinze Michael Ejike
Arinze Michael Ejike | 3 2月 2026 在 16:27
MrBrooklin #:
关键词是 "曾经是"!)但现在不是了。
再见,弗拉基米尔
代码库的内容非常丰富。尤其是库部分。就像代码库中最好的部分。
从新手到专家:使用 MQL5 制作动画新闻标题(四) — 本地托管 AI 模型市场洞察 从新手到专家:使用 MQL5 制作动画新闻标题(四) — 本地托管 AI 模型市场洞察
在今天的讨论中,我们将探讨如何自行托管开源 AI 模型,并使用它们来生成市场洞察。这是我们持续扩展 News Headline EA 的一部分努力,引入了 AI 洞察通道,将其转变为多集成辅助工具。升级后的 EA 旨在通过日历事件、财经突发新闻、技术指标以及现在的 AI 生成的市场观点,让交易者随时了解最新动态,从而为交易决策提供及时、多样化和智能的支持。加入我们的讨论,我们将探讨实用的集成策略,以及 MQL5 如何与外部资源协作,构建强大而智能的交易工作终端。
神经类群优化算法 (NOA) 神经类群优化算法 (NOA)
一种新的生物启发的优化元启发式算法——NOA(Neuroboids Optimization Algorithm,神经类群优化算法),结合了集体智能和神经网络的原理。与传统方法不同,该算法使用了一个由具备自学习能力的“神经类群(neuroboids)”组成的群体,每个神经类群都拥有自己的神经网络,能够实时调整其搜索策略。本文揭示了该算法的架构、代理的自学习机制,以及这种混合方法在解决复杂优化问题方面的应用前景。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
从新手到专家:使用 MQL5 制作动画新闻标题 (三) — 指标洞察 从新手到专家:使用 MQL5 制作动画新闻标题 (三) — 指标洞察
在本文中,我们将通过引入专门的指标洞察通道来推进新闻标题EA —— 一个紧凑的图表显示,显示由RSI、MACD、随机震荡指标和 CCI 等流行指标生成的关键技术信号。这种方法消除了 MetaTrader 5 终端上多个指标子窗口的需要,使您的工作空间保持干净高效。通过利用 MQL5 API 在后台访问指标数据,我们可以使用自定义逻辑实时处理和可视化市场洞察。加入我们,探索如何在 MQL5 中操纵指标数据,以创建一个智能且节省空间的滚动洞察系统,所有这些都在您的交易图表上的一个水平通道内。