MT5指标编译通过 · EX5 25KB 自动发布 3 0

SMC 机构级交易指标

xuhaosheng·2 小时前发布

智能过滤高质量订单块与 FVG,自动管理失效区域,适合专业交易

SMC 机构级交易指标

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

SMC_Institutional.mq5640 行
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
#property copyright "XAUOF 指标工坊"
#property version   "2.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

//--- 输入参数
input group "=== 核心设置 ==="
input int    SwingStrength = 7;           // 结构强度(左右确认 K 线数)
input double MinOBBodyPips = 10;          // 订单块最小实体(点数)
input double MinFVGSizePips = 8;          // FVG 最小尺寸(点数)
input bool   AutoRemoveInvalidOB = true;  // 自动移除失效订单块
input int    MaxActiveOB = 8;             // 最多显示订单块数量
input int    MaxActiveFVG = 6;            // 最多显示 FVG 数量

input group "=== 显示选项 ==="
input bool   ShowSwingPoints = false;     // 显示结构高低点(默认关闭)
input bool   ShowOrderBlocks = true;      // 显示订单块
input bool   ShowFVG = true;              // 显示公允价值缺口
input bool   ShowOBLabels = true;         // 显示订单块标签
input int    OBExtendBars = 100;          // 订单块延伸长度

input group "=== 专业配色 ==="
input color  BullOBColor = C'30,144,255'; // 看涨订单块(深蓝)
input color  BearOBColor = C'220,20,60';  // 看跌订单块(深红)
input color  BullFVGColor = C'64,224,208';// 看涨 FVG(青绿)
input color  BearFVGColor = C'255,182,193';// 看跌 FVG(浅粉)
input int    OBTransparency = 85;         // 订单块透明度(0-100)
input int    FVGTransparency = 90;        // FVG 透明度(0-100)

//--- 订单块结构
struct OrderBlock
{
   datetime time;
   double   top;
   double   bottom;
   bool     isBullish;
   string   objName;
   bool     isValid;
   double   strength;  // 强度评分
};

OrderBlock activeOBs[];
int obCount = 0;

//--- FVG 结构
struct FairValueGap
{
   datetime time;
   double   top;
   double   bottom;
   bool     isBullish;
   string   objName;
   bool     isValid;
};

FairValueGap activeFVGs[];
int fvgCount = 0;

//+------------------------------------------------------------------+
//| 初始化函数                                                        |
//+------------------------------------------------------------------+
int OnInit()
{
   ArrayResize(activeOBs, 0);
   ArrayResize(activeFVGs, 0);
   obCount = 0;
   fvgCount = 0;
   
   // 清理旧对象
   ObjectsDeleteAll(0, "SMC_");
   
   // 扫描历史
   ScanHistoricalData();
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 计算函数                                                          |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   if(rates_total < SwingStrength * 2 + 10) return 0;
   
   static datetime lastProcessed = 0;
   datetime currentBar = time[rates_total - 1];
   if(currentBar == lastProcessed) return rates_total;
   lastProcessed = currentBar;
   
   // 检查确认 K 线位置
   int checkBar = rates_total - SwingStrength - 2;
   if(checkBar < SwingStrength + 3) return rates_total;
   
   // 1. 验证现有订单块是否仍然有效
   if(AutoRemoveInvalidOB)
   {
      ValidateOrderBlocks(close[rates_total - 1]);
   }
   
   // 2. 检测新订单块
   if(ShowOrderBlocks)
   {
      DetectNewOrderBlock(checkBar, time, open, high, low, close);
   }
   
   // 3. 检测新 FVG
   if(ShowFVG)
   {
      DetectNewFVG(checkBar, time, high, low);
   }
   
   // 4. 检测结构点(可选)
   if(ShowSwingPoints)
   {
      DetectSwingPoints(checkBar, rates_total, time, high, low);
   }
   
   return rates_total;
}

