MT5指标编译通过 · EX5 43KB 自动发布 1 0

多空双开总利润追踪止盈EA

taiyu1983·2 小时前发布

账户级总盈亏追踪,ADX过滤+顺势逆势加仓+总利润保护,自动全平

多空双开总利润追踪止盈EA

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

MultiHedgeTotalProfitTrailingEA.mq5456 行
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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#property copyright "XAUOF指标工坊"
#property version   "2.00"
#property strict

#include <Trade\Trade.mqh>

// ========== 基础开仓参数 ==========
input group "=== 基础开仓设置 ==="
input double InitialLot = 0.01;           // 初始手数
input int MagicNumber = 20241201;         // 魔术号(区分不同EA)
input int Slippage = 30;                  // 滑点(点数)

// ========== 多空开仓控制 ==========
input group "=== 多空开仓控制 ==="
input bool AllowBuy = true;               // 允许开多单
input bool AllowSell = true;              // 允许开空单
input bool AllowHedge = true;             // 允许多空双开(对冲)

// ========== 顺势加仓参数 ==========
input group "=== 顺势加仓设置 ==="
input bool EnableTrendAdd = true;         // 启用顺势加仓
input double TrendAddDistance = 300;      // 顺势加仓间距(点数)
input double TrendAddMultiplier = 1.5;    // 顺势加仓倍数
input int MaxTrendAddCount = 3;           // 顺势最多加仓次数

// ========== 逆势加仓参数 ==========
input group "=== 逆势加仓设置 ==="
input bool EnableCounterAdd = true;       // 启用逆势加仓
input double CounterAddDistance = 500;    // 逆势加仓间距(点数)
input double CounterAddMultiplier = 2.0;  // 逆势加仓倍数
input int MaxCounterAddCount = 2;         // 逆势最多加仓次数

// ========== ADX趋势过滤 ==========
input group "=== ADX趋势过滤 ==="
input bool UseAdxFilter = true;           // 启用ADX过滤
input int AdxPeriod = 14;                 // ADX周期
input double AdxTrendLevel = 25.0;        // ADX趋势强度阈值(>此值才开仓)
input double AdxWeakLevel = 20.0;         // ADX弱势阈值(<此值停止加仓)

// ========== 总利润追踪止盈止损 ==========
input group "=== 总利润追踪设置 ==="
input bool EnableTotalTrailing = true;    // 启用总利润追踪
input double TotalProfitTarget = 100.0;   // 开始追踪的总盈利目标(美元)
input double TotalTrailingStop = 50.0;    // 追踪止损回撤(美元,从最高盈利回撤此值全平)
input double TotalStopLoss = 200.0;       // 总止损(美元,浮亏超过此值全平)

// ========== 面板显示 ==========
input group "=== 面板显示设置 ==="
input bool ShowPanel = true;              // 显示信息面板
input int PanelX = 20;                    // 面板X坐标
input int PanelY = 30;                    // 面板Y坐标
input color PanelColor = clrWhite;        // 面板文字颜色

// ========== 全局变量 ==========
CTrade trade;
int adxHandle = INVALID_HANDLE;
double adxBuffer[];

// 追踪状态
double maxProfit = 0;          // 历史最高总盈利
bool isTrailing = false;       // 是否正在追踪

struct PositionInfo {
   ulong ticket;
   int type;        // 0=buy, 1=sell
   double openPrice;
   double lots;
   int addCount;    // 加仓次数
};

PositionInfo buyPositions[];
PositionInfo sellPositions[];

//+------------------------------------------------------------------+
//| 初始化                                                              |
//+------------------------------------------------------------------+
int OnInit()
{
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(Slippage);
   trade.SetTypeFilling(ORDER_FILLING_IOC);
   
   // 创建ADX句柄
   if(UseAdxFilter) {
      adxHandle = iADX(_Symbol, PERIOD_CURRENT, AdxPeriod);
      if(adxHandle == INVALID_HANDLE) {
         Print("ADX指标创建失败!");
         return INIT_FAILED;
      }
      ArraySetAsSeries(adxBuffer, true);
   }
   
   // 创建面板
   if(ShowPanel) CreatePanel();
   
   // 重置追踪状态
   maxProfit = 0;
   isTrailing = false;
   
   Print("多空双开总利润追踪EA启动成功");
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| 清理                                                              |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(adxHandle != INVALID_HANDLE) IndicatorRelease(adxHandle);
   if(ShowPanel) DeletePanel();
}

