MT4指标编译通过 · EX4 47KB 自动发布 43 0

黄金追涨杀跌高级策略EA

luoye·6 天前发布

严格趋势+多级确认,越涨越买越跌越卖,智能风控,图表驱动

黄金追涨杀跌高级策略EA

效果示意图 · AI 根据源码绘制,仅示意画了哪些元素,细节以实际运行为准

XAUUSD_SAR_MA_EA.mq4731 行
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
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
#property copyright "XAUUSD Advanced System"
#property version   "2.10"
#property strict
#property description "基于图表分析优化:均线排列确认+趋势强度评估+动态止盈"

// ============ 输入参数 ============
input double   InitialLots      = 0.01;         // 初始手数
input int      MaxOpenTrades    = 12;           // 最多持仓单数
input double   LotMultiplier    = 1.5;          // 手数倍增系数
input bool     UseTimeFilter    = true;         // 交易时间过滤
input int      StartHour        = 8;            // 开始小时
input int      EndHour          = 22;           // 结束小时

// ========== 趋势确认参数(关键改进)==========
input int      MA5Period        = 5;            // MA5周期
input int      MA15Period       = 15;           // MA15周期
input int      MA30Period       = 30;           // MA30周期
input double   MinTrendSpread   = 15.0;         // 最小趋势强度 点数(推荐 10-20)
input double   StrongTrendSpread = 30.0;        // 强趋势强度 点数(推荐 25-40)

// ========== 加仓参数 ==========
input int      AddPositionPoints = 60;          // 每涨/跌多少点加仓(推荐 40-80)
input int      MinAddInterval   = 2;            // 最小加仓间隔(分钟)
input bool     AggressiveMode   = true;         // 激进模式

// ========== 止损止盈参数 ==========
input int      StopLossPoints   = 120;          // 固定止损点数(根据波动率调整)
input int      DynamicTPPoints  = 250;          // 动态止盈点数(会根据持仓调整)
input int      BreakEvenPoints  = 70;           // 达到此点移动止损到成本
input int      TrailingDistance = 35;           // 追踪止盈距离
input int      TrailingStep     = 8;            // 追踪止盈步进

// ========== 动态止盈参数 ==========
input bool     UseDynamicTP     = true;         // 启用动态止盈
input double   ProfitTarget1    = 3.0;          // 第一目标 % - 快速获利
input double   ProfitTarget2    = 8.0;          // 第二目标 % - 中期获利
input double   ProfitTarget3    = 15.0;         // 第三目标 % - 大额获利
input double   PartialClosePercent = 40.0;      // 部分平仓比例

// ========== 风控参数 ==========
input double   MaxMarginPercent = 65.0;         // 最大保证金率
input double   MaxDrawdownPercent = 10.0;       // 最大回撤
input int      MaxConsecutiveLosses = 3;        // 最大连续亏损笔数
input bool     ShowPanel        = true;         // 显示面板
input int      MagicNumber      = 20240301;     // EA魔术号

// ============ 全局变量 ============
datetime       lastBuyOrderTime = 0;
datetime       lastSellOrderTime = 0;
double         lastBuyPrice = 0;
double         lastSellPrice = 0;
double         highestEquity = 0;
double         initialBalance = 0;
bool           profitLocked1 = false;
bool           profitLocked2 = false;
int            consecutiveLosses = 0;

// 面板相关
string         PANEL_PREFIX = "XAUUSD_Panel_";
int            currentPanelX = 10;
int            currentPanelY = 10;
int            PANEL_WIDTH = 340;
int            PANEL_HEIGHT = 380;

// ============ OnInit ============
int OnInit()
{
    initialBalance = AccountBalance();
    highestEquity = initialBalance;
    
    if(ShowPanel) {
        CreatePanel();
    }
    
    Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Print("高级追涨杀跌EA已启动 - 基于图表优化");
    Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Print("最小趋势强度: ", MinTrendSpread, " 点(图表中三线分离程度)");
    Print("强趋势强度: ", StrongTrendSpread, " 点");
    Print("初始手数: ", InitialLots, " | 手数倍增: ", LotMultiplier);
    Print("最多持仓: ", MaxOpenTrades, " 单");
    Print("盈利目标: ", ProfitTarget1, "% / ", ProfitTarget2, "% / ", ProfitTarget3, "%");
    Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    
    return(INIT_SUCCEEDED);
}

// ============ OnDeinit ============
void OnDeinit(const int reason)
{
    // 清理面板对象
    ObjectsDeleteAll(0, PANEL_PREFIX);
}

