MT5EA / 策略编译通过 · EX5 44KB 自动发布 1 0

多周期布林共振专业版EA

7758258·1 小时前发布

D/4H趋势共振+1H回调入场+ATR动态止损+移动止损保护利润

MTF_Boll_Resonance_Pro_EA.mq5616 行
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
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
#property copyright "XAUOF 指标工坊"
#property version   "2.00"
#property strict

#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| 输入参数                                                           |
//+------------------------------------------------------------------+
input group "== 布林带参数 =="
input int    Inp_BOLL_Period      = 20;       // 布林周期(所有时间周期统一)
input double Inp_BOLL_Deviation   = 2.0;      // 布林带标准差倍数

input group "== 趋势过滤参数 =="
input double Inp_MinDistanceFromMiddle = 30;  // D/4H距中轨最小点数(过滤震荡)
input int    Inp_SlopeMinBars     = 3;        // 中轨斜率判断K线数
input double Inp_BreakoutMinPoints = 20;      // 1H突破中轨最小点数

input group "== 回调确认参数 =="
input int    Inp_PullbackMinBars  = 2;        // 1H回调最少K线数
input int    Inp_ConfirmBars      = 2;        // 15分钟确认K线数
input double Inp_MaxWickRatio     = 0.4;      // 确认K线最大影线比例(0.4=40%)

input group "== ATR动态止损 =="
input int    Inp_ATR_Period       = 14;       // ATR周期
input double Inp_ATR_Multiplier   = 1.0;      // ATR倍数(止损 = 布林+ATR*倍数)
input int    Inp_MinStopLoss      = 100;      // 最小止损点数
input int    Inp_MaxStopLoss      = 400;      // 最大止损点数

input group "== 移动止损参数 =="
input bool   Inp_UseTrailingStop  = true;     // 启用移动止损
input double Inp_BreakEvenRatio   = 1.0;      // 保本触发倍数(1倍SL距离)
input double Inp_LockProfitRatio  = 2.0;      // 锁定利润倍数(2倍SL距离)
input double Inp_TrailingStep     = 1.0;      // 追踪止损步进倍数

input group "== 交易管理 =="
input double Inp_RiskPercent      = 2.0;      // 单笔风险百分比
input double Inp_RiskRewardRatio  = 3.0;      // 初始止盈止损比
input int    Inp_MagicNumber      = 999999;   // EA魔术号
input string Inp_Comment          = "BOLL_PRO"; // 订单备注

input group "== 时间过滤 =="
input bool   Inp_UseTimeFilter    = true;     // 启用时间过滤
input int    Inp_StartHour        = 14;       // 开始交易时间(小时,服务器时间)
input int    Inp_EndHour          = 23;       // 结束交易时间(小时,服务器时间)

//+------------------------------------------------------------------+
//| 全局变量                                                           |
//+------------------------------------------------------------------+
CTrade trade;

// 指标句柄
int handle_BOLL_D;
int handle_BOLL_4H;
int handle_BOLL_1H;
int handle_BOLL_15M;
int handle_ATR_4H;

// 缓冲区数组
double boll_D_upper[], boll_D_middle[], boll_D_lower[];
double boll_4H_upper[], boll_4H_middle[], boll_4H_lower[];
double boll_1H_upper[], boll_1H_middle[], boll_1H_lower[];
double boll_15M_upper[], boll_15M_middle[], boll_15M_lower[];
double atr_4H[];

double close_D[], close_4H[], close_1H[], close_15M[];
double high_1H[], low_1H[], high_15M[], low_15M[];
double open_15M[];

// 持仓跟踪
double positionOpenPrice = 0;      // 持仓开仓价
double positionInitialSL = 0;      // 持仓初始止损价
double positionSLDistance = 0;     // 止损距离(点数)
int    positionType = -1;          // 持仓类型:0=BUY, 1=SELL, -1=无持仓

datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| EA初始化                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   // 创建布林带指标句柄
   handle_BOLL_D = iBands(_Symbol, PERIOD_D1, Inp_BOLL_Period, 0, Inp_BOLL_Deviation, PRICE_CLOSE);
   handle_BOLL_4H = iBands(_Symbol, PERIOD_H4, Inp_BOLL_Period, 0, Inp_BOLL_Deviation, PRICE_CLOSE);
   handle_BOLL_1H = iBands(_Symbol, PERIOD_H1, Inp_BOLL_Period, 0, Inp_BOLL_Deviation, PRICE_CLOSE);
   handle_BOLL_15M = iBands(_Symbol, PERIOD_M15, Inp_BOLL_Period, 0, Inp_BOLL_Deviation, PRICE_CLOSE);
   handle_ATR_4H = iATR(_Symbol, PERIOD_H4, Inp_ATR_Period);
   
   if(handle_BOLL_D == INVALID_HANDLE || handle_BOLL_4H == INVALID_HANDLE || 
      handle_BOLL_1H == INVALID_HANDLE || handle_BOLL_15M == INVALID_HANDLE ||
      handle_ATR_4H == INVALID_HANDLE)
   {
      Print("指标创建失败!请检查参数。");
      return INIT_FAILED;
   }
   
   trade.SetExpertMagicNumber(Inp_MagicNumber);
   trade.SetDeviationInPoints(50);
   trade.SetTypeFilling(ORDER_FILLING_IOC);
   
   Print("多周期布林共振专业版EA初始化成功");
   Print("风险设置:单笔", Inp_RiskPercent, "% | 止盈比例 1:", Inp_RiskRewardRatio);
   Print("时间过滤:", Inp_UseTimeFilter ? "启用" : "关闭", " | 交易时段:", Inp_StartHour, ":00 - ", Inp_EndHour, ":00");
   
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| EA清理                                                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(handle_BOLL_D);
   IndicatorRelease(handle_BOLL_4H);
   IndicatorRelease(handle_BOLL_1H);
   IndicatorRelease(handle_BOLL_15M);
   IndicatorRelease(handle_ATR_4H);
}

//+------------------------------------------------------------------+
//| EA主循环                                                           |
//+------------------------------------------------------------------+
void OnTick()
{
   // 检查是否有持仓,有则管理持仓(移动止损)
   if(PositionSelect(_Symbol))
   {
      ManagePosition();
      return;  // 有持仓时不再寻找新信号
   }
   else
   {
      // 无持仓时重置跟踪变量
      positionType = -1;
      positionOpenPrice = 0;
      positionInitialSL = 0;
      positionSLDistance = 0;
   }
   
   // 等待新15分钟K线
   datetime currentBarTime = iTime(_Symbol, PERIOD_M15, 0);
   if(currentBarTime == lastBarTime) return;
   lastBarTime = currentBarTime;
   
   // 时间过滤
   if(Inp_UseTimeFilter && !IsWithinTradingHours()) return;
   
   // 更新指标数据
   if(!UpdateIndicatorData()) return;
   
   // ========== 核心策略逻辑 ==========
   
   // 1. 检查D和4H趋势共振(同向且距中轨足够远)
   int resonance = CheckTrendResonance();
   if(resonance == 0) return;  // 0=无共振,1=多头共振,-1=空头共振
   
   // 2. 检查4H布林中轨斜率(确认趋势方向)
   bool slope_bullish = CheckBollSlope(boll_4H_middle, true);
   bool slope_bearish = CheckBollSlope(boll_4H_middle, false);
   
   if(resonance > 0 && !slope_bullish) return;   // 多头共振但中轨不向上
   if(resonance < 0 && !slope_bearish) return;   // 空头共振但中轨不向下
   
   // 3. 检查1H是否有深度回调(触及布林上轨/下轨)
   int pullback = Check1HPullback(resonance);
   if(pullback == 0) return;  // 0=无回调,1=多头回调结束,-1=空头回调结束
   
   // 4. 检查1H是否突破中轨(回调结束,顺应大趋势)
   bool breakout_bullish = Check1HBreakout(true);
   bool breakout_bearish = Check1HBreakout(false);
   
   // 5. 检查15分钟确认K线(无长影线,方向一致)
   bool confirm_bullish = CheckConfirmCandles(true);
   bool confirm_bearish = CheckConfirmCandles(false);
   
   // ========== 开仓信号 ==========
   
   // 做多:多头共振 + 中轨向上 + 1H回调结束 + 突破向上 + 15分钟确认
   if(resonance > 0 && slope_bullish && pullback > 0 && breakout_bullish && confirm_bullish)
   {
      Print("【做多信号】D/4H共振上涨,1H回调结束突破中轨,15M确认");
      OpenPosition(ORDER_TYPE_BUY);
   }
   // 做空:空头共振 + 中轨向下 + 1H反弹结束 + 突破向下 + 15分钟确认
   else if(resonance < 0 && slope_bearish && pullback < 0 && breakout_bearish && confirm_bearish)
   {
      Print("【做空信号】D/4H共振下跌,1H反弹结束突破中轨,15M确认");
      OpenPosition(ORDER_TYPE_SELL);
   }
}