//+------------------------------------------------------------------+
//| 扫描历史数据                                                      |
//+------------------------------------------------------------------+
void ScanHistoricalData()
{
   int lookback = 500;
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   
   int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, lookback, rates);
   if(copied <= SwingStrength + 10)
   {
      Print("数据不足,无法扫描历史");
      return;
   }
   
   // 从老到新扫描(倒序索引)
   for(int i = copied - SwingStrength - 3; i >= SwingStrength + 2; i--)
   {
      // 检测订单块
      if(ShowOrderBlocks)
      {
         CheckOBInHistory(i, rates);
      }
      
      // 检测 FVG
      if(ShowFVG)
      {
         CheckFVGInHistory(i, rates);
      }
   }
   
   // 只保留最强的几个
   FilterTopOrderBlocks();
   FilterTopFVGs();
   
   Print(StringFormat("已加载 %d 个订单块,%d 个 FVG", obCount, fvgCount));
}

//+------------------------------------------------------------------+
//| 历史订单块检测                                                    |
//+------------------------------------------------------------------+
void CheckOBInHistory(int idx, const MqlRates &rates[])
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double minBody = MinOBBodyPips * point;
   
   // 看涨订单块:idx 大阳线吞没 idx+1 阴线
   bool isBullOB = false;
   double body1 = MathAbs(rates[idx + 1].close - rates[idx + 1].open);
   double body2 = rates[idx].close - rates[idx].open;
   
   if(rates[idx + 1].close < rates[idx + 1].open &&  // idx+1 是阴线
      rates[idx].close > rates[idx].open &&           // idx 是阳线
      body2 > minBody &&                              // 阳线实体够大
      rates[idx].close > rates[idx + 1].high)         // 吞没前高
   {
      isBullOB = true;
   }
   
   // 看跌订单块:idx 大阴线吞没 idx+1 阳线
   bool isBearOB = false;
   double body3 = rates[idx].open - rates[idx].close;
   
   if(rates[idx + 1].close > rates[idx + 1].open &&  // idx+1 是阳线
      rates[idx].close < rates[idx].open &&           // idx 是阴线
      body3 > minBody &&                              // 阴线实体够大
      rates[idx].close < rates[idx + 1].low)          // 吞没前低
   {
      isBearOB = true;
   }
   
   // 创建订单块
   if(isBullOB || isBearOB)
   {
      OrderBlock ob;
      ob.time = rates[idx + 1].time;
      ob.top = rates[idx + 1].high;
      ob.bottom = rates[idx + 1].low;
      ob.isBullish = isBullOB;
      ob.isValid = true;
      ob.strength = isBullOB ? body2 / point : body3 / point;
      ob.objName = "SMC_OB_" + TimeToString(ob.time, TIME_DATE|TIME_MINUTES);
      
      // 检查是否已存在
      bool exists = false;
      for(int j = 0; j < obCount; j++)
      {
         if(activeOBs[j].objName == ob.objName)
         {
            exists = true;
            break;
         }
      }
      
      if(!exists && obCount < 100)
      {
         ArrayResize(activeOBs, obCount + 1);
         activeOBs[obCount] = ob;
         obCount++;
      }
   }
}