// ============ OnTick ============
void OnTick()
{
    // ========== 风控检查 ==========
    double currentEquity = AccountEquity();
    if(currentEquity > highestEquity) {
        highestEquity = currentEquity;
    }
    
    CheckDrawdownProtection();
    
    if(UseDynamicTP) {
        ManageDynamicTakeProfit();
    }
    
    ManageTrailingStop();
    
    // ========== 时间过滤 ==========
    if(UseTimeFilter) {
        int currentHour = Hour();
        if(currentHour < StartHour || currentHour >= EndHour) {
            if(ShowPanel) UpdatePanel();
            return;
        }
    }
    
    // ========== 保证金检查 ==========
    if(GetMarginPercent() > MaxMarginPercent) {
        if(ShowPanel) UpdatePanel();
        return;
    }
    
    // ========== 连续亏损检查 ==========
    if(consecutiveLosses >= MaxConsecutiveLosses) {
        if(ShowPanel) UpdatePanel();
        return;
    }
    
    // ========== 获取关键数据 ==========
    double currentPrice = Close[0];
    double ask = Ask;
    double bid = Bid;
    double point = Point;
    
    // 获取均线值
    double ma5_cur = iMA(NULL, 0, MA5Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double ma15_cur = iMA(NULL, 0, MA15Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double ma30_cur = iMA(NULL, 0, MA30Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double sar_cur = iSAR(NULL, 0, 0.02, 0.2, 0);
    
    // ========== 趋势分析(关键改进)==========
    double upSpread = 0;
    double downSpread = 0;
    
    // 多头排列强度
    if(ma5_cur > ma15_cur && ma15_cur > ma30_cur) {
        upSpread = (ma5_cur - ma30_cur) / point;  // 转换为点数
    }
    
    // 空头排列强度
    if(ma5_cur < ma15_cur && ma15_cur < ma30_cur) {
        downSpread = (ma30_cur - ma5_cur) / point;  // 转换为点数
    }
    
    // 判断趋势确认
    bool upTrendConfirmed = (upSpread >= MinTrendSpread && sar_cur < currentPrice);
    bool downTrendConfirmed = (downSpread >= MinTrendSpread && sar_cur > currentPrice);
    bool strongUpTrend = (upSpread >= StrongTrendSpread);
    bool strongDownTrend = (downSpread >= StrongTrendSpread);
    
    int buyCount = CountOpenTradesByType(OP_BUY);
    int sellCount = CountOpenTradesByType(OP_SELL);
    int totalCount = buyCount + sellCount;
    
    datetime currentTime = TimeCurrent();
    int timeSinceBuy = (int)((currentTime - lastBuyOrderTime) / 60);
    int timeSinceSell = (int)((currentTime - lastSellOrderTime) / 60);
    
    // ========== 追涨逻辑 ==========
    if(upTrendConfirmed && buyCount < MaxOpenTrades) {
        bool shouldBuy = false;
        
        // 首单:强势上涨 + 趋势确认
        if(buyCount == 0 && strongUpTrend) {
            shouldBuy = true;
            Print("✓✓ 首单追涨触发: 强上涨 ", DoubleToStr(upSpread, 1), " 点");
        }
        // 加仓:价格继续上涨 + 时间间隔满足
        else if(buyCount > 0 && lastBuyPrice > 0) {
            double priceRise = ask - lastBuyPrice;
            double risePoints = priceRise / point;
            bool timeOK = (timeSinceBuy >= MinAddInterval);
            
            if(AggressiveMode && timeOK && risePoints >= AddPositionPoints * 0.7) {
                shouldBuy = true;
                Print("✓ 追涨加仓 #", buyCount + 1, ": 已涨 ", DoubleToStr(risePoints, 1), " 点 (趋势强度 ", DoubleToStr(upSpread, 1), ")");
            } else if(!AggressiveMode && timeOK && risePoints >= AddPositionPoints && strongUpTrend) {
                shouldBuy = true;
                Print("✓ 追涨加仓 #", buyCount + 1, ": 已涨 ", DoubleToStr(risePoints, 1), " 点");
            }
        }
        
        if(shouldBuy) {
            ExecuteBuy(buyCount);
            lastBuyOrderTime = currentTime;
            lastBuyPrice = ask;
            
            // 如果有卖单且趋势强烈反转,平掉卖单
            if(sellCount > 0 && strongUpTrend) {
                Print("⚠ 趋势反转,平掉所有卖单");
                CloseAllByType(OP_SELL);
            }
        }
    }
    
    // ========== 杀跌逻辑 ==========
    if(downTrendConfirmed && sellCount < MaxOpenTrades) {
        bool shouldSell = false;
        
        // 首单:强势下跌 + 趋势确认
        if(sellCount == 0 && strongDownTrend) {
            shouldSell = true;
            Print("✓✓ 首单杀跌触发: 强下跌 ", DoubleToStr(downSpread, 1), " 点");
        }
        // 加仓:价格继续下跌
        else if(sellCount > 0 && lastSellPrice > 0) {
            double priceFall = lastSellPrice - bid;
            double fallPoints = priceFall / point;
            bool timeOK = (timeSinceSell >= MinAddInterval);
            
            if(AggressiveMode && timeOK && fallPoints >= AddPositionPoints * 0.7) {
                shouldSell = true;
                Print("✓ 杀跌加仓 #", sellCount + 1, ": 已跌 ", DoubleToStr(fallPoints, 1), " 点 (趋势强度 ", DoubleToStr(downSpread, 1), ")");
            } else if(!AggressiveMode && timeOK && fallPoints >= AddPositionPoints && strongDownTrend) {
                shouldSell = true;
                Print("✓ 杀跌加仓 #", sellCount + 1, ": 已跌 ", DoubleToStr(fallPoints, 1), " 点");
            }
        }
        
        if(shouldSell) {
            ExecuteSell(sellCount);
            lastSellOrderTime = currentTime;
            lastSellPrice = bid;
            
            // 如果有买单且趋势强烈反转,平掉买单
            if(buyCount > 0 && strongDownTrend) {
                Print("⚠ 趋势反转,平掉所有买单");
                CloseAllByType(OP_BUY);
            }
        }
    }
    
    // ========== 更新面板 ==========
    if(ShowPanel) {
        UpdatePanel();
    }
}

// ============ 回撤保护 ============
void CheckDrawdownProtection()
{
    double currentEquity = AccountEquity();
    double drawdown = 0;
    
    if(highestEquity > initialBalance) {
        drawdown = ((highestEquity - currentEquity) / highestEquity) * 100;
    }
    
    if(drawdown >= MaxDrawdownPercent) {
        int posCount = CountAllOpenTrades();
        if(posCount > 0) {
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            Print("✗ 回撤保护: 从最高点回撤 ", DoubleToStr(drawdown, 2), "%");
            CloseAllPositions();
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            
            initialBalance = currentEquity;
            highestEquity = currentEquity;
            profitLocked1 = false;
            profitLocked2 = false;
            consecutiveLosses++;
        }
    }
}

// ============ 动态止盈管理 ============
void ManageDynamicTakeProfit()
{
    double profitPercent = GetProfitPercent();
    int totalPositions = CountAllOpenTrades();
    
    if(totalPositions == 0) return;
    
    // 第一阶段:达到第一目标,部分平仓
    if(!profitLocked1 && profitPercent >= ProfitTarget1) {
        int closeCount = (int)(totalPositions * PartialClosePercent / 100.0);
        if(closeCount > 0) {
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            Print("✓ 第一目标 ", DoubleToStr(profitPercent, 2), "% 达成,部分平仓 ", closeCount, " 单");
            PartialClosePositions(closeCount);
            profitLocked1 = true;
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        }
    }
    
    // 第二阶段:达到第二目标,再次部分平仓
    if(!profitLocked2 && profitPercent >= ProfitTarget2) {
        int remaining = CountAllOpenTrades();
        int closeCount = (int)(remaining * PartialClosePercent / 100.0);
        if(closeCount > 0) {
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            Print("✓ 第二目标 ", DoubleToStr(profitPercent, 2), "% 达成,再次平仓 ", closeCount, " 单");
            PartialClosePositions(closeCount);
            profitLocked2 = true;
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
        }
    }
    
    // 第三阶段:达到第三目标,全部平仓
    if(profitPercent >= ProfitTarget3) {
        int remaining = CountAllOpenTrades();
        if(remaining > 0) {
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            Print("✓✓✓ 第三目标 ", DoubleToStr(profitPercent, 2), "% 达成,全部平仓!");
            CloseAllPositions();
            Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            
            initialBalance = AccountBalance();
            highestEquity = initialBalance;
            profitLocked1 = false;
            profitLocked2 = false;
            consecutiveLosses = 0;
        }
    }
}

// ============ 部分平仓 ============
void PartialClosePositions(int count)
{
    int closed = 0;
    
    for(int i = OrdersTotal() - 1; i >= 0 && closed < count; i--) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        
        if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
                closed++;
            }
        }
    }
    
    Print("  实际平仓 ", closed, " 单");
}