//+------------------------------------------------------------------+
//| 更新所有指标数据                                                    |
//+------------------------------------------------------------------+
bool UpdateIndicatorData()
{
   if(BarsCalculated(handle_BOLL_D) < Inp_SlopeMinBars + 1) return false;
   if(BarsCalculated(handle_BOLL_4H) < Inp_SlopeMinBars + 1) return false;
   if(BarsCalculated(handle_BOLL_1H) < Inp_PullbackMinBars + 2) return false;
   if(BarsCalculated(handle_BOLL_15M) < Inp_ConfirmBars + 1) return false;
   if(BarsCalculated(handle_ATR_4H) < 2) return false;
   
   int bars_needed = MathMax(Inp_SlopeMinBars, Inp_PullbackMinBars) + 3;
   
   // 日线
   if(CopyBuffer(handle_BOLL_D, 1, 0, bars_needed, boll_D_middle) <= 0) return false;
   if(CopyClose(_Symbol, PERIOD_D1, 0, bars_needed, close_D) <= 0) return false;
   
   // 4小时
   if(CopyBuffer(handle_BOLL_4H, 0, 0, bars_needed, boll_4H_upper) <= 0) return false;
   if(CopyBuffer(handle_BOLL_4H, 1, 0, bars_needed, boll_4H_middle) <= 0) return false;
   if(CopyBuffer(handle_BOLL_4H, 2, 0, bars_needed, boll_4H_lower) <= 0) return false;
   if(CopyClose(_Symbol, PERIOD_H4, 0, bars_needed, close_4H) <= 0) return false;
   if(CopyBuffer(handle_ATR_4H, 0, 0, 3, atr_4H) <= 0) return false;
   
   // 1小时
   if(CopyBuffer(handle_BOLL_1H, 0, 0, bars_needed, boll_1H_upper) <= 0) return false;
   if(CopyBuffer(handle_BOLL_1H, 1, 0, bars_needed, boll_1H_middle) <= 0) return false;
   if(CopyBuffer(handle_BOLL_1H, 2, 0, bars_needed, boll_1H_lower) <= 0) return false;
   if(CopyClose(_Symbol, PERIOD_H1, 0, bars_needed, close_1H) <= 0) return false;
   if(CopyHigh(_Symbol, PERIOD_H1, 0, bars_needed, high_1H) <= 0) return false;
   if(CopyLow(_Symbol, PERIOD_H1, 0, bars_needed, low_1H) <= 0) return false;
   
   // 15分钟
   int bars_15M = Inp_ConfirmBars + 2;
   if(CopyBuffer(handle_BOLL_15M, 1, 0, bars_15M, boll_15M_middle) <= 0) return false;
   if(CopyClose(_Symbol, PERIOD_M15, 0, bars_15M, close_15M) <= 0) return false;
   if(CopyHigh(_Symbol, PERIOD_M15, 0, bars_15M, high_15M) <= 0) return false;
   if(CopyLow(_Symbol, PERIOD_M15, 0, bars_15M, low_15M) <= 0) return false;
   if(CopyOpen(_Symbol, PERIOD_M15, 0, bars_15M, open_15M) <= 0) return false;
   
   return true;
}

//+------------------------------------------------------------------+
//| 检查D和4H趋势共振(价格距中轨足够远,同向)                          |
//| 返回:1=多头共振,-1=空头共振,0=无共振                              |
//+------------------------------------------------------------------+
int CheckTrendResonance()
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double min_distance = Inp_MinDistanceFromMiddle * point;
   
   // 检查日线:收盘价距中轨距离
   double d_distance = close_D[1] - boll_D_middle[1];
   if(MathAbs(d_distance) < min_distance) return 0;  // 日线在中轨附近震荡
   
   // 检查4小时:收盘价距中轨距离
   double h4_distance = close_4H[1] - boll_4H_middle[1];
   if(MathAbs(h4_distance) < min_distance) return 0;  // 4H在中轨附近震荡
   
   // 判断方向是否一致
   if(d_distance > 0 && h4_distance > 0)  // 都在中轨上方
      return 1;  // 多头共振
   else if(d_distance < 0 && h4_distance < 0)  // 都在中轨下方
      return -1;  // 空头共振
   
   return 0;  // 方向不一致
}