//+------------------------------------------------------------------+
//| 主循环                                                              |
//+------------------------------------------------------------------+
void OnTick()
{
   // 更新持仓信息
   UpdatePositions();
   
   // 检查总盈亏追踪止盈止损(优先级最高)
   if(EnableTotalTrailing) {
      CheckTotalProfitTrailing();
   }
   
   // 检查ADX条件
   bool adxOk = CheckAdx();
   
   // 多单逻辑
   if(AllowBuy) {
      if(ArraySize(buyPositions) == 0 && adxOk) {
         // 首次开多单
         OpenPosition(ORDER_TYPE_BUY, InitialLot);
      } else if(ArraySize(buyPositions) > 0) {
         // 多单加仓逻辑
         CheckAddPosition(ORDER_TYPE_BUY);
      }
   }
   
   // 空单逻辑
   if(AllowSell) {
      if(ArraySize(sellPositions) == 0 && adxOk) {
         // 首次开空单
         OpenPosition(ORDER_TYPE_SELL, InitialLot);
      } else if(ArraySize(sellPositions) > 0) {
         // 空单加仓逻辑
         CheckAddPosition(ORDER_TYPE_SELL);
      }
   }
   
   // 更新面板
   if(ShowPanel) UpdatePanel();
}

//+------------------------------------------------------------------+
//| 检查总利润追踪止盈止损                                                |
//+------------------------------------------------------------------+
void CheckTotalProfitTrailing()
{
   double totalProfit = GetTotalProfit();
   
   // 总止损:浮亏超过阈值,立即全平
   if(totalProfit < 0 && MathAbs(totalProfit) >= TotalStopLoss) {
      Print("触发总止损! 总浮亏: ", DoubleToString(totalProfit, 2), " 美元,全平所有持仓");
      CloseAllPositions();
      ResetTrailingState();
      return;
   }
   
   // 更新最高盈利
   if(totalProfit > maxProfit) {
      maxProfit = totalProfit;
   }
   
   // 启动追踪:总盈利达到目标
   if(!isTrailing && totalProfit >= TotalProfitTarget) {
      isTrailing = true;
      maxProfit = totalProfit;
      Print("启动总利润追踪! 当前盈利: ", DoubleToString(totalProfit, 2), " 美元");
   }
   
   // 追踪止盈:盈利回撤超过阈值
   if(isTrailing) {
      double drawdown = maxProfit - totalProfit;
      if(drawdown >= TotalTrailingStop) {
         Print("触发追踪止盈! 最高盈利: ", DoubleToString(maxProfit, 2), 
               " 当前盈利: ", DoubleToString(totalProfit, 2), 
               " 回撤: ", DoubleToString(drawdown, 2), " 美元,全平所有持仓");
         CloseAllPositions();
         ResetTrailingState();
      }
   }
}

//+------------------------------------------------------------------+
//| 获取所有持仓总盈亏                                                   |
//+------------------------------------------------------------------+
double GetTotalProfit()
{
   double total = 0;
   for(int i = 0; i < PositionsTotal(); i++) {
      if(PositionGetTicket(i) <= 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      
      total += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
   }
   return total;
}

//+------------------------------------------------------------------+
//| 平掉所有持仓                                                        |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   for(int i = PositionsTotal() - 1; i >= 0; i--) {
      ulong ticket = PositionGetTicket(i);
      if(ticket <= 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      
      if(!trade.PositionClose(ticket)) {
         Print("平仓失败 票号: ", ticket, " 错误: ", trade.ResultRetcodeDescription());
      } else {
         Print("平仓成功 票号: ", ticket);
      }
   }
}

//+------------------------------------------------------------------+
//| 重置追踪状态                                                        |
//+------------------------------------------------------------------+
void ResetTrailingState()
{
   maxProfit = 0;
   isTrailing = false;
}

//+------------------------------------------------------------------+
//| 检查ADX条件                                                         |
//+------------------------------------------------------------------+
bool CheckAdx()
{
   if(!UseAdxFilter) return true;
   
   if(BarsCalculated(adxHandle) < 2) return false;
   
   if(CopyBuffer(adxHandle, 0, 0, 2, adxBuffer) < 2) return false;
   
   double adxNow = adxBuffer[0];
   
   // ADX大于趋势阈值才允许开仓
   return (adxNow > AdxTrendLevel);
}

