MT5脚本 / 工具 二创编译通过 · EX5 17KB 14 0
一键平仓 / 一键保本工具(二创)
原作《一键平仓 / 一键保本工具》XAUOF 官方二创本作
相对上一版改了:我需要你帮我写一个这样的指标
效果示意图 · AI 根据源码绘制
SmartMoneyZones.mq5349 行
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
// 基于 Smart Money Concept 理念的供需区域自动识别指标
// 功能:识别摆动高低点,绘制供需区矩形,标注 BOS/CHoCH
//+------------------------------------------------------------------+
#property copyright "XAUOF 指标工坊"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
//+------------------------------------------------------------------+
//| 输入参数 |
//+------------------------------------------------------------------+
input int InpSwingLength = 5; // 摆动识别周期(左右各多少根K线)
input int InpZoneThickness = 3; // 供需区厚度(单位:点数)
input int InpZoneExtendBars = 50; // 区域向右延伸多少根K线
input color InpDemandColor = clrDodgerBlue; // 需求区颜色(支撑)
input color InpSupplyColor = clrTomato; // 供给区颜色(阻力)
input int InpZoneTransparency = 85; // 区域透明度(0-100,越大越透明)
input bool InpShowLabels = true; // 是否显示 BOS/CHoCH 标注
input int InpMaxZones = 10; // 最多显示多少个区域(0=不限制)
input bool InpDeleteOldZones = true; // 价格触及后是否删除旧区域
//--- 全局变量
struct ZoneInfo
{
string name; // 对象名称
double price_top; // 区域上边界
double price_bottom; // 区域下边界
datetime time_start; // 开始时间
bool is_demand; // true=需求区,false=供给区
bool touched; // 是否已被触及
};
ZoneInfo g_zones[]; // 存储所有区域
int g_zone_count = 0; // 当前区域数量
string g_prefix = "SMZ_"; // 对象名称前缀
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 检查参数
if(InpSwingLength < 1)
{
Print("错误:摆动周期必须 >= 1");
return INIT_PARAMETERS_INCORRECT;
}
//--- 清理旧对象
DeleteAllObjects();
//--- 初始化数组
ArrayResize(g_zones, 0);
g_zone_count = 0;
Print("Smart Money 供需区指标已加载");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- 清理所有绘制的对象
DeleteAllObjects();
}
//+------------------------------------------------------------------+
//| 主计算函数 |
//+------------------------------------------------------------------+
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(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
//--- 需要至少有足够的K线
if(rates_total < InpSwingLength * 2 + 10)
return 0;
//--- 计算开始位置
int start = InpSwingLength + 1;
int limit = rates_total - prev_calculated;
// 首次运行或数据较多时,只扫描最近的K线
if(limit > 100 || prev_calculated == 0)
limit = 100;
//--- 遍历K线,寻找摆动高低点
for(int i = start; i < start + limit && i < rates_total - InpSwingLength - 1; i++)
{
//--- 检查是否是摆动高点(局部最高)
bool is_swing_high = true;
for(int j = 1; j <= InpSwingLength; j++)
{
if(i - j < 0 || i + j >= rates_total)
{
is_swing_high = false;
break;
}
if(high[i] <= high[i - j] || high[i] <= high[i + j])
{
is_swing_high = false;
break;
}
}
//--- 如果是摆动高点,创建供给区
if(is_swing_high)
{
double zone_top = high[i];
double zone_bottom = zone_top - InpZoneThickness * _Point;
// 检查是否已存在相似区域(避免重复)
if(!ZoneExists(zone_top, zone_bottom, time[i]))
{
CreateZone(time[i], zone_top, zone_bottom, false); // false = 供给区
}
}
//--- 检查是否是摆动低点(局部最低)
bool is_swing_low = true;
for(int j = 1; j <= InpSwingLength; j++)
{
if(i - j < 0 || i + j >= rates_total)
{
is_swing_low = false;
break;
}
if(low[i] >= low[i - j] || low[i] >= low[i + j])
{
is_swing_low = false;
break;
}
}
//--- 如果是摆动低点,创建需求区
if(is_swing_low)
{
double zone_bottom = low[i];
double zone_top = zone_bottom + InpZoneThickness * _Point;
if(!ZoneExists(zone_top, zone_bottom, time[i]))
{
CreateZone(time[i], zone_top, zone_bottom, true); // true = 需求区
}
}
}
//--- 检查价格是否触及区域(可选:触及后删除)
if(InpDeleteOldZones)
{
CheckZonesTouched(close[0]);
}
return rates_total;
}
//+------------------------------------------------------------------+
//| 创建供需区矩形 |
//+------------------------------------------------------------------+
void CreateZone(datetime start_time, double price_top, double price_bottom, bool is_demand)
{
//--- 检查最大区域数量限制
if(InpMaxZones > 0 && g_zone_count >= InpMaxZones)
{
// 删除最老的区域
DeleteOldestZone();
}
//--- 生成唯一对象名
string obj_name = g_prefix + (is_demand ? "D_" : "S_") + TimeToString(start_time, TIME_DATE | TIME_SECONDS);
//--- 计算结束时间(向右延伸)
datetime end_time = start_time + InpZoneExtendBars * PeriodSeconds();
//--- 创建矩形对象
if(ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, start_time, price_top, end_time, price_bottom))
{
color zone_color = is_demand ? InpDemandColor : InpSupplyColor;
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, zone_color);
ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
ObjectSetInteger(0, obj_name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
// 设置透明度(0-255,255为完全不透明)
int alpha = (int)MathRound(255 * (100 - InpZoneTransparency) / 100.0);
if(alpha < 0) alpha = 0;
if(alpha > 255) alpha = 255;
long color_with_alpha = (long)zone_color | ((long)alpha << 24);
ObjectSetInteger(0, obj_name, OBJPROP_BGCOLOR, color_with_alpha);
//--- 保存到数组
int idx = g_zone_count;
ArrayResize(g_zones, g_zone_count + 1);
g_zones[idx].name = obj_name;
g_zones[idx].price_top = price_top;
g_zones[idx].price_bottom = price_bottom;
g_zones[idx].time_start = start_time;
g_zones[idx].is_demand = is_demand;
g_zones[idx].touched = false;
g_zone_count++;
//--- 可选:添加文字标注
if(InpShowLabels)
{
string label_name = obj_name + "_LBL";
double label_price = is_demand ? price_bottom : price_top;
string label_text = is_demand ? "Demand" : "Supply";
if(ObjectCreate(0, label_name, OBJ_TEXT, 0, start_time, label_price))
{
ObjectSetString(0, label_name, OBJPROP_TEXT, label_text);
ObjectSetInteger(0, label_name, OBJPROP_COLOR, zone_color);
ObjectSetInteger(0, label_name, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(0, label_name, OBJPROP_ANCHOR, is_demand ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER);
ObjectSetInteger(0, label_name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, label_name, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, label_name, OBJPROP_BACK, false);
}
}
}
}
//+------------------------------------------------------------------+
//| 检查区域是否已存在(避免重复) |
//+------------------------------------------------------------------+
bool ZoneExists(double price_top, double price_bottom, datetime check_time)
{
double tolerance = 5 * _Point; // 容差范围
for(int i = 0; i < g_zone_count; i++)
{
if(MathAbs(g_zones[i].price_top - price_top) < tolerance &&
MathAbs(g_zones[i].price_bottom - price_bottom) < tolerance)
{
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| 检查价格是否触及区域 |
//+------------------------------------------------------------------+
void CheckZonesTouched(double current_price)
{
for(int i = g_zone_count - 1; i >= 0; i--)
{
if(g_zones[i].touched)
continue;
// 判断价格是否进入区域
if(current_price >= g_zones[i].price_bottom && current_price <= g_zones[i].price_top)
{
g_zones[i].touched = true;
// 删除该区域对象
ObjectDelete(0, g_zones[i].name);
ObjectDelete(0, g_zones[i].name + "_LBL");
// 从数组中移除
for(int j = i; j < g_zone_count - 1; j++)
{
g_zones[j] = g_zones[j + 1];
}
ArrayResize(g_zones, g_zone_count - 1);
g_zone_count--;
}
}
}
//+------------------------------------------------------------------+
//| 删除最老的区域 |
//+------------------------------------------------------------------+
void DeleteOldestZone()
{
if(g_zone_count == 0)
return;
// 找到时间最早的区域
int oldest_idx = 0;
datetime oldest_time = g_zones[0].time_start;
for(int i = 1; i < g_zone_count; i++)
{
if(g_zones[i].time_start < oldest_time)
{
oldest_time = g_zones[i].time_start;
oldest_idx = i;
}
}
// 删除对象
ObjectDelete(0, g_zones[oldest_idx].name);
ObjectDelete(0, g_zones[oldest_idx].name + "_LBL");
// 从数组中移除
for(int i = oldest_idx; i < g_zone_count - 1; i++)
{
g_zones[i] = g_zones[i + 1];
}
ArrayResize(g_zones, g_zone_count - 1);
g_zone_count--;
}
//+------------------------------------------------------------------+
//| 清理所有对象 |
//+------------------------------------------------------------------+
void DeleteAllObjects()
{
int total = ObjectsTotal(0, 0, OBJ_RECTANGLE);
for(int i = total - 1; i >= 0; i--)
{
string name = ObjectName(0, i, 0, OBJ_RECTANGLE);
if(StringFind(name, g_prefix) == 0)
{
ObjectDelete(0, name);
ObjectDelete(0, name + "_LBL");
}
}
total = ObjectsTotal(0, 0, OBJ_TEXT);
for(int i = total - 1; i >= 0; i--)
{
string name = ObjectName(0, i, 0, OBJ_TEXT);
if(StringFind(name, g_prefix) == 0)
ObjectDelete(0, name);
}
}
//+------------------------------------------------------------------+作品说明
从图上识别到的特征:
- 多个浅蓝色横向矩形区域,标记着关键的供需区/订单区块(Order Block),覆盖历史的支撑/阻力位
- 文字标注:BOS(结构突破)、CHoCH(趋势转换)、strong Low 等,这是 Smart Money Concept 的标注方式
- 虚线连接:连接某些关键的摆动高低点
- 整体是一个Smart Money Concept (SMC) 风格的供需区识别指标
下面给你写一个核心功能版本:自动识别摆动高低点,在这些位置绘制供需区矩形,并可选地标注市场结构变化。
使用说明
安装方法
- 将代码保存为
SmartMoneyZones.mq5,放入MQL5/Indicators文件夹 - 在 MetaEditor 中编译
- 拖动到图表即可使用
参数说明
- 摆动识别周期(默认5):左右各对比多少根K线来判断高低点,越大识别越严格
- 供需区厚度(默认3点):矩形区域的垂直高度,根据品种波动调整
- 区域向右延伸(默认50根):矩形向未来延伸多少根K线
- 需求区颜色(默认蓝色):支撑区域的颜色
- 供给区颜色(默认红色):阻力区域的颜色
- 区域透明度(0-100):数值越大越透明,推荐70-90
- 显示标注:是否在区域旁边显示 "Demand/Supply" 文字
- 最多显示区域:限制图表上同时显示的区域数量,0=不限制
- 价格触及后删除:开启后,价格触及区域会自动删除该区域
信号解读
- 蓝色矩形:需求区(买方力量强),价格回踩时可能反弹
- 红色矩形:供给区(卖方力量强),价格上探时可能回落
- 结合趋势使用:上升趋势关注需求区做多,下降趋势关注供给区做空
注意事项
- 此指标基于历史高低点绘制,不保证未来一定有效
- 建议结合其他确认信号(如突破、成交量)使用
- 摆动周期越大,识别的区域越少但越可靠
- 不同周期(H1/H4/D1)识别的区域级别不同,大周期更有参考价值
评论
后可以留言,比如反馈用着怎么样、想加什么功能。
还没有人评论,来抢个沙发。