//+------------------------------------------------------------------+
//| 历史 FVG 检测                                                     |
//+------------------------------------------------------------------+
void CheckFVGInHistory(int idx, const MqlRates &rates[])
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double minSize = MinFVGSizePips * point;
   
   // 看涨 FVG:idx+2.high < idx.low
   if(rates[idx + 2].high < rates[idx].low)
   {
      double gapSize = rates[idx].low - rates[idx + 2].high;
      if(gapSize >= minSize)
      {
         FairValueGap fvg;
         fvg.time = rates[idx + 1].time;
         fvg.top = rates[idx].low;
         fvg.bottom = rates[idx + 2].high;
         fvg.isBullish = true;
         fvg.isValid = true;
         fvg.objName = "SMC_FVG_" + TimeToString(rates[idx].time, TIME_DATE|TIME_MINUTES);
         
         bool exists = false;
         for(int j = 0; j < fvgCount; j++)
         {
            if(activeFVGs[j].objName == fvg.objName)
            {
               exists = true;
               break;
            }
         }
         
         if(!exists && fvgCount < 100)
         {
            ArrayResize(activeFVGs, fvgCount + 1);
            activeFVGs[fvgCount] = fvg;
            fvgCount++;
         }
      }
   }
   
   // 看跌 FVG:idx+2.low > idx.high
   if(rates[idx + 2].low > rates[idx].high)
   {
      double gapSize = rates[idx + 2].low - rates[idx].high;
      if(gapSize >= minSize)
      {
         FairValueGap fvg;
         fvg.time = rates[idx + 1].time;
         fvg.top = rates[idx + 2].low;
         fvg.bottom = rates[idx].high;
         fvg.isBullish = false;
         fvg.isValid = true;
         fvg.objName = "SMC_FVG_" + TimeToString(rates[idx].time, TIME_DATE|TIME_MINUTES);
         
         bool exists = false;
         for(int j = 0; j < fvgCount; j++)
         {
            if(activeFVGs[j].objName == fvg.objName)
            {
               exists = true;
               break;
            }
         }
         
         if(!exists && fvgCount < 100)
         {
            ArrayResize(activeFVGs, fvgCount + 1);
            activeFVGs[fvgCount] = fvg;
            fvgCount++;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| 只保留最强的订单块                                                |
//+------------------------------------------------------------------+
void FilterTopOrderBlocks()
{
   if(obCount <= MaxActiveOB) 
   {
      DrawAllOrderBlocks();
      return;
   }
   
   // 按强度排序(冒泡排序)
   for(int i = 0; i < obCount - 1; i++)
   {
      for(int j = 0; j < obCount - i - 1; j++)
      {
         if(activeOBs[j].strength < activeOBs[j + 1].strength)
         {
            OrderBlock temp = activeOBs[j];
            activeOBs[j] = activeOBs[j + 1];
            activeOBs[j + 1] = temp;
         }
      }
   }
   
   // 只保留前 MaxActiveOB 个
   ArrayResize(activeOBs, MaxActiveOB);
   obCount = MaxActiveOB;
   
   DrawAllOrderBlocks();
}

//+------------------------------------------------------------------+
//| 只保留最近的 FVG                                                  |
//+------------------------------------------------------------------+
void FilterTopFVGs()
{
   if(fvgCount <= MaxActiveFVG)
   {
      DrawAllFVGs();
      return;
   }
   
   // 只保留最新的
   ArrayResize(activeFVGs, MaxActiveFVG);
   fvgCount = MaxActiveFVG;
   
   DrawAllFVGs();
}

//+------------------------------------------------------------------+
//| 绘制所有订单块                                                    |
//+------------------------------------------------------------------+
void DrawAllOrderBlocks()
{
   for(int i = 0; i < obCount; i++)
   {
      if(!activeOBs[i].isValid) continue;
      
      datetime t2 = activeOBs[i].time + PeriodSeconds(PERIOD_CURRENT) * OBExtendBars;
      
      if(ObjectFind(0, activeOBs[i].objName) < 0)
      {
         ObjectCreate(0, activeOBs[i].objName, OBJ_RECTANGLE, 0, 
                     activeOBs[i].time, activeOBs[i].top, 
                     t2, activeOBs[i].bottom);
         
         color clr = activeOBs[i].isBullish ? BullOBColor : BearOBColor;
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_COLOR, clr);
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_FILL, true);
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_BACK, true);
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_WIDTH, 2);
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_STYLE, STYLE_SOLID);
         
         // 设置透明度
         long rgb = ObjectGetInteger(0, activeOBs[i].objName, OBJPROP_COLOR);
         long alpha = (100 - OBTransparency) * 255 / 100;
         ObjectSetInteger(0, activeOBs[i].objName, OBJPROP_COLOR, (alpha << 24) | rgb);
         
         // 添加标签
         if(ShowOBLabels)
         {
            string label = activeOBs[i].objName + "_L";
            double labelPrice = activeOBs[i].isBullish ? activeOBs[i].bottom : activeOBs[i].top;
            ObjectCreate(0, label, OBJ_TEXT, 0, activeOBs[i].time, labelPrice);
            ObjectSetString(0, label, OBJPROP_TEXT, activeOBs[i].isBullish ? "OB↑" : "OB↓");
            ObjectSetInteger(0, label, OBJPROP_COLOR, clr);
            ObjectSetInteger(0, label, OBJPROP_FONTSIZE, 8);
            ObjectSetInteger(0, label, OBJPROP_ANCHOR, activeOBs[i].isBullish ? ANCHOR_TOP : ANCHOR_BOTTOM);
         }
      }
   }
}