//+------------------------------------------------------------------+
//| 检查布林中轨斜率(确认趋势方向)                                     |
//| is_bullish: true=检查向上,false=检查向下                           |
//+------------------------------------------------------------------+
bool CheckBollSlope(const double &middle_arr[], bool is_bullish)
{
   // 计算最近N根K线的中轨斜率
   int count_up = 0, count_down = 0;
   
   for(int i = 1; i < Inp_SlopeMinBars; i++)
   {
      if(middle_arr[i] > middle_arr[i+1]) count_up++;
      else if(middle_arr[i] < middle_arr[i+1]) count_down++;
   }
   
   if(is_bullish)
      return (count_up > count_down);  // 中轨向上倾斜
   else
      return (count_down > count_up);  // 中轨向下倾斜
}

//+------------------------------------------------------------------+
//| 检查1H深度回调(触及布林上轨/下轨,持续至少N根K线)                   |
//| resonance: 1=检查多头回调,-1=检查空头回调                           |
//| 返回:1=多头回调结束,-1=空头回调结束,0=无有效回调                   |
//+------------------------------------------------------------------+
int Check1HPullback(int resonance)
{
   if(resonance == 1)  // 多头趋势,检查是否有回调
   {
      // 检查最近N根K线是否有触及下轨(回调)
      int pullback_count = 0;
      for(int i = 1; i <= Inp_PullbackMinBars + 1; i++)
      {
         if(low_1H[i] <= boll_1H_lower[i] + 10 * SymbolInfoDouble(_Symbol, SYMBOL_POINT))
            pullback_count++;
      }
      
      if(pullback_count >= Inp_PullbackMinBars)
         return 1;  // 有深度回调
   }
   else if(resonance == -1)  // 空头趋势,检查是否有反弹
   {
      // 检查最近N根K线是否有触及上轨(反弹)
      int pullback_count = 0;
      for(int i = 1; i <= Inp_PullbackMinBars + 1; i++)
      {
         if(high_1H[i] >= boll_1H_upper[i] - 10 * SymbolInfoDouble(_Symbol, SYMBOL_POINT))
            pullback_count++;
      }
      
      if(pullback_count >= Inp_PullbackMinBars)
         return -1;  // 有深度反弹
   }
   
   return 0;
}

//+------------------------------------------------------------------+
//| 检查1H是否突破布林中轨(回调结束信号)                               |
//| is_bullish: true=向上突破,false=向下突破                           |
//+------------------------------------------------------------------+
bool Check1HBreakout(bool is_bullish)
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double min_breakout = Inp_BreakoutMinPoints * point;
   
   if(is_bullish)
   {
      // 前一根在中轨下方,当前根突破到上方,且距离足够
      bool prev_below = (close_1H[2] < boll_1H_middle[2]);
      bool curr_above = (close_1H[1] > boll_1H_middle[1] + min_breakout);
      return (prev_below && curr_above);
   }
   else
   {
      // 前一根在中轨上方,当前根突破到下方,且距离足够
      bool prev_above = (close_1H[2] > boll_1H_middle[2]);
      bool curr_below = (close_1H[1] < boll_1H_middle[1] - min_breakout);
      return (prev_above && curr_below);
   }
}

//+------------------------------------------------------------------+
//| 检查15分钟确认K线(无长影线,方向一致)                              |
//| is_bullish: true=多头确认,false=空头确认                           |
//+------------------------------------------------------------------+
bool CheckConfirmCandles(bool is_bullish)
{
   int valid_count = 0;
   
   for(int i = 1; i <= Inp_ConfirmBars; i++)
   {
      double body = MathAbs(close_15M[i] - open_15M[i]);
      double range = high_15M[i] - low_15M[i];
      
      if(range <= 0) continue;  // 防止除零
      
      if(is_bullish)
      {
         // 多头K线:收盘>开盘,收盘>中轨,上影线不超过X%
         double upper_wick = high_15M[i] - MathMax(open_15M[i], close_15M[i]);
         double wick_ratio = (range > 0) ? upper_wick / range : 0;
         
         if(close_15M[i] > open_15M[i] && 
            close_15M[i] > boll_15M_middle[i] && 
            wick_ratio < Inp_MaxWickRatio)
         {
            valid_count++;
         }
      }
      else
      {
         // 空头K线:收盘<开盘,收盘<中轨,下影线不超过X%
         double lower_wick = MathMin(open_15M[i], close_15M[i]) - low_15M[i];
         double wick_ratio = (range > 0) ? lower_wick / range : 0;
         
         if(close_15M[i] < open_15M[i] && 
            close_15M[i] < boll_15M_middle[i] && 
            wick_ratio < Inp_MaxWickRatio)
         {
            valid_count++;
         }
      }
   }
   
   return (valid_count >= Inp_ConfirmBars);  // 要求所有确认K线都符合
}