// ============ 管理追踪止损 ============
void ManageTrailingStop()
{
    double point = Point;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
        
        double openPrice = OrderOpenPrice();
        double currentSL = OrderStopLoss();
        double currentTP = OrderTakeProfit();
        
        if(OrderType() == OP_BUY) {
            double profit = Bid - openPrice;
            double profitPoints = profit / point;
            
            if(profitPoints >= BreakEvenPoints) {
                double newSL = Bid - TrailingDistance * point;
                
                if(newSL > currentSL + TrailingStep * point && newSL < Bid) {
                    if(OrderModify(OrderTicket(), openPrice, newSL, currentTP, 0, clrNONE)) {
                        Print("✓ 买单 #", OrderTicket(), " 追踪止损: ", DoubleToStr(currentSL, Digits), " → ", DoubleToStr(newSL, Digits));
                    }
                }
            }
        }
        else if(OrderType() == OP_SELL) {
            double profit = openPrice - Ask;
            double profitPoints = profit / point;
            
            if(profitPoints >= BreakEvenPoints) {
                double newSL = Ask + TrailingDistance * point;
                
                if(newSL < currentSL - TrailingStep * point && newSL > Ask) {
                    if(OrderModify(OrderTicket(), openPrice, newSL, currentTP, 0, clrNONE)) {
                        Print("✓ 卖单 #", OrderTicket(), " 追踪止损: ", DoubleToStr(currentSL, Digits), " → ", DoubleToStr(newSL, Digits));
                    }
                }
            }
        }
    }
}