//+------------------------------------------------------------------+
//| 绘制所有 FVG                                                      |
//+------------------------------------------------------------------+
void DrawAllFVGs()
{
   for(int i = 0; i < fvgCount; i++)
   {
      if(!activeFVGs[i].isValid) continue;
      
      datetime t2 = activeFVGs[i].time + PeriodSeconds(PERIOD_CURRENT) * (OBExtendBars / 2);
      
      if(ObjectFind(0, activeFVGs[i].objName) < 0)
      {
         ObjectCreate(0, activeFVGs[i].objName, OBJ_RECTANGLE, 0,
                     activeFVGs[i].time, activeFVGs[i].top,
                     t2, activeFVGs[i].bottom);
         
         color clr = activeFVGs[i].isBullish ? BullFVGColor : BearFVGColor;
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_COLOR, clr);
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_FILL, true);
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_BACK, true);
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_WIDTH, 1);
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_STYLE, STYLE_DOT);
         
         // 透明度
         long rgb = ObjectGetInteger(0, activeFVGs[i].objName, OBJPROP_COLOR);
         long alpha = (100 - FVGTransparency) * 255 / 100;
         ObjectSetInteger(0, activeFVGs[i].objName, OBJPROP_COLOR, (alpha << 24) | rgb);
      }
   }
}

//+------------------------------------------------------------------+
//| 验证订单块是否仍然有效                                            |
//+------------------------------------------------------------------+
void ValidateOrderBlocks(double currentPrice)
{
   for(int i = 0; i < obCount; i++)
   {
      if(!activeOBs[i].isValid) continue;
      
      // 看涨订单块被完全跌破 = 失效
      if(activeOBs[i].isBullish && currentPrice < activeOBs[i].bottom)
      {
         activeOBs[i].isValid = false;
         ObjectDelete(0, activeOBs[i].objName);
         ObjectDelete(0, activeOBs[i].objName + "_L");
      }
      
      // 看跌订单块被完全突破 = 失效
      if(!activeOBs[i].isBullish && currentPrice > activeOBs[i].top)
      {
         activeOBs[i].isValid = false;
         ObjectDelete(0, activeOBs[i].objName);
         ObjectDelete(0, activeOBs[i].objName + "_L");
      }
   }
}

//+------------------------------------------------------------------+
//| 实时检测新订单块                                                  |
//+------------------------------------------------------------------+
void DetectNewOrderBlock(int bar, const datetime &time[], const double &open[],
                        const double &high[], const double &low[], const double &close[])
{
   if(bar < 2) return;
   
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double minBody = MinOBBodyPips * point;
   
   double body = MathAbs(close[bar] - open[bar]);
   if(body < minBody) return;
   
   // 看涨 OB
   if(close[bar] > open[bar] && 
      close[bar] > high[bar - 1] &&
      close[bar - 1] < open[bar - 1])
   {
      AddOrderBlock(time[bar - 1], high[bar - 1], low[bar - 1], true, body / point);
   }
   
   // 看跌 OB
   if(close[bar] < open[bar] && 
      close[bar] < low[bar - 1] &&
      close[bar - 1] > open[bar - 1])
   {
      AddOrderBlock(time[bar - 1], high[bar - 1], low[bar - 1], false, body / point);
   }
}

//+------------------------------------------------------------------+
//| 添加订单块                                                        |
//+------------------------------------------------------------------+
void AddOrderBlock(datetime t, double top, double bottom, bool bull, double strength)
{
   if(obCount >= MaxActiveOB) return;
   
   OrderBlock ob;
   ob.time = t;
   ob.top = top;
   ob.bottom = bottom;
   ob.isBullish = bull;
   ob.isValid = true;
   ob.strength = strength;
   ob.objName = "SMC_OB_" + TimeToString(t, TIME_DATE|TIME_MINUTES);
   
   // 检查重复
   for(int i = 0; i < obCount; i++)
   {
      if(activeOBs[i].objName == ob.objName) return;
   }
   
   ArrayResize(activeOBs, obCount + 1);
   activeOBs[obCount] = ob;
   obCount++;
   
   DrawAllOrderBlocks();
}

