MT5指标编译通过 · EX5 17KB 11 6
订单块(供需区)自动识别
自动画出最近的看涨、看跌订单块矩形,价格回到区域内时弹窗提醒

OrderBlock_Indicator.mq5328 行
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
#property copyright "Order Block Indicator"
#property link ""
#property version "1.00"
#property indicator_chart_window
#property indicator_plots 0
// ========== 可调参数 ==========
input int MaxBlocks = 5; // 最多显示订单块数量(推荐3-5个)
input int ExtendBars = 50; // 矩形向右延伸K线数(推荐30-100)
input double BreakoutMultiplier = 1.5; // 突破强度最小倍数(突破K线长度需≥订单块K线×此倍数,推荐1.5-3.0)
input bool AlertOnReturn = true; // 价格回到区域时是否弹窗提醒
input color BullishColor = clrLimeGreen;// 看涨订单块颜色
input color BearishColor = clrRed; // 看跌订单块颜色
input int Transparency = 85; // 矩形透明度(0-100,越大越透明)
// ========== 订单块结构 ==========
struct OrderBlock {
int type; // 1=看涨,-1=看跌,0=无效
double priceTop; // 矩形上边界
double priceBottom; // 矩形下边界
datetime timeStart; // 起始时间
int barIndex; // 订单块K线索引
bool alerted; // 是否已提醒
string objectName; // 矩形对象名称
};
OrderBlock blocks[]; // 存储所有订单块
int blockCount = 0; // 当前订单块数量
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit() {
// 设置定时器,每秒检查一次价格回归提醒
if(AlertOnReturn) {
EventSetTimer(1);
}
// 初始化订单块数组
ArrayResize(blocks, MaxBlocks);
for(int i = 0; i < MaxBlocks; i++) {
blocks[i].type = 0;
blocks[i].alerted = false;
blocks[i].objectName = "";
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
// 删除所有订单块矩形
for(int i = 0; i < MaxBlocks; i++) {
if(blocks[i].objectName != "") {
ObjectDelete(0, blocks[i].objectName);
}
}
// 删除定时器
EventKillTimer();
}
//+------------------------------------------------------------------+
//| 主计算函数 |
//+------------------------------------------------------------------+
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是最新K线)
ArraySetAsSeries(time, true);
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
// 至少需要3根K线才能识别订单块
if(rates_total < 3) return(0);
// 从最近的K线开始扫描(跳过正在形成的K线0)
int start = 1;
if(prev_calculated > 0) {
start = 1; // 每次只检查最近的几根K线
}
// 扫描新的订单块(从索引1到10,只识别最近形成的)
for(int i = start; i < MathMin(10, rates_total - 1); i++) {
// 检查看涨订单块:i-1是下跌K线,i是强势上涨突破前高
if(i >= 1 && i < rates_total - 1) {
double prevOpen = open[i];
double prevClose = close[i];
double prevHigh = high[i];
double prevLow = low[i];
double currOpen = open[i-1];
double currClose = close[i-1];
double currHigh = high[i-1];
double currLow = low[i-1];
// 看涨订单块识别:prev是下跌K线,curr是上涨K线且突破前高
if(prevClose < prevOpen) { // prev是下跌K线
double prevBodySize = prevOpen - prevClose;
double currBodySize = MathAbs(currClose - currOpen);
// 检查curr是否强势突破(上涨且突破前高,且强度足够)
if(currClose > currOpen &&
currHigh > prevHigh &&
prevBodySize > 0 &&
currBodySize >= prevBodySize * BreakoutMultiplier) {
// 检查是否已存在相同位置的订单块
bool exists = false;
for(int j = 0; j < MaxBlocks; j++) {
if(blocks[j].type == 1 &&
MathAbs(blocks[j].timeStart - time[i]) < PeriodSeconds(PERIOD_CURRENT) * 2) {
exists = true;
break;
}
}
if(!exists) {
// 创建新的看涨订单块(使用prev的实体范围)
AddOrderBlock(1, prevOpen, prevClose, time[i], i);
}
}
}
// 看跌订单块识别:prev是上涨K线,curr是下跌K线且跌破前低
if(prevClose > prevOpen) { // prev是上涨K线
double prevBodySize = prevClose - prevOpen;
double currBodySize = MathAbs(currClose - currOpen);
// 检查curr是否强势跌破(下跌且跌破前低,且强度足够)
if(currClose < currOpen &&
currLow < prevLow &&
prevBodySize > 0 &&
currBodySize >= prevBodySize * BreakoutMultiplier) {
// 检查是否已存在相同位置的订单块
bool exists = false;
for(int j = 0; j < MaxBlocks; j++) {
if(blocks[j].type == -1 &&
MathAbs(blocks[j].timeStart - time[i]) < PeriodSeconds(PERIOD_CURRENT) * 2) {
exists = true;
break;
}
}
if(!exists) {
// 创建新的看跌订单块(使用prev的实体范围)
AddOrderBlock(-1, prevClose, prevOpen, time[i], i);
}
}
}
}
}
// 更新所有订单块矩形位置和检查是否被突破
UpdateOrderBlocks(time, close);
return(rates_total);
}
//+------------------------------------------------------------------+
//| 添加新订单块 |
//+------------------------------------------------------------------+
void AddOrderBlock(int type, double top, double bottom, datetime startTime, int barIdx) {
// 确保top > bottom
if(top < bottom) {
double temp = top;
top = bottom;
bottom = temp;
}
// 查找空位或替换最老的订单块
int idx = -1;
for(int i = 0; i < MaxBlocks; i++) {
if(blocks[i].type == 0) {
idx = i;
break;
}
}
// 如果没有空位,删除最老的
if(idx == -1) {
idx = MaxBlocks - 1;
if(blocks[idx].objectName != "") {
ObjectDelete(0, blocks[idx].objectName);
}
// 向后移动数组
for(int i = MaxBlocks - 1; i > 0; i--) {
blocks[i] = blocks[i-1];
}
idx = 0;
}
// 创建新订单块
blocks[idx].type = type;
blocks[idx].priceTop = top;
blocks[idx].priceBottom = bottom;
blocks[idx].timeStart = startTime;
blocks[idx].barIndex = barIdx;
blocks[idx].alerted = false;
blocks[idx].objectName = "OB_" + IntegerToString(type) + "_" + TimeToString(startTime, TIME_DATE|TIME_SECONDS);
// 创建矩形对象
CreateRectangle(blocks[idx]);
}
//+------------------------------------------------------------------+
//| 创建矩形对象 |
//+------------------------------------------------------------------+
void CreateRectangle(OrderBlock &block) {
datetime endTime = block.timeStart + PeriodSeconds(PERIOD_CURRENT) * ExtendBars;
color rectColor = (block.type == 1) ? BullishColor : BearishColor;
// 创建矩形
ObjectCreate(0, block.objectName, OBJ_RECTANGLE, 0, block.timeStart, block.priceTop, endTime, block.priceBottom);
ObjectSetInteger(0, block.objectName, OBJPROP_COLOR, rectColor);
ObjectSetInteger(0, block.objectName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, block.objectName, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, block.objectName, OBJPROP_FILL, true);
ObjectSetInteger(0, block.objectName, OBJPROP_BACK, true);
// 设置透明度(0-255,255是完全透明)
int alpha = (int)((Transparency / 100.0) * 255);
ObjectSetInteger(0, block.objectName, OBJPROP_BGCOLOR, ColorWithAlpha(rectColor, alpha));
// 设置描述
string desc = (block.type == 1) ? "看涨订单块" : "看跌订单块";
ObjectSetString(0, block.objectName, OBJPROP_TOOLTIP, desc);
}
//+------------------------------------------------------------------+
//| 颜色透明度处理 |
//+------------------------------------------------------------------+
color ColorWithAlpha(color baseColor, int alpha) {
// MQL5的颜色格式:0xAARRGGBB
int r = (baseColor & 0xFF);
int g = ((baseColor >> 8) & 0xFF);
int b = ((baseColor >> 16) & 0xFF);
return (color)((alpha << 24) | (b << 16) | (g << 8) | r);
}
//+------------------------------------------------------------------+
//| 更新订单块并检查是否被突破 |
//+------------------------------------------------------------------+
void UpdateOrderBlocks(const datetime &time[], const double &close[]) {
double currentPrice = close[0];
for(int i = 0; i < MaxBlocks; i++) {
if(blocks[i].type == 0) continue;
// 更新矩形右边界时间
datetime endTime = TimeCurrent() + PeriodSeconds(PERIOD_CURRENT) * ExtendBars;
ObjectSetInteger(0, blocks[i].objectName, OBJPROP_TIME, 1, endTime);
// 检查是否被完全突破
bool breached = false;
if(blocks[i].type == 1) {
// 看涨订单块被向下突破
if(currentPrice < blocks[i].priceBottom) {
breached = true;
}
} else if(blocks[i].type == -1) {
// 看跌订单块被向上突破
if(currentPrice > blocks[i].priceTop) {
breached = true;
}
}
// 如果被突破,删除订单块
if(breached) {
ObjectDelete(0, blocks[i].objectName);
blocks[i].type = 0;
blocks[i].objectName = "";
}
}
}
//+------------------------------------------------------------------+
//| 定时器函数:检查价格是否回到订单块区域 |
//+------------------------------------------------------------------+
void OnTimer() {
if(!AlertOnReturn) return;
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
for(int i = 0; i < MaxBlocks; i++) {
if(blocks[i].type == 0) continue;
// 检查价格是否在订单块范围内
bool inZone = (currentPrice >= blocks[i].priceBottom && currentPrice <= blocks[i].priceTop);
// 如果价格回到区域且未提醒过
if(inZone && !blocks[i].alerted) {
string alertMsg = "";
if(blocks[i].type == 1) {
alertMsg = "价格回到看涨订单块区域!\n价格: " + DoubleToString(currentPrice, _Digits) +
"\n区域: " + DoubleToString(blocks[i].priceBottom, _Digits) + " - " + DoubleToString(blocks[i].priceTop, _Digits);
} else {
alertMsg = "价格回到看跌订单块区域!\n价格: " + DoubleToString(currentPrice, _Digits) +
"\n区域: " + DoubleToString(blocks[i].priceBottom, _Digits) + " - " + DoubleToString(blocks[i].priceTop, _Digits);
}
Alert(alertMsg);
blocks[i].alerted = true;
}
// 如果价格离开区域,重置提醒标志
if(!inZone) {
blocks[i].alerted = false;
}
}
}
//+------------------------------------------------------------------+作品说明
思路说明
订单块(Order Block)是 Smart Money 概念中的重要支撑/阻力区域。本指标通过识别「冲动突破前的最后一根反向K线」来标记订单块:
- 看涨订单块:下跌K线被后续强势上涨突破 → 该下跌K线实体是潜在支撑
- 看跌订单块:上涨K线被后续强势下跌突破 → 该上涨K线实体是潜在阻力
用半透明矩形标记这些区域并向右延伸,当价格回到区域时可选弹窗提醒,区域被完全突破后自动删除,始终保留最近的有效订单块。
使用说明
安装方法
- 将代码保存为
OrderBlock_Indicator.mq5,放入 MT5 的MQL5/Indicators文件夹 - 在 MetaEditor 中编译(F7),确保无错误
- 在图表上右键 → "技术指标列表" → "自定义" → 选择
OrderBlock_Indicator
参数调节
- 最多显示订单块数量:建议 3-5 个,太多会让图表杂乱
- 矩形向右延伸K线数:根据交易周期调整,H1 建议 50-100,M15 建议 30-50
- 突破强度最小倍数:默认 1.5 表示突破K线实体长度需≥订单块K线的 1.5 倍,数值越大过滤越严格
- 价格回到区域时弹窗提醒:开启后,当价格首次回到订单块区域时会弹窗提示(可能是潜在入场机会)
- 颜色和透明度:可根据个人喜好调整,透明度建议 70-90 之间
信号解读
- 绿色矩形(看涨订单块):机构可能在此区域布局多单,价格回到该区域可能获得支撑
- 红色矩形(看跌订单块):机构可能在此区域布局空单,价格回到该区域可能遇到阻力
- 订单块被完全突破后会自动删除,说明该区域已失效
- 最佳入场时机:价格首次回到订单块区域时(配合其他信号确认)
注意事项
- 订单块不是绝对支撑/阻力,需结合趋势、成交量等多维度分析
- 在震荡市中订单块可能频繁失效,建议在趋势明确时使用
- 弹窗提醒只在价格首次进入区域时触发,避免频繁打扰
- 较小周期(如 M1/M5)订单块失效快,建议用 M15 及以上周期
评论
后可以留言,比如反馈用着怎么样、想加什么功能。
还没有人评论,来抢个沙发。