// ============ 执行买入(递增手数)============
void ExecuteBuy(int currentBuyCount)
{
    double ask = Ask;
    if(ask <= 0 || currentBuyCount >= MaxOpenTrades) return;
    
    // 计算递增手数
    double lots = InitialLots * MathPow(LotMultiplier, currentBuyCount);
    lots = NormalizeDouble(lots, 2);
    
    // 限制最大手数
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    if(lots > maxLot) lots = maxLot;
    
    double point = Point;
    double stopLoss = ask - StopLossPoints * point;
    double takeProfit = ask + DynamicTPPoints * point;
    
    // 检查保证金
    double freeMargin = AccountFreeMargin();
    if(freeMargin < lots * 100) {
        Print("⚠ 买单 #", currentBuyCount + 1, " 保证金不足(需要手数: ", DoubleToStr(lots, 2), ")");
        return;
    }
    
    int ticket = OrderSend(Symbol(), OP_BUY, lots, ask, 10, stopLoss, takeProfit, 
                          "BUY #" + IntegerToString(currentBuyCount + 1) + " " + DoubleToStr(lots, 2), 
                          MagicNumber, 0, clrGreen);
    
    if(ticket > 0) {
        Print("✓ 买单 #", currentBuyCount + 1, " 已开: Ticket=", ticket, ", 手数=", DoubleToStr(lots, 2), ", 价格=", DoubleToStr(ask, Digits));
    } else {
        Print("✗ 买单 #", currentBuyCount + 1, " 失败: Error ", GetLastError());
    }
}

// ============ 执行卖出(递增手数)============
void ExecuteSell(int currentSellCount)
{
    double bid = Bid;
    if(bid <= 0 || currentSellCount >= MaxOpenTrades) return;
    
    // 计算递增手数
    double lots = InitialLots * MathPow(LotMultiplier, currentSellCount);
    lots = NormalizeDouble(lots, 2);
    
    // 限制最大手数
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    if(lots > maxLot) lots = maxLot;
    
    double point = Point;
    double stopLoss = bid + StopLossPoints * point;
    double takeProfit = bid - DynamicTPPoints * point;
    
    // 检查保证金
    double freeMargin = AccountFreeMargin();
    if(freeMargin < lots * 100) {
        Print("⚠ 卖单 #", currentSellCount + 1, " 保证金不足(需要手数: ", DoubleToStr(lots, 2), ")");
        return;
    }
    
    int ticket = OrderSend(Symbol(), OP_SELL, lots, bid, 10, stopLoss, takeProfit, 
                          "SELL #" + IntegerToString(currentSellCount + 1) + " " + DoubleToStr(lots, 2), 
                          MagicNumber, 0, clrRed);
    
    if(ticket > 0) {
        Print("✓ 卖单 #", currentSellCount + 1, " 已开: Ticket=", ticket, ", 手数=", DoubleToStr(lots, 2), ", 价格=", DoubleToStr(bid, Digits));
    } else {
        Print("✗ 卖单 #", currentSellCount + 1, " 失败: Error ", GetLastError());
    }
}

// ============ 获取保证金率 ============
double GetMarginPercent()
{
    double balance = AccountBalance();
    double margin = AccountMargin();
    
    if(balance <= 0) return 0;
    
    return (margin / balance) * 100;
}

// ============ 获取盈亏百分比 ============
double GetProfitPercent()
{
    double equity = AccountEquity();
    
    if(initialBalance <= 0) return 0;
    
    return ((equity - initialBalance) / initialBalance) * 100;
}

// ============ 计数所有持仓 ============
int CountAllOpenTrades()
{
    int count = 0;
    
    for(int i = 0; i < OrdersTotal(); i++) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            count++;
        }
    }
    
    return count;
}

// ============ 计数指定方向持仓 ============
int CountOpenTradesByType(int orderType)
{
    int count = 0;
    
    for(int i = 0; i < OrdersTotal(); i++) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        if(OrderType() == orderType) {
            count++;
        }
    }
    
    return count;
}

// ============ 平仓所有持仓 ============
void CloseAllPositions()
{
    int closed = 0;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        
        if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
                closed++;
            }
        }
    }
    
    Print("✓ 已平仓 ", closed, " 单");
}

