MT5指标编译通过 · EX5 16KB 自动发布 11 0

订单块自动识别与回测提醒指标

lm152632·10 小时前发布

自动标记看涨看跌订单块矩形区域,价格回测时弹窗提醒

订单块自动识别与回测提醒指标
OrderBlock_Alert.mq5407
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
#property copyright   "XAUOF指标工坊"
#property version     "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

//+------------------------------------------------------------------+
//| 输入参数
//+------------------------------------------------------------------+
input int    MaxOrderBlocks = 5;            // 最多显示订单块数量(1-20)
input int    BreakoutCandles = 3;           // 突破确认K线数(判断趋势强度)
input double BreakoutRatio = 1.5;           // 突破K线实体倍数(相对前一根)
input color  BullishColor = clrDodgerBlue;  // 看涨订单块颜色
input color  BearishColor = clrCrimson;     // 看跌订单块颜色
input int    RectTransparency = 85;         // 矩形透明度(0-100,越大越透明)
input bool   EnableAlert = true;            // 启用回测提醒
input bool   ShowOnlyUntested = true;       // 仅显示未回测区域

//+------------------------------------------------------------------+
//| 订单块结构体
//+------------------------------------------------------------------+
struct OrderBlock
{
   datetime time;        // 订单块形成时间
   double   high;        // 区域上沿
   double   low;         // 区域下沿
   bool     is_bullish;  // true=看涨, false=看跌
   bool     is_tested;   // 是否已回测
   string   rect_name;   // 矩形对象名称
};

OrderBlock g_blocks[];          // 订单块数组
int        g_block_count = 0;   // 当前订单块数量
datetime   g_last_alert_time;   // 上次提醒时间(避免重复)