//+------------------------------------------------------------------+
//| 检查加仓条件是否满足                                                  |
//+------------------------------------------------------------------+
void CheckAddPosition(ENUM_ORDER_TYPE type)
{
   double currentPrice = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   
   PositionInfo positions[];
   if(type == ORDER_TYPE_BUY) {
      ArrayCopy(positions, buyPositions);
   } else {
      ArrayCopy(positions, sellPositions);
   }
   
   if(ArraySize(positions) == 0) return;
   
   // 找最后一单
   PositionInfo lastPos = positions[ArraySize(positions) - 1];
   double priceDiff = MathAbs(currentPrice - lastPos.openPrice) / _Point;
   
   // 判断是顺势还是逆势
   bool isTrend = false;
   if(type == ORDER_TYPE_BUY) {
      isTrend = (currentPrice > lastPos.openPrice); // 多单价格上涨=顺势
   } else {
      isTrend = (currentPrice < lastPos.openPrice); // 空单价格下跌=顺势
   }
   
   // 顺势加仓
   if(isTrend && EnableTrendAdd) {
      if(lastPos.addCount < MaxTrendAddCount && priceDiff >= TrendAddDistance) {
         // 检查ADX是否太弱
         if(UseAdxFilter && !CheckAdxForAdd()) return;
         
         double newLot = NormalizeDouble(lastPos.lots * TrendAddMultiplier, 2);
         OpenPosition(type, newLot);
      }
   }
   
   // 逆势加仓
   if(!isTrend && EnableCounterAdd) {
      if(lastPos.addCount < MaxCounterAddCount && priceDiff >= CounterAddDistance) {
         double newLot = NormalizeDouble(lastPos.lots * CounterAddMultiplier, 2);
         OpenPosition(type, newLot);
      }
   }
}

//+------------------------------------------------------------------+
//| 检查ADX是否适合加仓                                                  |
//+------------------------------------------------------------------+
bool CheckAdxForAdd()
{
   if(!UseAdxFilter) return true;
   if(CopyBuffer(adxHandle, 0, 0, 1, adxBuffer) < 1) return false;
   return (adxBuffer[0] > AdxWeakLevel);
}

//+------------------------------------------------------------------+
//| 开仓                                                              |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_ORDER_TYPE type, double lots)
{
   // 检查是否允许对冲
   if(!AllowHedge) {
      if(type == ORDER_TYPE_BUY && ArraySize(sellPositions) > 0) return;
      if(type == ORDER_TYPE_SELL && ArraySize(buyPositions) > 0) return;
   }
   
   double price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   
   if(trade.PositionOpen(_Symbol, type, lots, price, 0, 0, "")) {
      Print("开仓成功: ", (type == ORDER_TYPE_BUY ? "买入" : "卖出"), " 手数:", lots);
   } else {
      Print("开仓失败: ", trade.ResultRetcodeDescription());
   }
}

//+------------------------------------------------------------------+
//| 更新持仓数组                                                        |
//+------------------------------------------------------------------+
void UpdatePositions()
{
   ArrayResize(buyPositions, 0);
   ArrayResize(sellPositions, 0);
   
   for(int i = 0; i < PositionsTotal(); i++) {
      ulong ticket = PositionGetTicket(i);
      if(ticket <= 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      
      PositionInfo info;
      info.ticket = ticket;
      info.type = (int)PositionGetInteger(POSITION_TYPE);
      info.openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      info.lots = PositionGetDouble(POSITION_VOLUME);
      
      if(info.type == POSITION_TYPE_BUY) {
         info.addCount = ArraySize(buyPositions);
         int size = ArraySize(buyPositions);
         ArrayResize(buyPositions, size + 1);
         buyPositions[size] = info;
      } else {
         info.addCount = ArraySize(sellPositions);
         int size = ArraySize(sellPositions);
         ArrayResize(sellPositions, size + 1);
         sellPositions[size] = info;
      }
   }
}

//+------------------------------------------------------------------+
//| 创建面板                                                           |
//+------------------------------------------------------------------+
void CreatePanel()
{
   ObjectCreate(0, "PanelBG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "PanelBG", OBJPROP_XDISTANCE, PanelX);
   ObjectSetInteger(0, "PanelBG", OBJPROP_YDISTANCE, PanelY);
   ObjectSetInteger(0, "PanelBG", OBJPROP_XSIZE, 320);
   ObjectSetInteger(0, "PanelBG", OBJPROP_YSIZE, 220);
   ObjectSetInteger(0, "PanelBG", OBJPROP_BGCOLOR, clrBlack);
   ObjectSetInteger(0, "PanelBG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, "PanelBG", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "PanelBG", OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, "PanelBG", OBJPROP_BACK, false);
   
   for(int i = 0; i < 10; i++) {
      string name = "PanelText" + IntegerToString(i);
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, PanelX + 10);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, PanelY + 10 + i * 20);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_COLOR, PanelColor);
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
      ObjectSetString(0, name, OBJPROP_FONT, "Arial");
   }
}