// ============ 平仓指定类型持仓 ============
void CloseAllByType(int orderType)
{
    int closed = 0;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol()) continue;
        if(OrderMagicNumber() != MagicNumber) continue;
        
        if(OrderType() == orderType) {
            if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
                closed++;
            }
        }
    }
    
    string typeStr = (orderType == OP_BUY) ? "买单" : "卖单";
    Print("✓ 已平仓所有", typeStr, " ", closed, " 单");
}

// ============ 创建资金面板 ============
void CreatePanel()
{
    // 清除旧的面板对象
    ObjectsDeleteAll(0, PANEL_PREFIX);
    
    // 创建背景矩形
    string bgName = PANEL_PREFIX + "Background";
    ObjectCreate(bgName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
    ObjectSet(bgName, OBJPROP_XDISTANCE, currentPanelX);
    ObjectSet(bgName, OBJPROP_YDISTANCE, currentPanelY);
    ObjectSet(bgName, OBJPROP_XSIZE, PANEL_WIDTH);
    ObjectSet(bgName, OBJPROP_YSIZE, PANEL_HEIGHT);
    ObjectSet(bgName, OBJPROP_BGCOLOR, C'40,40,40');
    ObjectSet(bgName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
    ObjectSet(bgName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSet(bgName, OBJPROP_SELECTABLE, false);
    
    // 标题
    CreatePanelLabel(PANEL_PREFIX + "Title", "━━━ 智能风控面板 ━━━", 10, 10, clrYellow, 10);
    
    // 各项数据标签
    CreatePanelLabel(PANEL_PREFIX + "Balance", "账户余额: ", 15, 40, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "BalanceVal", "0.00", 180, 40, clrLime, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Equity", "账户净值: ", 15, 60, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "EquityVal", "0.00", 180, 60, clrLime, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Margin", "保证金率: ", 15, 80, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "MarginVal", "0.00%", 180, 80, clrOrange, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Profit", "盈亏比例: ", 15, 100, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "ProfitVal", "0.00%", 180, 100, clrAqua, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "FloatingProfit", "浮动盈亏: ", 15, 120, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "FloatingProfitVal", "0.00", 180, 120, clrAqua, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Drawdown", "当前回撤: ", 15, 140, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "DrawdownVal", "0.00%", 180, 140, clrRed, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "BuyCount", "买单数量: ", 15, 160, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "BuyCountVal", "0", 180, 160, clrLime, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "SellCount", "卖单数量: ", 15, 180, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "SellCountVal", "0", 180, 180, clrRed, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "TotalCount", "总持仓数: ", 15, 200, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "TotalCountVal", "0", 180, 200, clrYellow, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Trend", "趋势强度: ", 15, 220, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "TrendVal", "中性", 180, 220, clrGray, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "NextTarget", "下一目标: ", 15, 240, clrWhite, 9);
    CreatePanelLabel(PANEL_PREFIX + "NextTargetVal", "--", 180, 240, clrGold, 9);
    
    CreatePanelLabel(PANEL_PREFIX + "Status", "状态: 运行中", 15, 270, clrLime, 10);
    CreatePanelLabel(PANEL_PREFIX + "Time", TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS), 15, 290, clrSilver, 8);
    
    CreatePanelLabel(PANEL_PREFIX + "Version", "v2.10 图表优化版", 15, 310, clrGray, 7);
    
    // 分隔线
    CreatePanelLabel(PANEL_PREFIX + "Divider", "━━━━━━━━━━━━━━━━━━━━━", 15, 330, clrDimGray, 8);
    
    CreatePanelLabel(PANEL_PREFIX + "Tip", "基于均线排列强度确认趋势", 15, 350, clrGray, 8);
    
    ChartRedraw();
}

// ============ 创建面板标签 ============
void CreatePanelLabel(string name, string text, int x, int y, color clr, int fontSize)
{
    ObjectCreate(name, OBJ_LABEL, 0, 0, 0);
    ObjectSetText(name, text, fontSize, "Arial", clr);
    ObjectSet(name, OBJPROP_XDISTANCE, currentPanelX + x);
    ObjectSet(name, OBJPROP_YDISTANCE, currentPanelY + y);
    ObjectSet(name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSet(name, OBJPROP_SELECTABLE, false);
}

// ============ 更新面板数据 ============
void UpdatePanel()
{
    if(!ShowPanel) return;
    
    double balance = AccountBalance();
    double equity = AccountEquity();
    double marginPercent = GetMarginPercent();
    double profitPercent = GetProfitPercent();
    double floatingProfit = equity - balance;
    
    // 计算回撤
    double drawdown = 0;
    if(highestEquity > initialBalance) {
        drawdown = ((highestEquity - equity) / highestEquity) * 100;
    }
    
    int buyCount = CountOpenTradesByType(OP_BUY);
    int sellCount = CountOpenTradesByType(OP_SELL);
    int totalCount = buyCount + sellCount;
    
    // 计算趋势强度
    double ma5 = iMA(NULL, 0, MA5Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double ma15 = iMA(NULL, 0, MA15Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double ma30 = iMA(NULL, 0, MA30Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    
    double upSpread = 0;
    double downSpread = 0;
    string trendText = "中性";
    color trendColor = clrGray;
    
    if(ma5 > ma15 && ma15 > ma30) {
        upSpread = (ma5 - ma30) / Point;
        trendText = "上涨 " + DoubleToStr(upSpread, 0) + " 点";
        trendColor = clrLime;
    } else if(ma5 < ma15 && ma15 < ma30) {
        downSpread = (ma30 - ma5) / Point;
        trendText = "下跌 " + DoubleToStr(downSpread, 0) + " 点";
        trendColor = clrRed;
    }
    
    // 计算下一个盈利目标
    string nextTarget = "--";
    if(!profitLocked1) {
        nextTarget = "目标1: " + DoubleToStr(ProfitTarget1, 1) + "%";
    } else if(!profitLocked2) {
        nextTarget = "目标2: " + DoubleToStr(ProfitTarget2, 1) + "%";
    } else {
        nextTarget = "目标3: " + DoubleToStr(ProfitTarget3, 1) + "%";
    }
    
    // 更新显示
    ObjectSetText(PANEL_PREFIX + "BalanceVal", DoubleToStr(balance, 2), 9, "Arial", clrLime);
    ObjectSetText(PANEL_PREFIX + "EquityVal", DoubleToStr(equity, 2), 9, "Arial", equity >= balance ? clrLime : clrRed);
    ObjectSetText(PANEL_PREFIX + "MarginVal", DoubleToStr(marginPercent, 2) + "%", 9, "Arial", 
                  marginPercent > 50 ? clrRed : clrOrange);
    ObjectSetText(PANEL_PREFIX + "ProfitVal", DoubleToStr(profitPercent, 2) + "%", 9, "Arial", 
                  profitPercent >= 0 ? clrLime : clrRed);
    ObjectSetText(PANEL_PREFIX + "FloatingProfitVal", DoubleToStr(floatingProfit, 2), 9, "Arial", 
                  floatingProfit >= 0 ? clrLime : clrRed);
    ObjectSetText(PANEL_PREFIX + "DrawdownVal", DoubleToStr(drawdown, 2) + "%", 9, "Arial", 
                  drawdown > 5 ? clrRed : clrOrange);
    ObjectSetText(PANEL_PREFIX + "BuyCountVal", IntegerToString(buyCount), 9, "Arial", clrLime);
    ObjectSetText(PANEL_PREFIX + "SellCountVal", IntegerToString(sellCount), 9, "Arial", clrRed);
    ObjectSetText(PANEL_PREFIX + "TotalCountVal", IntegerToString(totalCount), 9, "Arial", clrYellow);
    ObjectSetText(PANEL_PREFIX + "TrendVal", trendText, 9, "Arial", trendColor);
    ObjectSetText(PANEL_PREFIX + "NextTargetVal", nextTarget, 9, "Arial", clrGold);
    ObjectSetText(PANEL_PREFIX + "Time", TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS), 8, "Arial", clrSilver);
    
    // 更新状态
    string status = "运行中";
    color statusColor = clrLime;
    
    if(consecutiveLosses >= MaxConsecutiveLosses) {
        status = "暂停: 连续止损";
        statusColor = clrRed;
    } else if(marginPercent > MaxMarginPercent) {
        status = "保证金超限";
        statusColor = clrOrange;
    } else if(drawdown >= MaxDrawdownPercent * 0.8) {
        status = "警告: 回撤接近上限";
        statusColor = clrYellow;
    }
    
    ObjectSetText(PANEL_PREFIX + "Status", "状态: " + status, 10, "Arial", statusColor);
    
    ChartRedraw();
}

作品说明

我发现问题了!代码写成了 MQL5 格式,但您要的是 MQL4 格式。我来重写完整的 MQL4 版本代码。

使用说明

1. 安装方法

  • 将代码保存为 XAUUSD_SAR_MA_EA.mq4
  • 复制到 MT4 的 MQL4/Experts 目录
  • 在 MetaEditor 中编译(F7)
  • 在 MT4 图表上附加 EA(需启用自动交易)

2. 核心优化点(基于图表分析)

  • 趋势强度确认:必须 MA5 > MA15 > MA30(或反向)且间距达到 MinTrendSpread 点才开首单
  • 强趋势判断:间距达到 StrongTrendSpread 点才允许激进加仓
  • SAR 辅助确认:趋势方向必须与 SAR 位置一致
  • 动态加仓:根据价格上涨/下跌幅度决定是否加仓,避免在横盘时频繁开单

3. 关键参数调整建议

  • MinTrendSpread (15点):图表左侧三线粘合区间不会开单,只在中间和右侧明确趋势时开单
  • StrongTrendSpread (30点):图表中间大涨段,三线分离明显,会触发首单和激进加仓
  • AddPositionPoints (60点):价格上涨/下跌60点后才加仓,避免过度交易
  • AggressiveMode (true):激进模式下,涨幅达到60*0.7=42点就加仓

4. 风控机制

  • 最大回撤保护:从最高净值回撤10%自动全部平仓
  • 分阶段止盈:3% / 8% / 15% 三档自动锁利
  • 保证金控制:超过65%不再开新单
  • 连续止损保护:连续3次触发回撤保护后暂停交易

5. 注意事项

  • 建议在 XAUUSD(黄金)5分钟图 上使用
  • 初始资金建议至少 $500 以上
  • 启用前先在 模拟账户 测试至少1周
  • 关注面板显示的趋势强度,低于15点时EA不会开首单
  • 手数倍增系数1.5较为稳健,如需激进可设置1.8-2.0

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

这是什么

这是一个 MT4 平台上的黄金自动交易 EA,核心逻辑是「追涨杀跌」:涨得越猛越追买,跌得越狠越杀跌。与暴力马丁不同,它通过 MA5 / MA15 / MA30 三条均线的排列强度来判断趋势是否成立,配合 SAR 做辅助过滤,只有趋势足够明确时才开首单,价格继续突破后再用递增手数加仓。止盈不是固定点数,而是分三档动态锁利(3% / 8% / 15%),同时有回撤保护机制防止盈利回吐。

逻辑原理

趋势判断:MA5 > MA15 > MA30 时为多头排列,MA5 < MA15 < MA30 时为空头排列。代码会计算 MA5 到 MA30 之间的点数距离,称为「趋势强度」。只有距离达到 MinTrendSpread(默认15点)才认为趋势成立,达到 StrongTrendSpread(默认30点)才允许开首单或激进加仓。SAR 必须在价格下方(上涨)或上方(下跌)才通过确认。

进场规则:多头排列且 SAR 在下方 + 趋势强度≥30点 → 首单做多。之后价格每上涨 AddPositionPoints(默认60点)且满足最小时间间隔(默认2分钟),开一笔加仓单,手数按 LotMultiplier(默认1.5倍)递增。空头排列同理做空。

出场规则:

  • 固定止损:每单开仓时设置 StopLossPoints(默认120点)的固定止损
  • 动态止盈:达到 3% 账户利润时部分平仓40%,8% 再平40%,15% 全部平仓
  • 追踪止损:单笔盈利超过 BreakEvenPoints(默认70点)后,止损跟随价格按 TrailingDistance(35点)追踪
  • 回撤保护:从最高净值回撤 MaxDrawdownPercent(默认10%)时全部平仓并暂停交易

反转处理:如果当前有买单但趋势突然转为强烈空头排列(或反之),代码会强制平掉反向持仓。

参数说明

  • InitialLots(0.01):首单手数。0.01 对应 0.01 标准手,约 $10/点波动。资金小于 $500 不建议改大
  • MaxOpenTrades(12):最多同时持有几单。默认12单,激进可设到15,保守设8
  • LotMultiplier(1.5):加仓时手数倍数。1.5 表示第二单1.5倍,第三单2.25倍。调到2.0 更激进但风险高
  • MinTrendSpread(15.0):趋势成立的最小强度,单位是点。低于这个值 EA 不开首单。黄金波动大可设20,小周期可设10
  • StrongTrendSpread(30.0):强趋势强度。只有达到这个值才允许开首单或激进加仓。保守交易者可设到40
  • AddPositionPoints(60):价格上涨/下跌多少点后加仓。60点对应黄金约$6。日内波段可用50–80,长线可设100+
  • AggressiveMode(true):激进模式。开启后达到 AddPositionPoints * 0.7 就加仓(约42点),关闭则必须满60点且趋势仍强
  • StopLossPoints(120):单笔止损点数。黄金5分钟图默认120点约$12,波动大时可放宽到150
  • BreakEvenPoints(70):盈利多少点后启动追踪止损。默认70点约$7,之后止损会跟随价格移动
  • TrailingDistance(35):追踪止损距离当前价格的点数。35点约$3.5,太小容易提前止盈,太大保护不够
  • ProfitTarget1 / 2 / 3(3.0 / 8.0 / 15.0):三档止盈目标,单位是账户利润百分比。例如账户余额 $1000,3% 就是盈利 $30 时触发第一档
  • PartialClosePercent(40.0):达到目标1和2时,每次平掉多少比例的持仓。40% 表示平掉接近一半
  • MaxDrawdownPercent(10.0):从最高净值回撤多少百分比时强制平仓保护。10% 较激进,保守设5%
  • MaxConsecutiveLosses(3):连续触发回撤保护几次后暂停交易,防止极端行情连续亏损

怎么用

  1. 将代码保存为 .mq4 文件,放到 MT4 数据文件夹的 MQL4/Experts 目录
  2. 在 MetaEditor 中打开并按 F7 编译,无错误后关闭
  3. 在 MT4 图表上选择 XAUUSD(黄金)品种,时间周期选 M5(5分钟图)
  4. 从导航器拖动 EA 到图表,勾选「允许自动交易」,点确定
  5. 图表左上角会出现一个深色面板,显示账户余额、持仓数量、趋势强度等实时信息
  6. EA 运行后会自动判断趋势,满足条件时自动开单,不需要手动操作

看信号的方法:

  • 面板显示「趋势强度: 上涨 XX 点」且数字 ≥30,说明可能开多单
  • 终端「专家」标签页里会打印开单日志,例如「✓✓ 首单追涨触发: 强上涨 35.2 点」
  • 如果持仓后价格回调,追踪止损会自动调整,不需要手动改

适用场景

  • 品种:主要为 XAUUSD(黄金),代码里没有品种限制,但参数是按黄金波动率调的。其他贵金属(白银)或高波动货币对(GBPUSD)理论可用,需重新测试参数
  • 周期:推荐 M5(5分钟图)。M15 可能趋势更稳但加仓频率低,M1 噪音太大容易假信号
  • 行情:适合单边趋势行情,例如美联储决议、非农数据后持续上涨或下跌。欧美时段(北京时间15:00–23:00)黄金波动大,成功率更高
  • 不适合的行情:
  • 震荡盘整期:三条均线粘在一起,趋势强度低于15点,EA 不会开首单但可能已有持仓被来回止损
  • 假突破行情:价格短暂突破后迅速反转,可能触发加仓后立即止损
  • 隔夜跳空:EA 不处理周末跳空缺口,周一开盘可能直接止损

风险提示

  1. 回撤保护是双刃剑:10% 回撤保护在剧烈波动时可能频繁触发,导致小亏不断累积。如果连续触发3次,EA 会暂停交易需要手动重启
  2. 加仓放大风险:手数倍增 1.5 倍看起来温和,但 12 单全开完总手数约为首单的 129 倍。如果首单 0.01 手,第12单约 0.13 手,保证金占用和亏损都会急剧放大
  3. 追踪止损可能提前出局:35点追踪距离在快速波动时容易被扫到止损,错过后续大行情。如果经常遇到「刚止盈就继续大涨」,可以把 TrailingDistance 调大到50点
  4. 动态止盈依赖账户净值:如果账户里还有其他 EA 或手动单,3% / 8% / 15% 的计算会受影响。建议单独账户或单独测试
  5. 不处理滑点和点差:代码里 OrderSend 的滑点参数是固定 10 点,ECN 账户或新闻时段点差暴涨可能导致实际成交价差很大。开单失败的日志会打印 Error 代码,需自行检查
  6. 首单条件严格可能错过机会:StrongTrendSpread 默认30点,意味着 MA5 和 MA30 要相差30点才开首单。黄金波动小时可能一整天都不开单。如果想提高开单频率,可以降到20点,但假信号会增加
  7. 代码未做周末或假期过滤:如果周五晚上持仓过周末,周一跳空可能直接触发回撤保护。建议手动在周五收盘前关闭 EA 或清空持仓

常见问题

这个EA会在震荡行情里频繁开单吗
不会。代码要求 MA5/15/30 三线排列且间距≥15点才开首单,震荡时三线粘合趋势强度为0,EA 不会开单。但如果已有持仓,震荡可能导致追踪止损反复触发。
手数倍增1.5倍安全吗,会不会爆仓
1.5倍相对温和,但12单全开完总手数约为首单的129倍。如果首单0.01手且MaxOpenTrades设12,极端情况下保证金占用可达数千美元。建议初始资金至少$500,或把MaxOpenTrades降到8。
参数默认值适合什么周期
默认参数是按XAUUSD 5分钟图调的。MinTrendSpread 15点、AddPositionPoints 60点对应5分钟图的典型波动。如果用15分钟图,建议把AddPositionPoints调大到100点以上。
这个EA可以用在XAUUSD以外的品种吗
代码里没有品种限制,但参数是按黄金点值和波动率设计的。其他品种如白银、原油或外汇对需要重新测试,特别是StopLossPoints和AddPositionPoints可能需要按该品种的ATR调整。
动态止盈的3% / 8% / 15%是按什么算的
按账户余额(AccountBalance)的百分比。例如余额$1000,盈利$30时触发第一档(3%)部分平仓。如果账户里有其他持仓或手动单影响余额,这个计算会不准确,建议单独账户测试。

XAUUSD Trend-Chasing EA with Multi-Level Take Profit for MT4

A MetaTrader 4 EA that chases trends using triple moving average (MA5/15/30) strength confirmation and SAR filter. Implements progressive lot sizing, dynamic take-profit levels (3%/8%/15%), and drawdown protection. Designed for XAUUSD on 5-minute charts.

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

评论 (1)

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

不开单