//+------------------------------------------------------------------+
//| 初始化函数
//+------------------------------------------------------------------+
int OnInit()
{
   // 参数校验
   if(MaxOrderBlocks < 1 || MaxOrderBlocks > 20)
   {
      Print("错误:订单块数量必须在1-20之间");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   ArrayResize(g_blocks, MaxOrderBlocks);
   g_block_count = 0;
   g_last_alert_time = 0;
   
   // 清理旧对象
   ObjectsDeleteAll(0, "OB_");
   
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| 反初始化函数
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // 清理所有订单块矩形
   ObjectsDeleteAll(0, "OB_");
}

//+------------------------------------------------------------------+
//| 指标计算函数
//+------------------------------------------------------------------+
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[])
{
   // 设置数组为时间序列(0为最新)
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(open, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   
   // 至少需要 BreakoutCandles+2 根K线才能识别
   if(rates_total < BreakoutCandles + 2)
      return 0;
   
   // 每次重新扫描最近的订单块(从索引3开始,避免未完成K线)
   ScanForOrderBlocks(time, open, high, low, close, rates_total);
   
   // 检查价格是否回测订单块
   if(EnableAlert)
      CheckRetestAlert(close[0]);
   
   // 更新矩形显示
   UpdateRectangles();
   
   return rates_total;
}

//+------------------------------------------------------------------+
//| 扫描订单块
//+------------------------------------------------------------------+
void ScanForOrderBlocks(const datetime &time[],
                        const double &open[],
                        const double &high[],
                        const double &low[],
                        const double &close[],
                        int rates_total)
{
   // 临时存储新发现的订单块
   OrderBlock temp_blocks[];
   ArrayResize(temp_blocks, 0);
   
   // 从第 BreakoutCandles+1 根开始扫描(跳过最新3根避免未完成)
   for(int i = BreakoutCandles + 1; i < MathMin(rates_total - 10, 500); i++)
   {
      // 检查看涨订单块:大阳线突破前面的下跌
      if(IsBullishOrderBlock(i, open, high, low, close))
      {
         OrderBlock ob;
         ob.time = time[i];
         ob.high = high[i];
         ob.low = low[i];
         ob.is_bullish = true;
         ob.is_tested = IsPriceRetested(i, close, high[i], low[i], true);
         ob.rect_name = "OB_Bull_" + TimeToString(time[i]);
         
         // 检查是否已存在
         if(!IsBlockExists(ob))
         {
            int size = ArraySize(temp_blocks);
            ArrayResize(temp_blocks, size + 1);
            temp_blocks[size] = ob;
         }
      }
      
      // 检查看跌订单块:大阴线突破前面的上涨
      if(IsBearishOrderBlock(i, open, high, low, close))
      {
         OrderBlock ob;
         ob.time = time[i];
         ob.high = high[i];
         ob.low = low[i];
         ob.is_bullish = false;
         ob.is_tested = IsPriceRetested(i, close, high[i], low[i], false);
         ob.rect_name = "OB_Bear_" + TimeToString(time[i]);
         
         if(!IsBlockExists(ob))
         {
            int size = ArraySize(temp_blocks);
            ArrayResize(temp_blocks, size + 1);
            temp_blocks[size] = ob;
         }
      }
   }
   
   // 按时间排序,保留最新的 MaxOrderBlocks 个
   SortAndLimitBlocks(temp_blocks);
}

//+------------------------------------------------------------------+
//| 判断看涨订单块
//+------------------------------------------------------------------+
bool IsBullishOrderBlock(int i,
                         const double &open[],
                         const double &high[],
                         const double &low[],
                         const double &close[])
{
   // 第 i 根是阴线(订单块候选)
   if(close[i] >= open[i])
      return false;
   
   double ob_body = open[i] - close[i];
   if(ob_body <= 0)
      return false;
   
   // 后续第 i-1 根是大阳线(突破)
   if(close[i-1] <= open[i-1])
      return false;
   
   double breakout_body = close[i-1] - open[i-1];
   
   // 突破K线实体必须大于订单块实体的 BreakoutRatio 倍
   if(breakout_body < ob_body * BreakoutRatio)
      return false;
   
   // 突破K线的收盘价必须高于订单块的高点
   if(close[i-1] <= high[i])
      return false;
   
   // 检查之前 BreakoutCandles 根是否在下跌
   for(int j = 1; j <= BreakoutCandles; j++)
   {
      if(i + j >= ArraySize(close))
         return false;
      if(close[i+j] < close[i+j-1])  // 至少有一根在下跌
         return true;
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| 判断看跌订单块
//+------------------------------------------------------------------+
bool IsBearishOrderBlock(int i,
                         const double &open[],
                         const double &high[],
                         const double &low[],
                         const double &close[])
{
   // 第 i 根是阳线(订单块候选)
   if(close[i] <= open[i])
      return false;
   
   double ob_body = close[i] - open[i];
   if(ob_body <= 0)
      return false;
   
   // 后续第 i-1 根是大阴线(突破)
   if(close[i-1] >= open[i-1])
      return false;
   
   double breakout_body = open[i-1] - close[i-1];
   
   // 突破K线实体必须大于订单块实体的 BreakoutRatio 倍
   if(breakout_body < ob_body * BreakoutRatio)
      return false;
   
   // 突破K线的收盘价必须低于订单块的低点
   if(close[i-1] >= low[i])
      return false;
   
   // 检查之前 BreakoutCandles 根是否在上涨
   for(int j = 1; j <= BreakoutCandles; j++)
   {
      if(i + j >= ArraySize(close))
         return false;
      if(close[i+j] > close[i+j-1])  // 至少有一根在上涨
         return true;
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| 检查价格是否回测过区域
//+------------------------------------------------------------------+
bool IsPriceRetested(int block_index,
                     const double &close[],
                     double block_high,
                     double block_low,
                     bool is_bullish)
{
   // 检查订单块形成后的K线是否触碰区域
   for(int i = 0; i < block_index; i++)
   {
      if(close[i] >= block_low && close[i] <= block_high)
         return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| 检查订单块是否已存在
//+------------------------------------------------------------------+
bool IsBlockExists(const OrderBlock &new_block)
{
   for(int i = 0; i < g_block_count; i++)
   {
      if(g_blocks[i].time == new_block.time)
         return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| 排序并限制订单块数量
//+------------------------------------------------------------------+
void SortAndLimitBlocks(OrderBlock &temp_blocks[])
{
   int temp_count = ArraySize(temp_blocks);
   if(temp_count == 0)
      return;
   
   // 简单冒泡排序(按时间倒序)
   for(int i = 0; i < temp_count - 1; i++)
   {
      for(int j = i + 1; j < temp_count; j++)
      {
         if(temp_blocks[i].time < temp_blocks[j].time)
         {
            OrderBlock temp = temp_blocks[i];
            temp_blocks[i] = temp_blocks[j];
            temp_blocks[j] = temp;
         }
      }
   }
   
   // 保留最新的 MaxOrderBlocks 个
   g_block_count = MathMin(temp_count, MaxOrderBlocks);
   for(int i = 0; i < g_block_count; i++)
   {
      g_blocks[i] = temp_blocks[i];
   }
}

//+------------------------------------------------------------------+
//| 检查回测提醒
//+------------------------------------------------------------------+
void CheckRetestAlert(double current_price)
{
   datetime current_time = TimeCurrent();
   
   // 避免1分钟内重复提醒
   if(current_time - g_last_alert_time < 60)
      return;
   
   for(int i = 0; i < g_block_count; i++)
   {
      // 如果已回测过且设置了仅显示未回测,跳过
      if(g_blocks[i].is_tested && ShowOnlyUntested)
         continue;
      
      // 检查当前价格是否在区域内
      if(current_price >= g_blocks[i].low && current_price <= g_blocks[i].high)
      {
         if(!g_blocks[i].is_tested)  // 首次回测
         {
            string msg = StringFormat("价格回测%s订单块!\n时间:%s\n区域:%.5f - %.5f",
                                    g_blocks[i].is_bullish ? "看涨" : "看跌",
                                    TimeToString(g_blocks[i].time),
                                    g_blocks[i].low,
                                    g_blocks[i].high);
            Alert(msg);
            g_blocks[i].is_tested = true;
            g_last_alert_time = current_time;
            break;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| 更新矩形显示
//+------------------------------------------------------------------+
void UpdateRectangles()
{
   // 先清理所有旧矩形
   ObjectsDeleteAll(0, "OB_");
   
   for(int i = 0; i < g_block_count; i++)
   {
      // 如果设置了仅显示未回测,且已回测,跳过
      if(ShowOnlyUntested && g_blocks[i].is_tested)
         continue;
      
      // 创建矩形
      string name = g_blocks[i].rect_name;
      datetime time_right = TimeCurrent() + PeriodSeconds(PERIOD_CURRENT) * 50;  // 延伸到右侧
      
      ObjectCreate(0, name, OBJ_RECTANGLE, 0,
                   g_blocks[i].time, g_blocks[i].high,
                   time_right, g_blocks[i].low);
      
      // 设置颜色和透明度
      color rect_color = g_blocks[i].is_bullish ? BullishColor : BearishColor;
      ObjectSetInteger(0, name, OBJPROP_COLOR, rect_color);
      ObjectSetInteger(0, name, OBJPROP_FILL, true);
      ObjectSetInteger(0, name, OBJPROP_BACK, true);
      ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
      
      // 设置透明度(0-255,255为完全透明)
      int transparency = (int)MathRound(RectTransparency * 2.55);
      ObjectSetInteger(0, name, OBJPROP_BGCOLOR, ColorToARGB(rect_color, transparency));
      
      // 添加文字标签
      string label_name = name + "_Label";
      ObjectCreate(0, label_name, OBJ_TEXT, 0, g_blocks[i].time, g_blocks[i].high);
      ObjectSetString(0, label_name, OBJPROP_TEXT, g_blocks[i].is_bullish ? "OB↑" : "OB↓");
      ObjectSetInteger(0, label_name, OBJPROP_COLOR, rect_color);
      ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 8);
      ObjectSetInteger(0, label_name, OBJPROP_BACK, false);
   }
   
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| 颜色转ARGB(带透明度)
//+------------------------------------------------------------------+
uint ColorToARGB(color clr, int alpha)
{
   uint r = (clr & 0xFF);
   uint g = ((clr >> 8) & 0xFF);
   uint b = ((clr >> 16) & 0xFF);
   return (alpha << 24) | (r << 16) | (g << 8) | b;
}
//+------------------------------------------------------------------+
真实 MT5 运行截图服务器把编译好的 EX5 挂到黄金 H1 图表上截的,上面的封面就是照着它画的
订单块自动识别与回测提醒指标 在 MT5 上的真实截图

作品说明

思路说明

订单块(Order Block)是指价格剧烈波动前的最后一根反向K线,代表机构建仓区域。识别逻辑:

  • 看涨OB:下跌后出现大阳线突破,前一根阴线为看涨订单块
  • 看跌OB:上涨后出现大阴线突破,前一根阳线为看跌订单块
  • 用矩形标记区域(高低点),价格回测时弹窗提醒
  • 可设置最多保留几个有效区域,自动清理旧区域

使用说明

安装步骤:

  1. 复制代码到 MetaEditor,保存为 OrderBlock_Alert.mq5
  2. 编译无误后,拖到任意图表即可使用

参数设置:

  • 最多显示订单块数量:建议 3-5 个,太多会混乱
  • 突破确认K线数:默认 3 根,判断趋势强度
  • 突破K线实体倍数:默认 1.5 倍,越大过滤越严格
  • 矩形透明度:0-100,推荐 80-90,既能看清又不遮挡价格
  • 仅显示未回测区域:打钩后,已触及的订单块会自动隐藏

信号解读:

  • 蓝色矩形(OB↑):看涨订单块,价格回测可考虑做多
  • 红色矩形(OB↓):看跌订单块,价格回测可考虑做空
  • 弹窗提醒时说明价格正在回测,结合其他指标确认入场

注意事项:

  1. 订单块不是百分百有效,需结合趋势和成交量判断
  2. 回测时不一定立即反弹,可能穿透或反复测试
  3. 建议在 H1 及以上周期使用,M5/M15 容易产生假信号
  4. 弹窗提醒有 1 分钟冷却,避免频繁弹窗干扰交易

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

这是什么

这是一个 MT5 订单块识别指标,自动找出价格剧烈突破前的最后一根反向 K 线,用蓝色或红色矩形标记出来。当价格回测这些区域时会弹窗提醒你,帮你抓住可能的支撑阻力位。

逻辑原理

订单块的核心是「反转前的最后建仓位置」。指标用两步判断:

看涨订单块:先找一根阴线,后面紧跟一根大阳线,阳线实体要超过阴线的 1.5 倍(默认),且收盘价突破阴线高点,之前还得有下跌。那根阴线就是看涨订单块,用蓝色矩形框住它的高低点。

看跌订单块:反过来,先找一根阳线,后面跟大阴线,阴线实体超过阳线 1.5 倍,收盘价跌破阳线低点,之前有上涨。那根阳线就是看跌订单块,红色矩形标记。

矩形会延伸到右侧,价格回测进区域时弹窗提醒你「价格回测看涨/看跌订单块」,提醒间隔 1 分钟防止刷屏。已经回测过的区域可以选择隐藏。

参数说明

MaxOrderBlocks(默认 5):图表上最多保留几个订单块矩形。太多会乱,建议 3-5 个,只看最新的几个就够。

BreakoutCandles(默认 3):判断趋势强度用的,检查订单块前面几根 K 线是不是在下跌(看涨)或上涨(看跌)。越大要求趋势越明显,但会漏掉一些信号。

BreakoutRatio(默认 1.5):突破 K 线的实体要达到订单块实体的几倍才算有效。调大过滤更严,假信号少但真信号也会少;调小信号多但容易误报。

BullishColor / BearishColor:看涨和看跌订单块的矩形颜色,默认蓝色和红色,随你喜好改。

RectTransparency(默认 85):矩形透明度,0 完全不透明,100 完全透明。85-90 之间既能看清区域又不挡住价格走势。

EnableAlert(默认开启):价格回测订单块时是否弹窗提醒,关掉就只显示矩形不提醒。

ShowOnlyUntested(默认开启):只显示还没被价格碰过的订单块。打开后,已经回测过的矩形会自动消失,图表更干净。

怎么用

把代码复制到 MetaEditor 保存成 OrderBlock_Alert.mq5,编译后拖到任意图表。蓝色矩形是看涨订单块,价格回测可以考虑做多;红色矩形是看跌订单块,回测可以考虑做空。

弹窗提醒说明价格正在测试区域,但不要盲目进场,结合趋势、成交量、其他指标一起判断。矩形右侧会延伸 50 根 K 线,方便你看后续价格反应。

适用场景

订单块逻辑在 H1、H4、D1 这些大周期上比较靠谱,机构建仓痕迹更明显。M5、M15 小周期容易被噪音干扰,假突破多,不建议用。

品种上没有限制,黄金、外汇、指数都能用,但最好选流动性好、走势相对规律的。配合趋势指标(均线、MACD)效果更好,顺势时回测订单块的成功率高。

横盘震荡行情慎用,频繁假突破会产生一堆无效订单块。单边趋势行情里,回测订单块往往是加仓点,这时候指标最有用。

风险提示

订单块不是百分百有效。价格回测不一定立即反弹,可能直接穿透或者反复测试好几次才反转。别把它当做唯一信号,单独用风险很大。

小周期(M5/M15)假信号多,突破可能只是短期波动,不代表真实的机构行为。代码判断的「突破」是基于收盘价和实体大小,盘中可能有假动作,最好等 K 线走完再确认。

弹窗提醒有 1 分钟冷却,如果价格在区域里反复横跳,你不会收到连续提醒。已回测的区域如果设置了隐藏,价格二次测试时不会再提醒你。

代码不包含任何止损止盈逻辑,也不会自动下单,所有交易决策还是得你自己做。

常见问题

这个指标会重绘吗?
不会。订单块一旦形成就固定了,矩形位置不会变。只有已回测状态会更新,但历史区域不会消失或移动。
M15 周期能用吗,还是只能用 H1 以上?
代码没有周期限制,但 M15 假突破多,容易产生无效订单块。建议 H1 及以上周期,机构建仓痕迹更明显。
已经回测过的订单块还有用吗?
有用。价格可能多次测试同一区域,二次回测也是潜在机会。如果你只想看未测试的,打开「仅显示未回测区域」参数。
突破倍数默认 1.5 合适吗,要不要调?
1.5 是个中间值,H1 周期够用。如果假信号多就调到 2.0 过滤更严,如果漏掉太多真信号可以降到 1.2-1.3,需要自己测试。
能用在黄金以外的品种吗?
可以。代码没有品种限制,外汇、指数、原油都能用。流动性好、波动规律的品种效果更好,冷门品种可能不太准。

Order Block Retest Alert Indicator MT5

Automatically identifies bullish and bearish order blocks and marks them with rectangles. Sends alerts when price retests these zones. Configurable display limits, breakout ratios, and transparency.

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

评论

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

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