MT5指标编译通过 · EX5 33KB 自动发布 2 0

双均线马丁趋势跟踪EA

litongxue·1 小时前发布

MA10/MA20趋势+止损再入+马丁加仓,亏损加码直到盈利

双均线马丁趋势跟踪EA

MT5 真机运行截图 · 服务器把编译好的 EX5 挂到黄金 H1 图表上截的,你装上去看到的就是这个样子

MA_Trend_Follow_Martingale_EA.mq5314 行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#property copyright "XAUOF指标工坊"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>

// ========== 输入参数 ==========
input int    MA_Fast_Period = 10;        // 快线周期(推荐10)
input int    MA_Slow_Period = 20;        // 慢线周期(推荐20)
input double Initial_Lot = 0.01;         // 初始手数(马丁起始手数)
input double Lot_Step = 0.01;            // 马丁加仓步长
input int    Magic_Number = 20250115;    // EA魔术号
input int    Slippage = 30;              // 允许滑点(点)
input string Comment_Text = "MA马丁EA";   // 订单注释

// ========== 全局变量 ==========
CTrade trade;
int handleMA10, handleMA20;
double bufMA10[], bufMA20[];

// 状态机:0=空闲 1=持多 2=持空 3=等待突破G1做多 4=等待突破D1做空
int currentState = 0;
double G1 = 0; // 上次多单止损K线的最高点
double D1 = 0; // 上次空单止损K线的最低点

// 马丁策略变量
double currentLotSize = 0.01; // 当前开仓手数,动态调整

//+------------------------------------------------------------------+
int OnInit()
{
   trade.SetExpertMagicNumber(Magic_Number);
   trade.SetDeviationInPoints(Slippage);
   
   // 创建MA指标句柄
   handleMA10 = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MODE_EMA, PRICE_CLOSE);
   handleMA20 = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MODE_EMA, PRICE_CLOSE);
   
   if(handleMA10 == INVALID_HANDLE || handleMA20 == INVALID_HANDLE)
   {
      Print("创建MA指标失败");
      return INIT_FAILED;
   }
   
   ArraySetAsSeries(bufMA10, true);
   ArraySetAsSeries(bufMA20, true);
   
   currentLotSize = Initial_Lot; // 初始化马丁手数
   
   Print("EA初始化成功,魔术号:", Magic_Number, " 初始手数:", currentLotSize);
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(handleMA10);
   IndicatorRelease(handleMA20);
}