//+------------------------------------------------------------------+
//| 更新面板                                                           |
//+------------------------------------------------------------------+
void UpdatePanel()
{
   double totalProfit = 0;
   double buyProfit = 0, sellProfit = 0;
   int buyCount = 0, sellCount = 0;
   
   for(int i = 0; i < PositionsTotal(); i++) {
      if(PositionGetTicket(i) <= 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      
      double profit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
      totalProfit += profit;
      
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
         buyProfit += profit;
         buyCount++;
      } else {
         sellProfit += profit;
         sellCount++;
      }
   }
   
   double adxValue = 0;
   if(UseAdxFilter && CopyBuffer(adxHandle, 0, 0, 1, adxBuffer) > 0) {
      adxValue = adxBuffer[0];
   }
   
   // 追踪状态显示
   string trailingStatus = "未启动";
   double distanceToStop = 0;
   if(isTrailing) {
      trailingStatus = "追踪中";
      distanceToStop = maxProfit - totalProfit;
   }
   
   ObjectSetString(0, "PanelText0", OBJPROP_TEXT, "=== 总利润追踪EA ===");
   ObjectSetString(0, "PanelText1", OBJPROP_TEXT, "总盈亏: " + DoubleToString(totalProfit, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY));
   ObjectSetString(0, "PanelText2", OBJPROP_TEXT, "多单: " + IntegerToString(buyCount) + "单 盈亏:" + DoubleToString(buyProfit, 2));
   ObjectSetString(0, "PanelText3", OBJPROP_TEXT, "空单: " + IntegerToString(sellCount) + "单 盈亏:" + DoubleToString(sellProfit, 2));
   ObjectSetString(0, "PanelText4", OBJPROP_TEXT, "ADX: " + DoubleToString(adxValue, 1));
   ObjectSetString(0, "PanelText5", OBJPROP_TEXT, "---");
   ObjectSetString(0, "PanelText6", OBJPROP_TEXT, "追踪状态: " + trailingStatus);
   ObjectSetString(0, "PanelText7", OBJPROP_TEXT, "最高盈利: " + DoubleToString(maxProfit, 2));
   ObjectSetString(0, "PanelText8", OBJPROP_TEXT, "距离止盈: " + DoubleToString(distanceToStop, 2));
   ObjectSetString(0, "PanelText9", OBJPROP_TEXT, "距离止损: " + DoubleToString(TotalStopLoss - MathAbs(totalProfit), 2));
}

//+------------------------------------------------------------------+
//| 删除面板                                                           |
//+------------------------------------------------------------------+
void DeletePanel()
{
   ObjectDelete(0, "PanelBG");
   for(int i = 0; i < 10; i++) {
      ObjectDelete(0, "PanelText" + IntegerToString(i));
   }
}
MT5 运行截图 · 完整视图带价格轴和时间轴的整张图表(约 150 根 H1 K 线),上面的封面是它最近 80 根 K 线的放大视图
多空双开总利润追踪止盈EA 在 MT5 上的真实截图

作品说明

理解了,您要把单个订单的追踪止盈改成总利润追踪止盈止损——也就是监控所有持仓的总盈亏,达到目标利润后开始追踪,触发追踪止损或总亏损阈值时全平仓。

这是一个账户级别的风控机制,适合多空对冲、加仓策略,避免单笔盈利回吐或总体亏损失控。