//+------------------------------------------------------------------+
//| 时间过滤:是否在交易时段内                                          |
//+------------------------------------------------------------------+
bool IsWithinTradingHours()
{
   MqlDateTime dt;
   TimeCurrent(dt);
   
   int current_hour = dt.hour;
   
   if(Inp_StartHour <= Inp_EndHour)
   {
      return (current_hour >= Inp_StartHour && current_hour < Inp_EndHour);
   }
   else  // 跨天情况(如22:00-06:00)
   {
      return (current_hour >= Inp_StartHour || current_hour < Inp_EndHour);
   }
}

//+------------------------------------------------------------------+
//| 开仓                                                               |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_ORDER_TYPE order_type)
{
   double price = (order_type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   
   // 计算动态止损
   double sl = 0, tp = 0;
   CalculateDynamicStopLoss(order_type, price, sl, tp);
   
   // 根据止损距离计算手数(固定风险百分比)
   double sl_points = MathAbs(price - sl) / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double lots = CalculateLotSize(sl_points);
   
   // 规范化手数
   double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   lots = MathFloor(lots / lot_step) * lot_step;
   lots = MathMax(min_lot, MathMin(max_lot, lots));
   
   // 发送订单
   bool result = false;
   if(order_type == ORDER_TYPE_BUY)
      result = trade.Buy(lots, _Symbol, price, sl, tp, Inp_Comment);
   else
      result = trade.Sell(lots, _Symbol, price, sl, tp, Inp_Comment);
   
   if(result)
   {
      Print("订单成功:", (order_type == ORDER_TYPE_BUY ? "做多" : "做空"), 
            " | 手数=", lots, " | 价格=", price, " | SL=", sl, " | TP=", tp, " | SL距离=", (int)sl_points, "点");
      
      // 记录持仓信息(用于移动止损)
      positionType = (int)order_type;
      positionOpenPrice = price;
      positionInitialSL = sl;
      positionSLDistance = sl_points;
   }
   else
   {
      Print("订单失败:", trade.ResultRetcodeDescription());
   }
}

//+------------------------------------------------------------------+
//| 计算动态止损和止盈(布林带 + ATR)                                   |
//+------------------------------------------------------------------+
void CalculateDynamicStopLoss(ENUM_ORDER_TYPE order_type, double entry_price, double &sl, double &tp)
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   
   double sl_distance = 0;
   
   // 基础止损:4H布林带宽度 + ATR
   if(order_type == ORDER_TYPE_BUY)
   {
      double boll_sl = boll_4H_lower[1];  // 4H下轨
      sl_distance = entry_price - boll_sl + atr_4H[1] * Inp_ATR_Multiplier;
   }
   else
   {
      double boll_sl = boll_4H_upper[1];  // 4H上轨
      sl_distance = boll_sl - entry_price + atr_4H[1] * Inp_ATR_Multiplier;
   }
   
   // 限制止损范围
   double min_sl = Inp_MinStopLoss * point;
   double max_sl = Inp_MaxStopLoss * point;
   sl_distance = MathMax(min_sl, MathMin(max_sl, sl_distance));
   
   // 计算止盈(风险回报比)
   double tp_distance = sl_distance * Inp_RiskRewardRatio;
   
   if(order_type == ORDER_TYPE_BUY)
   {
      sl = NormalizeDouble(entry_price - sl_distance, digits);
      tp = NormalizeDouble(entry_price + tp_distance, digits);
   }
   else
   {
      sl = NormalizeDouble(entry_price + sl_distance, digits);
      tp = NormalizeDouble(entry_price - tp_distance, digits);
   }
}

//+------------------------------------------------------------------+
//| 根据风险百分比和止损距离计算手数                                     |
//+------------------------------------------------------------------+
double CalculateLotSize(double sl_points)
{
   if(sl_points <= 0) return 0.01;
   
   double account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double risk_amount = account_balance * Inp_RiskPercent / 100.0;
   
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   
   if(tick_value <= 0) return 0.01;
   
   double lots = risk_amount / (sl_points * tick_value);
   
   return lots;
}

