跳转到正文

从零编写 MQL5 智能交易系统,第1篇:EA 结构与不使用马丁格尔的风险管理

通过我们自行编写的交易机器人,了解 MQL5 EA:三个核心函数、根据止损距离计算仓位,以及高胜率为何常常掩盖亏损。

Admin
从零编写 MQL5 智能交易系统,第1篇:EA 结构与不使用马丁格尔的风险管理 · 2026年8月15日

从零编写 MQL5 智能交易系统,第1篇:EA 结构与不使用马丁格尔的风险管理

我们在持续运行的模拟账户上测试目录中的十五款免费 EA,并公布其结果。在完成449笔交易后,一个令人不安的规律浮现出来:几乎所有导致账户资金亏光的机器人,胜率都很高。其中一款有68%的交易盈利平仓,却仍然亏光了本金。

于是,我们编写了自己的机器人,目的并非战胜市场,而是通过代码展示如何构建一个旨在避免单日亏光账户资金的机器人。它已收录在目录中,并附有源代码,目前正在我们的模拟账户上交易。本篇介绍基本结构与风险管理;第二篇将介绍如何通过命令行编译 EA 并运行策略测试器。

**编者注:**前述说法描述的是该 EA 风险控制的设计目标,并不保证账户不会亏光。跳空、滑点和止损执行情况都可能使实际亏损超过计划风险。

智能交易系统由哪些部分组成

每个 MQL5 EA 都有三个由终端调用的函数。

int OnInit()                      // once when attached to a chart
void OnTick()                     // on every price change
void OnDeinit(const int reason)   // when removed from the chart

OnInit负责初始化设置:我们在这里设置魔术编号,让机器人区分自己的持仓与其他持仓,同时设置订单执行模式。

#include <Trade\Trade.mqh>

CTrade trade;

int OnInit()
{
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetTypeFillingBySymbol(_Symbol);
   trade.SetDeviationInPoints(20);
   return(INIT_SUCCEEDED);
}

标准库中的CTrade类会为你构建交易请求。在2026年,已没有必要手动构造MqlTradeRequest结构体。

OnTick在每个 tick 到来时运行,每分钟可触发数十次。如果策略基于已收盘的 K 线运行,第一步就应过滤掉不必要的调用。否则,机器人会重复作出同一个决策数百次:

static datetime lastBar = 0;
datetime barTime = iTime(_Symbol, PERIOD_M15, 0);
if(barTime == lastBar) return;   // this candle has already been processed
lastBar = barTime;

参数:为什么我们不使用报价点

我们的 EA 初版在四年的历史数据中没有进行任何交易。问题出在一个以报价点表示的过滤条件上:不同经纪商的黄金报价精度相差十倍,因此“区间宽度不超过3000个报价点”在一家经纪商那里意味着三美元,在另一家那里却意味着三十美元。结果,过滤条件排除了所有交易机会。

因此,我们将阈值表示为价格的百分比。这些设置可以直接用于不同经纪商和交易品种,无需调整:

input double MinRangePct = 0.15;  // quiet day, no opportunity
input double MaxRangePct = 2.0;   // news gap, false breakout

double rangePct = (rangeHigh - rangeLow) / price * 100.0;
if(rangePct < MinRangePct || rangePct > MaxRangePct) return;

点差也同样如此。设置绝对上限没有意义:黄金点差可能达到90–190个报价点,因此60个报价点的阈值会排除所有机会。关键不在于点差本身,而在于它会消耗价格波动幅度的多大比例:

double spreadShare = spreadPrice / (rangeHigh - rangeLow) * 100.0;
if(spreadShare > MaxSpreadRangePct) return;   // costs would consume the move

核心原则:根据止损计算仓位,而不是反过来

这正是机器人能否熬过糟糕的一周、还是亏光账户资金的关键区别。

多数免费 EA 采用的错误做法是:固定仓位,或在亏损后增大交易手数,然后随意找个位置设置止损,甚至完全不设止损。正确做法是倒过来:先确定价格到哪里意味着交易逻辑失效,再计算仓位,使这次判断失误的代价控制在预先设定的账户资金比例内。