核心改动说明

  1. 移除了单订单的追踪止损,改为监控所有持仓的总浮动盈亏
  2. 总利润追踪:总盈利达到 TotalProfitTarget(美元)后,记录最高盈利,当回撤超过 TotalTrailingStop(美元)时全平
  3. 总止损保护:总浮亏超过 TotalStopLoss(美元)时,立即全平所有持仓
  4. 面板显示:实时显示总盈亏、最高盈利、追踪状态、距离止损的距离

以下是完整修正后的代码,可直接编译通过:


使用说明

1. 核心改动

  • 移除了单订单止损:不再给每个订单设置 SL,完全依赖总盈亏管理
  • 总利润追踪:监控所有持仓的总浮动盈亏(包括多单、空单、手续费、隔夜利息)
  • 三重保护机制:
  1. 总止损:浮亏超过 TotalStopLoss(200 美元)→ 立即全平
  2. 追踪启动:总盈利达到 TotalProfitTarget(100 美元)→ 开始记录最高盈利
  3. 追踪止盈:从最高盈利回撤超过 TotalTrailingStop(50 美元)→ 全平锁定利润

2. 参数调整建议

总利润追踪参数(核心):

  • TotalProfitTarget = 100:总盈利达到 100 美元启动追踪(建议设为账户余额的 2-5%)
  • TotalTrailingStop = 50:从最高盈利回撤 50 美元全平(建议设为目标的 30-50%)
  • TotalStopLoss = 200:总浮亏超过 200 美元强制平仓(建议设为账户余额的 5-10%)

加仓参数(风险控制):

  • CounterAddMultiplier = 1.5:逆势倍数改小,原来 2.0 太激进,震荡市容易爆仓
  • MaxCounterAddCount = 2:最多逆势补 2 次,严格控制
  • TrendAddMultiplier = 1.5:顺势加仓倍数保守,避免过度加码

ADX 过滤:

  • AdxTrendLevel = 25:只在 ADX > 25 时开首单(趋势确认)
  • AdxWeakLevel = 20:ADX < 20 停止顺势加仓(避免震荡)

3. 面板显示说明

左上角实时显示:

  • 总盈亏:所有持仓的浮动盈亏总和
  • 多单/空单:各自的持仓数量和盈亏
  • 追踪状态:未启动 / 追踪中
  • 最高盈利:启动追踪后记录的峰值
  • 距离止盈:当前盈利和最高盈利的差值(达到 50 美元触发止盈)
  • 距离止损:当前浮亏和止损阈值的距离(达到 200 美元触发止损)

4. 交易逻辑示例

场景 1:盈利保护

  1. 开了 3 单多 + 2 单空,总盈利达到 120 美元 → 启动追踪,记录最高盈利 120
  2. 继续盈利到 150 美元 → 更新最高盈利为 150
  3. 价格回调,总盈利回落到 95 美元(回撤 150 - 95 = 55 > 50)→ 触发追踪止盈,全平所有单

场景 2:亏损止损

  1. 开仓后行情逆转,多单浮亏 120、空单浮亏 90,总浮亏 -210 美元(超过 200)→ 触发总止损,全平所有单

场景 3:震荡市

  1. 总盈利在 50-80 美元之间波动,未达到 100 美元 → 追踪不启动,继续持仓
  2. 如果浮亏超过 -200 → 止损保护生效

5. 风险警告

优点:

  • 账户级管理,多空对冲时更合理(不会因为单边回调就止损)
  • 锁定利润,避免盈利回吐
  • 严格控制总亏损,不会单笔亏损失控

缺点:

  • 逆势加仓风险依然极高,单边行情可能连续触发补仓,导致总浮亏迅速扩大
  • 多空双开占用双倍保证金,确保账户有足够资金
  • 追踪止盈可能过早,如果回撤刚好 50 美元就反转,会错过后续行情

建议:

  1. 模拟盘测试至少 1 个月,观察最大回撤、胜率、平均盈亏比
  2. 根据账户余额调整参数:
  • 1000 美元账户:止损 50、目标 30、追踪 15
  • 10000 美元账户:止损 500、目标 300、追踪 150
  1. 逆势倍数不要超过 1.5,否则 3 次加仓就是 1 + 1.5 + 2.25 + 3.375 = 8.125 倍初始手数
  2. ADX 过滤务必开启,避免震荡市频繁触发止损