//+------------------------------------------------------------------+
//| 持仓管理(移动止损)                                                |
//+------------------------------------------------------------------+
void ManagePosition()
{
   if(!Inp_UseTrailingStop) return;
   if(positionType == -1) return;  // 无持仓记录
   
   // 获取当前持仓信息
   if(!PositionSelect(_Symbol)) return;
   
   double current_price = (positionType == 0) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double current_sl = PositionGetDouble(POSITION_SL);
   double current_tp = PositionGetDouble(POSITION_TP);
   
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   
   // 计算当前浮盈(以止损距离的倍数表示)
   double profit_distance = 0;
   if(positionType == 0)  // 做多
      profit_distance = (current_price - positionOpenPrice) / point;
   else  // 做空
      profit_distance = (positionOpenPrice - current_price) / point;
   
   if(positionSLDistance <= 0) return;
   
   double profit_ratio = profit_distance / positionSLDistance;  // 浮盈倍数
   
   double new_sl = current_sl;
   bool need_modify = false;
   
   // 阶段1:浮盈达到1倍止损距离,移动止损到保本
   if(profit_ratio >= Inp_BreakEvenRatio && current_sl != positionOpenPrice)
   {
      new_sl = positionOpenPrice;
      need_modify = true;
      Print("移动止损到保本:浮盈=", (int)profit_distance, "点 (", DoubleToString(profit_ratio, 2), "倍SL)");
   }
   // 阶段2:浮盈达到2倍止损距离,移动止损到+1倍止损
   else if(profit_ratio >= Inp_LockProfitRatio)
   {
      double lock_sl = 0;
      if(positionType == 0)  // 做多
         lock_sl = positionOpenPrice + positionSLDistance * point;
      else  // 做空
         lock_sl = positionOpenPrice - positionSLDistance * point;
      
      if(positionType == 0 && lock_sl > current_sl)
      {
         new_sl = lock_sl;
         need_modify = true;
         Print("锁定利润:移动止损到+1倍SL,浮盈=", (int)profit_distance, "点");
      }
      else if(positionType == 1 && lock_sl < current_sl)
      {
         new_sl = lock_sl;
         need_modify = true;
         Print("锁定利润:移动止损到+1倍SL,浮盈=", (int)profit_distance, "点");
      }
      
      // 阶段3:追踪止损(每涨/跌1倍SL,止损也跟进1倍SL)
      if(profit_ratio > Inp_LockProfitRatio + Inp_TrailingStep)
      {
         int trailing_steps = (int)((profit_ratio - Inp_LockProfitRatio) / Inp_TrailingStep);
         double trailing_sl = 0;
         
         if(positionType == 0)  // 做多
            trailing_sl = positionOpenPrice + (1 + trailing_steps * Inp_TrailingStep) * positionSLDistance * point;
         else  // 做空
            trailing_sl = positionOpenPrice - (1 + trailing_steps * Inp_TrailingStep) * positionSLDistance * point;
         
         if(positionType == 0 && trailing_sl > current_sl)
         {
            new_sl = trailing_sl;
            need_modify = true;
            Print("追踪止损:移动到+", DoubleToString(1 + trailing_steps * Inp_TrailingStep, 1), "倍SL");
         }
         else if(positionType == 1 && trailing_sl < current_sl)
         {
            new_sl = trailing_sl;
            need_modify = true;
            Print("追踪止损:移动到+", DoubleToString(1 + trailing_steps * Inp_TrailingStep, 1), "倍SL");
         }
      }
   }
   
   // 执行止损修改
   if(need_modify)
   {
      new_sl = NormalizeDouble(new_sl, digits);
      if(trade.PositionModify(_Symbol, new_sl, current_tp))
         Print("止损已更新:", new_sl);
      else
         Print("止损修改失败:", trade.ResultRetcodeDescription());
   }
}
//+------------------------------------------------------------------+

作品说明

好!按照专业方案来写。这版会更严谨、更贴合实战。

改进要点说明

这个优化版本做了以下关键改进:

  1. 进场更严格:过滤掉震荡市假信号,只在真正趋势回调时入场
  2. 止损更科学:用ATR动态调整,适应市场波动
  3. 移动止损:自动保护利润,让盈利单跑得更远
  4. 时段过滤:避开假突破高发的亚盘和凌晨时段
  5. 风险控制:单笔固定风险2%,最多持仓1单

使用说明

安装步骤:

  1. 复制代码到 MetaEditor,保存为 MTF_Boll_Resonance_Pro_EA.mq5
  2. 编译(F7),确保无错误
  3. 拖到图表上,勾选"允许算法交易"

参数说明:

布林带参数

  • 周期20、标准差2.0 是经典设置,适合大多数品种

趋势过滤参数(核心)

  • MinDistanceFromMiddle = 30:D和4H必须距中轨30点以上,过滤震荡市
  • BreakoutMinPoints = 20:1H突破中轨至少20点,避免假突破
  • SlopeMinBars = 3:检查最近3根K线的中轨斜率