//+------------------------------------------------------------------+
void OnTick()
{
   // 等待指标计算完成
   if(BarsCalculated(handleMA10) < MA_Slow_Period || BarsCalculated(handleMA20) < MA_Slow_Period)
      return;
   
   // 复制MA数值(索引0=当前K线,1=前一根...)
   if(CopyBuffer(handleMA10, 0, 0, 5, bufMA10) < 5) return;
   if(CopyBuffer(handleMA20, 0, 0, 5, bufMA20) < 5) return;
   
   // 获取当前K线和前3根K线的OHLC
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates) < 5) return;
   
   // 计算实体中点价格(最近3根K线,索引1/2/3,不含当前未完成K线0)
   double mid1 = (rates[1].open + rates[1].close) / 2.0;
   double mid2 = (rates[2].open + rates[2].close) / 2.0;
   double mid3 = (rates[3].open + rates[3].close) / 2.0;
   
   // 当前价格和MA值
   double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ma10_current = bufMA10[1]; // 用完成K线的MA值
   double ma20_current = bufMA20[1];
   
   // 检查当前持仓
   bool hasPosition = false;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
      {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number)
         {
            hasPosition = true;
            break;
         }
      }
   }
   
   // ========== 持仓管理:检查止损条件 ==========
   if(currentState == 1) // 持多仓
   {
      // 止损条件:价格回落到MA10与MA20之间 OR 价格同时低于两均线
      bool stopLong = false;
      if(price < ma10_current && price > ma20_current) stopLong = true; // 在两线之间
      if(price < ma10_current && price < ma20_current) stopLong = true; // 同时低于
      
      if(stopLong)
      {
         // 平仓前计算盈亏,决定下次手数
         double totalProfit = GetTotalProfit();
         CloseAllPositions();
         
         // 马丁策略:亏损加仓,盈利重置
         if(totalProfit < 0)
         {
            currentLotSize += Lot_Step;
            Print("多单止损亏损,下次手数增加至:", currentLotSize);
         }
         else
         {
            currentLotSize = Initial_Lot;
            Print("多单止损盈利,手数重置为:", currentLotSize);
         }
         
         G1 = rates[0].high; // 记录当前止损K线的最高点
         currentState = 3;   // 进入等待突破G1状态
         Print("多单止损,记录止损K线最高点G1=", G1, " 盈亏=", totalProfit);
      }
   }
   else if(currentState == 2) // 持空仓
   {
      // 止损条件:价格上升到MA10与MA20之间 OR 价格同时高于两均线
      bool stopShort = false;
      if(price > ma10_current && price < ma20_current) stopShort = true; // 在两线之间
      if(price > ma10_current && price > ma20_current) stopShort = true; // 同时高于
      
      if(stopShort)
      {
         // 平仓前计算盈亏,决定下次手数
         double totalProfit = GetTotalProfit();
         CloseAllPositions();
         
         // 马丁策略:亏损加仓,盈利重置
         if(totalProfit < 0)
         {
            currentLotSize += Lot_Step;
            Print("空单止损亏损,下次手数增加至:", currentLotSize);
         }
         else
         {
            currentLotSize = Initial_Lot;
            Print("空单止损盈利,手数重置为:", currentLotSize);
         }
         
         D1 = rates[0].low; // 记录当前止损K线的最低点
         currentState = 4;  // 进入等待突破D1状态
         Print("空单止损,记录止损K线最低点D1=", D1, " 盈亏=", totalProfit);
      }
   }
   
   // 如果已有持仓,不再检查开仓信号
   if(hasPosition) return;
   
   // ========== 开仓信号判断 ==========
   
   // 【做多信号】
   if(currentState == 0 || currentState == 3)
   {
      // 前提:MA10 > MA20
      if(bufMA10[1] > bufMA20[1])
      {
         // 连续3根K线实体中点都在MA10之上
         bool signal = (mid1 > bufMA10[1] && mid2 > bufMA10[2] && mid3 > bufMA10[3]);
         
         // 如果是状态3(等待突破G1),需要额外判断价格>G1
         if(currentState == 3)
         {
            if(signal && price > G1)
            {
               OpenBuy();
               currentState = 1;
               Print("突破G1再入场做多,价格=", price, " G1=", G1, " 手数=", currentLotSize);
            }
         }
         else if(currentState == 0) // 初始状态
         {
            if(signal)
            {
               OpenBuy();
               currentState = 1;
               Print("首次开多,MA10=", ma10_current, " MA20=", ma20_current, " 手数=", currentLotSize);
            }
         }
      }
      else
      {
         // MA10已经<MA20,取消等待突破G1状态,重置手数
         if(currentState == 3) 
         {
            currentState = 0;
            currentLotSize = Initial_Lot; // 趋势反转,重置马丁
            Print("趋势反转,马丁手数重置");
         }
      }
   }
   
   // 【做空信号】
   if(currentState == 0 || currentState == 4)
   {
      // 前提:MA10 < MA20
      if(bufMA10[1] < bufMA20[1])
      {
         // 连续3根K线实体中点都在MA10之下
         bool signal = (mid1 < bufMA10[1] && mid2 < bufMA10[2] && mid3 < bufMA10[3]);
         
         // 如果是状态4(等待突破D1),需要额外判断价格<D1
         if(currentState == 4)
         {
            if(signal && price < D1)
            {
               OpenSell();
               currentState = 2;
               Print("跌破D1再入场做空,价格=", price, " D1=", D1, " 手数=", currentLotSize);
            }
         }
         else if(currentState == 0) // 初始状态
         {
            if(signal)
            {
               OpenSell();
               currentState = 2;
               Print("首次开空,MA10=", ma10_current, " MA20=", ma20_current, " 手数=", currentLotSize);
            }
         }
      }
      else
      {
         // MA10已经>MA20,取消等待突破D1状态,重置手数
         if(currentState == 4) 
         {
            currentState = 0;
            currentLotSize = Initial_Lot; // 趋势反转,重置马丁
            Print("趋势反转,马丁手数重置");
         }
      }
   }
}

//+------------------------------------------------------------------+
// 计算当前所有持仓的总盈亏
double GetTotalProfit()
{
   double totalProfit = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
      {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number)
         {
            totalProfit += PositionGetDouble(POSITION_PROFIT);
         }
      }
   }
   return totalProfit;
}

//+------------------------------------------------------------------+
void OpenBuy()
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   if(trade.Buy(currentLotSize, _Symbol, ask, 0, 0, Comment_Text))
   {
      Print("开多成功,手数=", currentLotSize, " 价格=", ask);
   }
   else
   {
      Print("开多失败,错误码=", GetLastError());
   }
}

//+------------------------------------------------------------------+
void OpenSell()
{
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(trade.Sell(currentLotSize, _Symbol, bid, 0, 0, Comment_Text))
   {
      Print("开空成功,手数=", currentLotSize, " 价格=", bid);
   }
   else
   {
      Print("开空失败,错误码=", GetLastError());
   }
}