//+------------------------------------------------------------------+
//| 实时检测 FVG                                                      |
//+------------------------------------------------------------------+
void DetectNewFVG(int bar, const datetime &time[], const double &high[], const double &low[])
{
   if(bar < 2) return;
   
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double minSize = MinFVGSizePips * point;
   
   // 看涨 FVG
   if(high[bar - 2] < low[bar])
   {
      double gap = low[bar] - high[bar - 2];
      if(gap >= minSize)
      {
         AddFVG(time[bar - 1], low[bar], high[bar - 2], true);
      }
   }
   
   // 看跌 FVG
   if(low[bar - 2] > high[bar])
   {
      double gap = low[bar - 2] - high[bar];
      if(gap >= minSize)
      {
         AddFVG(time[bar - 1], low[bar - 2], high[bar], false);
      }
   }
}

//+------------------------------------------------------------------+
//| 添加 FVG                                                          |
//+------------------------------------------------------------------+
void AddFVG(datetime t, double top, double bottom, bool bull)
{
   if(fvgCount >= MaxActiveFVG) return;
   
   FairValueGap fvg;
   fvg.time = t;
   fvg.top = top;
   fvg.bottom = bottom;
   fvg.isBullish = bull;
   fvg.isValid = true;
   fvg.objName = "SMC_FVG_" + TimeToString(t, TIME_DATE|TIME_MINUTES);
   
   for(int i = 0; i < fvgCount; i++)
   {
      if(activeFVGs[i].objName == fvg.objName) return;
   }
   
   ArrayResize(activeFVGs, fvgCount + 1);
   activeFVGs[fvgCount] = fvg;
   fvgCount++;
   
   DrawAllFVGs();
}

//+------------------------------------------------------------------+
//| 检测结构点                                                        |
//+------------------------------------------------------------------+
void DetectSwingPoints(int bar, int total, const datetime &time[],
                       const double &high[], const double &low[])
{
   if(bar < SwingStrength || bar + SwingStrength >= total) return;
   
   bool isHigh = true;
   for(int i = 1; i <= SwingStrength; i++)
   {
      if(high[bar - i] > high[bar] || high[bar + i] >= high[bar])
      {
         isHigh = false;
         break;
      }
   }
   
   bool isLow = true;
   for(int i = 1; i <= SwingStrength; i++)
   {
      if(low[bar - i] < low[bar] || low[bar + i] <= low[bar])
      {
         isLow = false;
         break;
      }
   }
   
   if(isHigh)
   {
      string name = "SMC_SwH_" + TimeToString(time[bar], TIME_DATE|TIME_MINUTES);
      if(ObjectFind(0, name) < 0)
      {
         ObjectCreate(0, name, OBJ_ARROW_DOWN, 0, time[bar], high[bar]);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkRed);
         ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
      }
   }
   
   if(isLow)
   {
      string name = "SMC_SwL_" + TimeToString(time[bar], TIME_DATE|TIME_MINUTES);
      if(ObjectFind(0, name) < 0)
      {
         ObjectCreate(0, name, OBJ_ARROW_UP, 0, time[bar], low[bar]);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkGreen);
         ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
      }
   }
}

//+------------------------------------------------------------------+
//| 清理函数                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, "SMC_");
   Comment("");
}
MT5 运行截图 · 完整视图带价格轴和时间轴的整张图表(约 150 根 H1 K 线),上面的封面是它最近 80 根 K 线的放大视图
SMC 机构级交易指标 在 MT5 上的真实截图

作品说明

明白了,机构级别的指标需要清晰、专业,只显示高质量信号。我重新设计一个干净的版本:只保留有效的订单块和 FVG,自动过滤低质量信号,订单块被突破后自动失效。

使用说明

核心改进(机构级特性):

  1. 智能过滤:只显示实体大于 10 点的订单块,FVG 小于 8 点直接忽略
  2. 自动失效管理:订单块被完全突破后自动从图表移除,保持干净
  3. 数量控制:最多显示 8 个订单块和 6 个 FVG,防止信息过载
  4. 强度排序:自动保留最强的订单块(按反转 K 线实体大小)
  5. 专业配色:使用半透明效果,背景不遮挡 K 线,标签清晰简洁
  6. 结构点可选:默认关闭高低点箭头,避免混乱,需要时再开启