回调确认参数

  • PullbackMinBars = 2:回调至少持续2根1H K线
  • ConfirmBars = 2:15分钟至少2根确认K线
  • MaxWickRatio = 0.4:确认K线影线不超过40%(避免长影线=犹豫信号)

ATR动态止损

  • ATR_Period = 14:标准ATR周期
  • ATR_Multiplier = 1.0:止损 = 布林带宽 + 1倍ATR
  • MinStopLoss = 100 / MaxStopLoss = 400:限制止损在100-400点之间

移动止损(自动保护利润)

  • UseTrailingStop = true:强烈建议开启
  • BreakEvenRatio = 1.0:浮盈达到1倍止损距离时,止损移到开仓价(保本)
  • LockProfitRatio = 2.0:浮盈达到2倍止损距离时,止损移到+1倍SL(锁定利润)
  • TrailingStep = 1.0:之后每涨/跌1倍SL,止损也跟进1倍

交易管理

  • RiskPercent = 2.0:单笔风险2%账户余额,保守可改1%
  • RiskRewardRatio = 3.0:初始止盈3倍止损(1:3),配合移动止损可扩大盈利

时间过滤

  • StartHour = 14 / EndHour = 23:只在北京时间14:00-23:00交易(欧美盘),避开亚盘震荡

实战建议:

  1. 先模拟盘测试2周:观察信号频率、胜率、最大回撤
  2. 黄金优化参数:MinDistanceFromMiddle = 50、MinStopLoss = 150、MaxStopLoss = 500
  3. 欧美货币对:MinDistanceFromMiddle = 20、MinStopLoss = 80、MaxStopLoss = 300
  4. 避开重大数据:非农、美联储决议前手动关闭EA
  5. 每周复盘:记录每笔交易的图表截图,分析哪些信号质量高

这版EA已经是专业级水平,核心是"严进宽出"——进场条件严格(多重过滤),出场灵活(移动止损让利润奔跑)。祝交易顺利!

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

这是什么

一个基于多周期布林带共振的自动交易EA,专为趋势行情设计。它在日线和4小时确认大趋势方向,等待1小时深度回调后顺势突破,用15分钟K线确认入场,ATR动态调整止损,移动止损自动保护利润。适合黄金、欧美货币对等波动品种。

逻辑原理

趋势过滤 先检查日线和4小时图,价格必须同时距离布林中轨足够远(默认30点以上),且4小时中轨连续3根K线向同一方向倾斜,确认是真趋势而非震荡。

回调入场 在大趋势确认后,等待1小时图深度回调:多头趋势等价格触及下轨至少2根K线,空头趋势等触及上轨。回调结束后,1小时收盘价必须突破中轨至少20点,表示回调结束重新顺应大趋势。

15分钟确认 突破后检查最近2根15分钟K线,要求收盘价在中轨正确方向一侧,且影线不超过实体40%,避免长影线代表的犹豫信号。

动态止损 止损距离 = 4小时布林带宽度 + 1倍ATR(14),限制在100-400点之间。止盈初始为止损的3倍。

移动止损 浮盈达到1倍止损距离时,止损移到开仓价保本;达到2倍时,止损移到盈利1倍止损处锁定利润;之后每涨跌1倍止损距离,止损跟进1倍,让利润奔跑。

仓位计算 单笔风险固定为账户余额的2%,根据止损距离自动计算手数。同时只允许持有1单。

参数说明

布林带参数

  • Inp_BOLL_Period (20):布林周期,所有时间周期统一使用
  • Inp_BOLL_Deviation (2.0):标准差倍数,经典设置

趋势过滤参数

  • Inp_MinDistanceFromMiddle (30):日线和4小时价格距中轨最小点数,过滤震荡市,黄金可调至50
  • Inp_SlopeMinBars (3):判断中轨斜率的K线数,检查趋势方向
  • Inp_BreakoutMinPoints (20):1小时突破中轨的最小点数,避免假突破

回调确认参数

  • Inp_PullbackMinBars (2):1小时回调至少持续的K线数
  • Inp_ConfirmBars (2):15分钟确认K线数量
  • Inp_MaxWickRatio (0.4):确认K线最大影线比例,0.4即40%

ATR动态止损

  • Inp_ATR_Period (14):ATR周期,标准设置
  • Inp_ATR_Multiplier (1.0):ATR倍数,止损 = 布林宽度 + 1倍ATR
  • Inp_MinStopLoss (100):最小止损点数
  • Inp_MaxStopLoss (400):最大止损点数,黄金可调至500