//+------------------------------------------------------------------+
void CloseAllPositions()
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
      {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number)
         {
            trade.PositionClose(ticket);
            Print("平仓订单:", ticket);
         }
      }
   }
}
MT5 运行截图 · 完整视图带价格轴和时间轴的整张图表(约 150 根 H1 K 线),上面的封面是它最近 80 根 K 线的放大视图
双均线马丁趋势跟踪EA 在 MT5 上的真实截图

作品说明

好的,我加入马丁策略:每次止损后如果是亏损,下次开仓手数增加0.01;如果是盈利,手数重置为0.01。

使用说明

新增马丁策略:

  • 初始手数 0.01:首次开仓固定 0.01 手
  • 亏损加仓:止损后如果是亏损,下次开仓手数增加 0.01(0.02 → 0.03 → 0.04...)
  • 盈利重置:止损后如果是盈利,下次开仓手数重置为 0.01
  • 趋势反转重置:若趋势从多转空(MA10从>MA20变成<MA20),手数也重置为 0.01

参数说明:

  • Initial_Lot:马丁起始手数,推荐 0.01
  • Lot_Step:每次加仓步长,推荐 0.01(可调 0.02 以加快马丁速度)
  • MA周期:10/20 适合黄金,其他品种可调整

风险提示:

  1. 马丁策略风险极高:连续止损会导致手数快速增长(0.01 → 0.02 → 0.04 → 0.08...),10次亏损手数将达到 0.11+,单次亏损可能爆仓
  2. 必须设置最大手数限制:建议添加参数 Max_Lot(如 0.1),超过就暂停交易
  3. 资金管理:账户至少要能承受 10 次连续加仓的保证金和亏损
  4. 适用场景:震荡后突破的行情,趋势一旦启动能快速回本;不适合单边暴涨暴跌

测试建议:

  1. 先在模拟盘测试至少 3 个月,观察最大连续亏损次数
  2. 回测时关注最大手数、最大回撤、连续亏损次数
  3. 实盘时从小资金(100美元)起步,严格止损

安装步骤: 保存为 MA_Trend_Follow_Martingale_EA.mq5 → 编译 → 加载到 H1 或 H4 图表 → 启用自动交易

AI 解读根据源码逐行分析写成,供参考,以实际运行为准

这是什么

这是一个基于双均线(EMA 10 和 EMA 20)的趋势跟踪 EA,结合马丁格尔资金管理策略。当趋势确认后入场,止损后会等待价格突破止损K线高低点再次入场,每次亏损后手数自动增加 0.01,盈利后重置为初始手数,目标是通过加仓摊平成本直到趋势回归盈利。

逻辑原理

趋势判断 使用 EMA 10 和 EMA 20 确定方向。当 MA10 在 MA20 上方视为上升趋势,反之为下降趋势。

开仓信号 多单:MA10 > MA20,且连续 3 根已完成 K 线的实体中点(开盘价与收盘价的平均值)都在 MA10 上方。 空单:MA10 < MA20,且连续 3 根 K 线实体中点都在 MA10 下方。

止损逻辑 不设固定点数止损,而是根据价格与均线关系判断:

  • 多单止损:价格回落到 MA10 与 MA20 之间,或同时跌破两条均线
  • 空单止损:价格上升到 MA10 与 MA20 之间,或同时突破两条均线

止损时记录当前 K 线的极值点(多单记录最高点 G1,空单记录最低点 D1)。

再入场机制 多单止损后不会立即重新开仓,而是等待价格再次突破止损K线最高点 G1,且满足开多信号时才入场。空单同理,等待跌破最低点 D1。这避免在震荡中反复止损。

马丁策略 止损时计算本次持仓总盈亏:

  • 如果亏损(盈亏 < 0),下次开仓手数增加一个步长(默认 0.01)
  • 如果盈利(盈亏 >= 0),下次开仓手数重置为初始手数(默认 0.01)
  • 如果趋势反转(MA10 与 MA20 交叉),手数也重置为初始值

例如:首次开 0.01 手亏损 → 第二次 0.02 手亏损 → 第三次 0.03 手盈利 → 第四次重置为 0.01 手。

参数说明

  • MA_Fast_Period(10):快速均线周期,数值越小对价格越敏感。适合 H1 以上周期,日内交易可改为 5
  • MA_Slow_Period(20):慢速均线周期,与快线配合判断趋势。常见组合 5/10、10/20、20/50
  • Initial_Lot(0.01):马丁起始手数,账户资金少于 500 美元建议保持 0.01
  • Lot_Step(0.01):每次亏损后加仓步长。改为 0.02 会让马丁速度翻倍,风险同步放大
  • Magic_Number(20250115):EA 识别码,多个 EA 同时运行时需设置不同值
  • Slippage(30):允许滑点范围(点),行情波动大时可放宽到 50
  • Comment_Text:订单注释,方便在交易历史中筛选