参数建议(黄金 H1):

  • 结构强度:7(严格确认,减少假信号)
  • 订单块最小实体:10-15 点(黄金波动大,过滤小反转)
  • FVG 最小尺寸:8-12 点(只标记明显缺口)
  • 最多订单块数量:5-8 个(图表保持整洁)
  • 自动移除失效:必须开启(这是机构级的关键)

配色方案:

  • 看涨订单块:深蓝色半透明(专业、不刺眼)
  • 看跌订单块:深红色半透明
  • FVG:更淡的青绿/浅粉,虚线边框
  • 透明度:85-90%,既能看清区域又不遮挡价格

交易逻辑:

  1. 等待价格首次回到订单块区域(未被触碰的最佳)
  2. 在订单块内寻找反转确认(针形线、吞没)
  3. 止损放在订单块外 5-10 点
  4. 订单块被完全突破 = 结构失效,指标会自动移除

与普通版本的区别:

  • 普通版:所有信号都显示,图表像圣诞树
  • 机构版:只显示高概率区域,一眼看清关键位置
  • 失效管理:自动清理无效订单块,保持专业外观
  • 视觉设计:配色、透明度、标签都按机构交易室标准

注意事项:

  • 首次加载扫描 500 根 K 线,H1 周期约 1 个月历史
  • 如果订单块太少,降低"最小实体"参数
  • 如果图表仍然混乱,减小"最多显示数量"
  • 此指标只标记区域,入场时机需结合价格行为确认

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

这是什么

这是一个基于 Smart Money Concepts(SMC,智能资金概念)的 MT5 指标,主要标记订单块(Order Block)和公允价值缺口(Fair Value Gap,FVG)两类关键区域。与常见的 SMC 指标不同,它内置了智能过滤和失效管理机制:只显示实体足够大的订单块和缺口,订单块被价格完全突破后自动从图表上移除,避免信息过载。适合需要干净图表、专注于高概率交易区域的用户。

逻辑原理

订单块识别:扫描 K 线序列,当出现一根大实体 K 线(实体大于设定点数)吞没前一根反向 K 线时,将被吞没的那根 K 线的高低点范围标记为订单块。看涨订单块是阳线吞没前一根阴线并突破其高点,看跌订单块是阴线吞没前一根阳线并跌破其低点。每个订单块会记录其强度(反转 K 线的实体大小),系统按强度排序并只保留最强的若干个(由"最多显示订单块数量"参数控制)。

FVG 识别:检测三根连续 K 线,如果第三根 K 线的低点高于第一根的高点(看涨缺口),或第三根的高点低于第一根的低点(看跌缺口),且缺口尺寸大于设定值,则在第二根 K 线位置标记 FVG 区域。系统保留最新的若干个 FVG。

失效管理:每次新 K 线生成时,检查所有订单块。看涨订单块如果被价格跌破其下沿,看跌订单块如果被突破其上沿,立即将该区域标记为失效并从图表删除。这避免了过期区域堆积。

结构点(可选):使用左右各 N 根 K 线确认法标记波段高点和低点,默认关闭,需要时可打开。

参数说明

  • 结构强度(默认 7):确认结构高低点时需要左右各多少根 K 线支撑。数值越大,确认越严格,结构点越少但更可靠。关系到订单块和结构点检测的严谨度,建议 5-10。
  • 订单块最小实体(默认 10 点):订单块的反转 K 线实体必须大于这个点数才会被标记。黄金等波动大的品种建议 10-15 点,货币对可用 5-8 点。过小会产生大量低质量区域。
  • FVG 最小尺寸(默认 8 点):缺口的垂直距离必须大于此值才显示。调高可过滤噪音,调低可捕捉更多小缺口。黄金建议 8-12 点。
  • 自动移除失效订单块(默认开启):订单块被突破后是否自动删除。强烈建议开启,这是本指标的核心特性,保持图表专业整洁。
  • 最多显示订单块数量(默认 8):图表上同时显示的订单块上限。超过此数量时,只保留强度最高的若干个。建议 5-10,避免混乱。
  • 最多显示 FVG 数量(默认 6):图表上同时显示的 FVG 上限,保留最新的几个。建议 5-8。
  • 显示结构高低点(默认关闭):是否在波段高低点画箭头。一般不需要,开启后会增加视觉干扰。
  • 显示订单块 / FVG / 标签:控制各类元素的显示开关。标签是订单块旁边的"OB↑"/"OB↓"文字。
  • 订单块延伸长度(默认 100):订单块矩形向右延伸多少根 K 线。如果周期较大,可适当增加。
  • 配色和透明度:订单块用深蓝(看涨)和深红(看跌),FVG 用青绿和浅粉。透明度 85-90% 可在标记区域的同时不遮挡价格走势。