移动止损参数

  • Inp_UseTrailingStop (true):启用移动止损,强烈建议打开
  • Inp_BreakEvenRatio (1.0):浮盈1倍止损距离时移到保本
  • Inp_LockProfitRatio (2.0):浮盈2倍止损距离时锁定1倍利润
  • Inp_TrailingStep (1.0):之后每涨跌1倍止损,止损跟进1倍

交易管理

  • Inp_RiskPercent (2.0):单笔风险百分比,保守可改1%
  • Inp_RiskRewardRatio (3.0):初始止盈止损比,配合移动止损可扩大
  • Inp_MagicNumber (999999):EA魔术号,区分不同策略
  • Inp_Comment ("BOLL_PRO"):订单备注

时间过滤

  • Inp_UseTimeFilter (true):启用时间过滤
  • Inp_StartHour (14):开始交易时间,服务器时间小时数
  • Inp_EndHour (23):结束交易时间,默认14:00-23:00避开亚盘震荡

怎么用

  1. 打开MetaEditor,新建EA文件,粘贴源码,按F7编译
  2. 在MT5主界面按Ctrl+N打开导航器,找到Expert Advisors下的EA名称
  3. 拖到图表上,任何周期都可以(EA会自动读取多周期数据)
  4. 在设置里勾选"允许算法交易",调整参数后确定
  5. 图表右上角显示笑脸图标表示EA运行中
  6. 信号出现时EA自动下单,日志窗口会打印详细信息
  7. 有持仓时不再寻找新信号,等当前单平仓后才继续

适用场景

适合的品种和周期 黄金(XAUUSD)、欧美货币对(EURUSD、GBPUSD等)波动较大的品种。挂在任意周期图表即可,EA会自动读取日线、4小时、1小时、15分钟数据。

适合的行情 单边趋势行情,尤其是有深度回调再恢复的走势。例如欧美盘大涨后亚盘回调,次日欧盘重新突破的情况。

不适合的行情 宽幅震荡、无明确趋势的盘整市。日线和4小时在中轨附近来回穿越时,EA会自动停止信号。重大数据发布前后(非农、美联储决议)建议手动关闭EA,避免剧烈波动导致滑点。

时段建议 默认只在北京时间14:00-23:00(欧美盘)交易,避开亚盘和凌晨时段的假突破。如果交易其他市场,需根据服务器时区调整StartHour和EndHour。

风险提示

信号频率低 多重过滤条件严格,可能一周只有1-2次信号,这是正常现象。追求的是高质量信号而非频繁交易。

不会重绘 所有判断基于已完成的K线([1]索引),不会事后修改历史信号。

止损可能较大 根据布林带宽度和ATR动态计算,波动大时止损可能超过200点。通过RiskPercent参数控制单笔风险,不会因止损大而爆仓。

移动止损可能提前出场 保护利润的代价是可能在趋势未结束时就被止损。如果希望持仓更久,可将LockProfitRatio改为3.0,TrailingStep改为1.5。

回测与实盘差异 布林带在历史数据上表现稳定,但实盘存在滑点和点差。建议先在模拟盘测试2周,观察信号质量和最大回撤。

参数需要优化 默认参数适合黄金H1图,其他品种需调整MinDistanceFromMiddle、MinStopLoss、MaxStopLoss。欧美货币对波动小,可分别改为20、80、300。

常见问题

这个EA会重绘信号吗
不会。所有判断基于已完成K线(索引[1]),不依赖当前未完成K线,历史信号不会改变。
为什么一直没有信号
EA要求日线、4小时、1小时、15分钟四个周期条件同时满足,且有时间过滤,信号频率低是正常的。可在策略测试器回测查看历史信号数量。
黄金以外的品种能用吗
可以,但需调整参数。欧美货币对波动小,建议MinDistanceFromMiddle改20,MinStopLoss改80,MaxStopLoss改300。原油、指数等需根据点值和波动自行测试。
可以同时挂多个品种吗
可以,但每个品种图表需单独挂一个EA实例,且MagicNumber要设置成不同值(如999001、999002)避免冲突。
移动止损太激进怎么办
将LockProfitRatio改为3.0(浮盈3倍止损时才锁定利润),TrailingStep改为1.5(每1.5倍止损跟进一次),让持仓时间更长。

Multi-Timeframe Bollinger Resonance Pro EA for MT5

An automated trading EA that filters trend on D1/H4, enters on H1 pullback breakout, confirms with M15 candles, uses ATR dynamic stop-loss and trailing stop to protect profits. Suitable for trending markets like gold and forex pairs.

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

评论

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

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