double RiskLots(double stopDistance)
{
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   if(tickValue <= 0 || tickSize <= 0) return(0);

   // How much money we are willing to lose on this trade
   double moneyRisk  = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100.0;
   // The cost of the stop loss for a one-lot position
   double lossPerLot = (stopDistance / tickSize) * tickValue;

   double lots = moneyRisk / lossPerLot;

   double minLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   lots = MathFloor(lots / lotStep) * lotStep;

   // The deposit cannot support this stop: skip the trade
   // rather than risk more than the specified amount
   if(lots < minLot) return(0);
   return(lots);
}

注意最后一行。你可能会想把仓位向上取整到最小手数,照样入场。但正是这种做法,会让机器人在不知不觉中承担设置值三倍的风险。放弃这笔交易的代价更小。

还有一个重要细节:从终端查询SYMBOL_TRADE_TICK_VALUE和SYMBOL_TRADE_TICK_SIZE,不要将其写死在代码中。黄金、货币对和指数的这些数值各不相同。一个“专为 EURUSD”编写的机器人,用于黄金时计算出的仓位可能相差一百倍。

保本止损:一种保护措施,并非万能方案

当一笔交易的浮盈达到初始风险的预设倍数时,止损就移动到入场价。这样,交易要么获利,要么以零盈亏平仓,避免转为亏损。

**编者注:**将止损设在入场价并不保证净盈亏为零:点差、佣金、隔夜利息和执行滑点仍可能造成亏损。

double risk   = MathAbs(entry - sl);
double profit = (type == POSITION_TYPE_BUY) ? (price - entry) : (entry - price);

if(BreakevenAtR > 0 && profit >= risk * BreakevenAtR)
   trade.PositionModify(ticket, entry, tp);   // move the stop to the entry price

移动止损的触发条件由参数决定,这一点很重要。在我们的测试中,当浮盈达到一倍初始风险时就移动止损,结果明显差于达到一点五倍时再移动。过早移至保本位,会让那些在真正走出行情前需要一定波动空间的交易提前止损离场。在四年的历史数据中,这两种设置的最终结果相差约百分之十。

测试结果

策略很简单:测量清淡亚洲交易时段的价格区间,在首根收盘价突破区间边界的 K 线收盘后入场,将止损放在另一侧边界之外,止盈目标设为止损距离的三倍,每天只交易一次。

我们使用2022–2024的数据选择参数,再使用未参与参数选择的2025–2026数据进行验证:

样本 收益率 交易笔数 盈利交易占比 盈利因子 回撤
训练样本 2022–2024 +33.0% 327 43.7% 1.35 7.5%
验证样本 2025–2026 +11.6% 145 46.2% 1.33 3.9%
不同经纪商,2022–2025 +41.5% 335 30.4% 1.41 9.2%

第三行使用相同的 EA 和设置,但报价来自另一家经纪商。差异来自点差和报价精度,而非策略本身:一家经纪商将黄金标为GOLD#,另一家则标为XAUUSD。如果换一家经纪商,策略就失效,说明它依赖的是特定报价源,而非市场本身。

盈利交易不到一半,当止盈目标为风险的三倍时,这是正常的。我们测试中那款胜率达到68%的机器人,在这一栏看起来出色得多,却仍然亏光了本金。仅凭胜率几乎无法判断 EA 的表现;应重点关注回撤和盈利因子。

我们也需要明确说明局限:在 EURUSD 上,相同设置的盈利因子约为一,因此这项优势仅适用于黄金。而回测终究只是回测。机器人已在我们的模拟账户上运行,其结果将显示在实时监测页面上,无法事后修改。

下一篇

第二篇将介绍俄语指南中很少涉及的内容:通过metaeditor64.exe在命令行编译 EA,并通过 INI 配置文件在策略测试器中运行,全程无需在界面上点击。这能把验证一个想法所需的十分钟手动操作,变成十秒钟的命令执行。正因如此,我们才能在一个晚上尝试一百组配置。

EA 的完整源代码位于其目录页面。你可以下载、阅读,并根据自己的需要修改。

本文中的经纪商链接为推广链接:我们会获得佣金,而你享受的条件与通过直接链接访问相同。我们只提及自己也在使用的服务。

分享本文:

评论 (0)

评论与评价按原文语言显示。

登录后发表评论

暂无评论

欢迎发表首条评论!

更多 EA 指南与测试

EA 评测、模拟交易结果与 MQL5 笔记。

所有博客文章