怎么用

将 .mq5 文件放入 MT5 的 Indicators 目录,编译后拖到任意品种任意周期的图表上。指标初始化时会自动扫描最近 500 根 K 线的历史数据,标记出满足条件的订单块和 FVG。之后每生成新 K 线都会实时检测和更新。

订单块显示为半透明矩形,看涨的蓝色、看跌的红色;FVG 显示为更淡的矩形且用虚线边框。交易时等待价格回到订单块区域(尤其是未被触碰过的),在区域内寻找反转确认信号(如针形线、吞没形态),止损设在订单块外几个点。如果价格完全突破订单块,区域会自动消失,说明该结构已失效,不应再依赖它做交易。

FVG 通常被视为价格回补目标,可结合订单块使用:价格回到 FVG 内部可能遇到支撑/阻力,或继续回补缺口。

适用场景

适合黄金(XAUUSD)、主要货币对(EURUSD、GBPUSD 等)和指数,在 H1、H4、D1 等较大周期上效果较好。订单块和 FVG 在趋势行情中作为回调入场点有较高胜率,震荡市中也可作为区间边界参考。

不适合极短周期(M1、M5)——噪音太多,过滤阈值难以把握。不适合低波动品种或冷门交易时段——K 线实体太小,难以形成有效订单块。强趋势单边行情中,价格可能不回调就直接突破订单块,此时失效管理会快速清除旧区域,需结合其他工具确认入场。

风险提示

订单块和 FVG 都是基于历史 K 线形态识别的,不预测未来,只标记潜在的支撑阻力区域。价格回到区域后是否真的反转,取决于当时的市场结构和资金流向,指标本身不提供入场时机确认。

滞后性:订单块需要等待反转 K 线收盘并经过"结构强度"参数设定的确认期才会显示,实时性较差。如果参数设置过于宽松(最小实体过小、最大数量过多),图表仍会变得混乱,失去筛选意义。

失效判断是机械的:只要价格触及订单块边界就算突破,不考虑假突破或插针。真实交易中可能需要等待 K 线实体收盘确认。

不处理重绘:历史扫描和实时检测的逻辑一致,不会重绘已确认的订单块,但如果修改参数或切换周期,指标会重新计算并可能显示不同的区域。

透明度问题:代码中透明度设置使用了 RGBA 格式(alpha 通道左移 24 位),但 MT5 的对象透明度实现可能因平台版本而异,部分情况下透明效果可能不明显或无效,需自行调整参数。

常见问题

这个指标会重绘吗?
不会。订单块和 FVG 一旦确认就固定在图表上,只会因为被突破而删除,不会改变已标记区域的位置或属性。但如果重新加载指标或修改参数,会根据新参数重新计算。
订单块被突破后还能用吗?
不能。代码设计逻辑是订单块被完全突破后立即失效并从图表删除,说明该支撑/阻力已被打破,不应继续依赖它交易。
能用在 XAUUSD 以外的品种吗?
可以。代码没有限制品种,黄金、外汇、指数都能用。但需要根据品种的点值和波动特性调整"最小实体"和"最小 FVG 尺寸"参数。例如 EURUSD 可以用 5-8 点,黄金用 10-15 点。
为什么图表上订单块很少或没有?
可能是"订单块最小实体"参数设置过大,或"最多显示数量"过小。降低最小实体阈值或增加显示数量。也可能当前周期内没有形成符合条件的强反转形态。
MT4 能用吗?
不能直接用。这是 MQL5 代码,MT4 使用 MQL4,语法和函数不兼容。需要将代码改写为 MQL4 版本才能在 MT4 上运行。

MT5 SMC Institutional Order Block & FVG Indicator

A professional Smart Money Concepts indicator that automatically identifies high-quality order blocks and fair value gaps. Features intelligent filtering, automatic invalidation management, and clean visualization with strength-based ranking.

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

评论

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

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