怎么用

将代码保存为 .mq5 文件,放入 MT5 的 MQL5/Experts 文件夹,在 MetaEditor 中编译。打开任意货币对或商品图表(推荐 H1 或 H4 周期),将 EA 拖到图表上,勾选"允许自动交易",点击确定。

EA 不会在图表上画任何指标线或箭头,开平仓信息在"专家"日志窗口查看。持仓情况在"交易"面板显示,可以看到当前手数和盈亏。

适用场景

适合

  • 趋势明显的品种:黄金、欧美、镑美等主流货币对
  • H1 及以上周期:日内周期均线滞后严重,假信号多
  • 震荡后突破的行情:横盘整理后趋势启动,止损再入机制能抓住第二波
  • 单边行情启动初期:马丁策略在趋势持续时能快速回本并盈利

不适合

  • 高频震荡行情:价格反复穿越均线会导致连续止损,马丁手数快速增长
  • 单边暴涨暴跌:无固定止损点数,极端行情可能晚止损导致单笔亏损过大
  • 小资金账户:100 美元以下账户很难承受 5 次以上连续加仓
  • 点差过大的平台:剥头皮类 EA 对成本敏感,点差 > 3 点会严重影响盈利

风险提示

马丁策略的致命缺陷 这是典型的线性马丁:0.01 → 0.02 → 0.03 → 0.04...,10 次连续亏损后手数达到 0.11。如果每次止损 50 点,单次亏损从 5 美元增长到 55 美元。代码中没有设置最大手数限制,理论上可以无限加仓直到保证金不足爆仓。

无固定止损的隐患 EA 只根据价格与均线关系止损,没有设置固定点数或金额止损。如果价格快速单边运行,可能在亏损较大时才触发均线止损条件。建议在代码中加入固定止损点数(如 100 点)作为兜底保护。

滞后性 均线本质是历史价格的平均值,信号天然滞后。行情反转时可能已经回撤 20%-30%,止损再入机制虽然减少了假信号,但也会错过趋势初段的利润。

连续止损风险 震荡行情中价格可能反复穿越均线,触发开仓 → 止损 → 加仓 → 再止损的循环。5 次连续止损后手数已经是初始值的 5 倍,单次亏损对账户的冲击会呈几何级增长。

必须做的防护

  1. 在代码中添加 input double Max_Lot = 0.1; 参数,开仓前检查 if(currentLotSize > Max_Lot) return;
  2. 设置每日最大亏损额(如账户的 5%),触及后停止交易
  3. 回测时重点关注最大连续亏损次数、最大手数、最大回撤三个指标
  4. 实盘前在模拟账户至少运行 3 个月,观察不同行情下的表现

不保证盈利 马丁策略的本质是用更大的风险换取更高的胜率,长期来看无法改变策略本身的数学期望。历史回测盈利不代表未来表现,任何 EA 都可能在极端行情中爆仓。

常见问题

这个 EA 会重绘吗?
不会。代码使用已完成 K 线(rates[1/2/3])的数据判断信号,不依赖当前未完成 K 线,历史信号不会改变。
连续亏损多少次会爆仓?
取决于账户资金和杠杆。假设 1000 美元账户,杠杆 1:100,每次止损 50 点,大约 8-10 次连续亏损会耗尽保证金。代码没有最大手数限制,需要自行添加。
可以用在其他品种吗?
可以,但均线周期可能需要调整。原油、指数等波动大的品种建议加大均线周期(如 20/50)或增加 Slippage 参数,避免滑点导致开仓失败。
能否取消马丁策略只做趋势跟踪?
可以。将 Lot_Step 改为 0,或者修改代码,在止损后不执行 currentLotSize += Lot_Step 这行,手数始终保持 Initial_Lot。
参数默认值适合什么周期?
H1 和 H4 周期。M15 等日内周期均线交叉频繁会导致过度交易,D1 日线周期信号太少。实盘建议从 H4 开始测试。

EMA 10/20 Martingale Trend Following EA for MT5

A trend-following EA based on EMA 10/20 crossover with re-entry after stop-loss and martingale position sizing. Lot size increases after each loss and resets after profit. Includes full MQL5 source code.

Source code is shown above. Compiled EX5 files are available to VIP members.

评论

后可以留言,比如反馈用着怎么样、想加什么功能。

还没有人评论,来抢个沙发。