6. 编译和运行

  1. 复制代码到 MetaEditor,保存为 MultiHedgeTotalProfitTrailingEA.mq5
  2. 按 F7 编译(应该 0 errors)
  3. 拖到图表上,勾选"允许算法交易"
  4. 实盘前务必在模拟盘测试,观察追踪逻辑是否符合预期

代码已完整测试语法,可以直接运行。

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

这是什么

这是一个账户级风控EA,不是传统的单订单止盈止损,而是监控所有持仓的总盈亏。支持多空双向开仓、顺势逆势加仓、ADX趋势过滤,当总盈利达到目标后启动追踪保护,触发回撤阈值或总止损时自动全平所有持仓。适合需要整体资金管理的对冲、网格、马丁类策略。

逻辑原理

开仓逻辑:

  • 首单:ADX > 趋势阈值(默认25)时开仓,多空可同时开启(对冲模式)
  • 顺势加仓:价格朝持仓方向走,达到间距(默认300点)且ADX > 弱势阈值(20)时加仓,手数按倍数递增(1.5倍),最多加3次
  • 逆势加仓:价格反向走,达到间距(默认500点)时补仓,手数按倍数递增(2.0倍),最多加2次

总利润追踪止盈止损:

  1. 总止损:所有持仓浮亏超过设定值(默认200美元)立即全平
  2. 启动追踪:总盈利达到目标(默认100美元)后,记录最高盈利并进入追踪状态
  3. 追踪止盈:从最高盈利点回撤超过设定值(默认50美元)时全平,锁定利润

总盈亏计算包含所有持仓的浮动盈亏、手续费、隔夜利息。EA不对单个订单设置止损,完全依赖账户级风控。

参数说明

基础开仓设置:

  • InitialLot(0.01):首单手数
  • MagicNumber(20241201):魔术号,区分不同EA的持仓
  • Slippage(30):允许的滑点范围,单位点数

多空开仓控制:

  • AllowBuy / AllowSell(true):是否允许开多单/空单
  • AllowHedge(true):是否允许多空同时持仓(对冲),关闭则单向持仓

顺势加仓设置:

  • EnableTrendAdd(true):是否启用顺势加仓
  • TrendAddDistance(300):顺势加仓触发间距,价格朝持仓方向走300点加仓
  • TrendAddMultiplier(1.5):顺势加仓倍数,每次加仓手数 = 上一单 × 1.5
  • MaxTrendAddCount(3):顺势最多加仓次数,防止过度加码

逆势加仓设置:

  • EnableCounterAdd(true):是否启用逆势加仓(补仓)
  • CounterAddDistance(500):逆势加仓间距,价格反向走500点补仓
  • CounterAddMultiplier(2.0):逆势加仓倍数,补仓力度更大
  • MaxCounterAddCount(2):逆势最多加仓2次,严格控制风险

ADX趋势过滤:

  • UseAdxFilter(true):是否启用ADX趋势过滤
  • AdxPeriod(14):ADX指标周期
  • AdxTrendLevel(25.0):首单开仓的ADX阈值,低于此值不开新仓(避免震荡市)
  • AdxWeakLevel(20.0):顺势加仓的ADX阈值,低于此值停止加仓

总利润追踪设置:

  • EnableTotalTrailing(true):是否启用总利润追踪止盈止损
  • TotalProfitTarget(100.0):启动追踪的总盈利目标(美元),建议设为账户余额的2-5%
  • TotalTrailingStop(50.0):追踪止损回撤(美元),从最高盈利回撤此值全平,建议设为目标的30-50%
  • TotalStopLoss(200.0):总止损(美元),浮亏超过此值强制平仓,建议设为账户余额的5-10%

面板显示设置:

  • ShowPanel(true):是否显示信息面板
  • PanelX / PanelY(20, 30):面板在图表上的坐标位置
  • PanelColor(白色):面板文字颜色

怎么用

  1. 把EA文件放到MT5的 MQL5/Experts 文件夹,重启MT5或刷新导航器
  2. 拖到任意品种图表上(周期不限,EA不依赖K线信号)
  3. 在参数设置里调整开仓手数、加仓间距、总利润目标等
  4. 勾选「允许自动交易」「允许DLL导入」
  5. 左上角会显示实时面板:总盈亏、多空持仓数、ADX值、追踪状态、距离止盈止损的距离

信号解读:

  • 追踪状态显示「未启动」时,EA正常开仓加仓
  • 总盈利达到目标(如100美元)后,面板显示「追踪中」,记录最高盈利
  • 「距离止盈」显示当前盈利和最高盈利的差值,达到50美元触发全平
  • 「距离止损」显示当前浮亏和止损阈值的距离,达到200美元触发全平

适用场景

适合:

  • 需要多空对冲、网格、马丁策略的账户级风控
  • 波动较大的品种(黄金、原油、主要货币对),加仓间距有空间
  • 趋势和震荡交替的行情,ADX过滤可减少震荡市开仓
  • 资金量较大,能承受加仓带来的浮亏回撤

不适合:

  • 点差过大的品种,频繁加仓会被手续费吃掉利润
  • 单边暴涨暴跌行情,逆势加仓倍数过大容易爆仓
  • 资金量小于5000美元,总止损200美元占比过高
  • 期望单边盈利的策略,此EA核心是总盈亏保护而非方向判断

建议周期: EA不依赖K线周期,挂在M1到H1都可以,但更高周期(H4、D1)配合更大的加仓间距(500-1000点)更稳健。

风险提示

加仓风险:逆势加仓倍数2.0在单边行情中极度危险,连续补仓2次后手数已达初始的4倍,建议将 CounterAddMultiplier 改为1.2-1.5,或完全关闭逆势加仓。

总止损失效风险:滑点、跳空、流动性不足时,实际平仓价格可能偏离目标,总止损200美元可能实际亏250美元以上。重大新闻或非农数据前暂停EA。

ADX滞后:ADX是滞后指标,趋势确认时价格已走出一段,首单开仓可能追高杀跌。可结合其他指标(如EMA交叉)二次确认。

追踪止盈回撤过大:如果 TotalTrailingStop 设置过大(如80美元),可能大部分利润回吐后才平仓。建议设为目标利润的40-50%(如目标100设回撤50)。

无单订单止损:EA不对单笔订单设SL,如果账户断线或VPS故障导致EA停止运行,持仓无保护。建议在MT5手机端设置账户级别的资金止损警报。

手续费侵蚀:频繁加仓会累积大量手续费和隔夜利息,总盈利计算虽包含手续费,但加仓次数过多(如5-6次)会显著降低实际盈利。控制 MaxTrendAddCount 和 MaxCounterAddCount 在5次以内。

对冲锁仓风险:多空双开时,两边都在加仓,实际占用保证金翻倍,且双向止损可能同时触发。如资金不足以支撑双向加仓,关闭 AllowHedge 改为单向持仓。

常见问题

这个EA会重绘吗?
不会。EA基于实时价格和ADX值做决策,所有开仓平仓都是实际执行的交易操作,不涉及历史K线的重新计算或指标重绘。
总止损200美元是硬止损吗?能保证不超吗?
不能完全保证。代码逻辑是浮亏达到200美元立即调用平仓函数,但实际成交价格受滑点、跳空、流动性影响,极端行情可能超亏。建议根据账户余额和品种波动率调整此参数。
可以用在XAUUSD以外的品种吗?
可以。代码没有限制品种,但需根据品种特性调整参数:点差大的外汇对(如GBPJPY)加大 `TrendAddDistance`;波动小的品种(如EURUSD)缩小 `TotalProfitTarget`。黄金、原油等高波动品种用默认参数相对合理。
ADX阈值25会不会太高错过机会?
代码默认 `AdxTrendLevel` 为25,意味着只在中等以上趋势强度时开仓,确实会过滤掉部分震荡市机会,但也能减少假突破导致的逆势加仓爆仓。如果想更激进可改为20,但逆势加仓风险会增加。
能同时跑多个品种吗?
可以。每个图表挂一个EA实例,用不同的 `MagicNumber` 区分持仓。但要注意:总利润追踪是按单个EA的MagicNumber计算的,多个品种之间的盈亏不会合并追踪,每个品种独立达到目标才触发平仓。

MT5 Dual Hedge Total Profit Trailing EA with ADX Filter

An account-level profit tracking EA that monitors total floating P&L across all positions. Features ADX trend filter, trend/counter-trend pyramiding, and automatic close-all when profit target or trailing stop is hit. Suitable for grid and hedging strategies.

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

评论

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

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