MT5指标编译通过 · EX5 31KB 自动发布 1 0

黄金多周期趋势共振指标

18150169931·58 分钟前发布

日线/4小时/1小时 EMA20与EMA60 方向一致时右上角亮出多头或空头共振信号

黄金多周期趋势共振指标

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

XAUOF_MTF_Resonance.mq5475 行
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
//+------------------------------------------------------------------+
//|                                          XAUOF_MTF_Resonance.mq5 |
//|                                                     XAUOF 指标工坊 |
//+------------------------------------------------------------------+
#property copyright "XAUOF 指标工坊"
#property link      "https://www.xauof.com"
#property version   "1.00"
#property description "多周期趋势共振:日线/4小时/1小时 的 EMA20 与 EMA60 方向一致时给出共振提示"

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   2

//--- 图形1:多头共振出现的箭头(向上)
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrLimeGreen
#property indicator_width1  3
#property indicator_label1  "多头共振"
//--- 图形2:空头共振出现的箭头(向下)
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrTomato
#property indicator_width2  3
#property indicator_label2  "空头共振"

//+------------------------------------------------------------------+
//| 可调参数(全部集中在这里)                                          |
//+------------------------------------------------------------------+
input int              InpFastPeriod   = 20;                // 快线均线周期(默认 20,数字越小越灵敏)
input int              InpSlowPeriod   = 60;                // 慢线均线周期(默认 60,必须大于快线)
input ENUM_MA_METHOD   InpMethod       = MODE_EMA;          // 均线类型(推荐 MODE_EMA 指数均线)
input ENUM_APPLIED_PRICE InpPrice      = PRICE_CLOSE;       // 均线计算价格(推荐 PRICE_CLOSE 收盘价)

input ENUM_TIMEFRAMES  InpTF1          = PERIOD_D1;         // 第一周期(默认 日线,看大方向)
input ENUM_TIMEFRAMES  InpTF2          = PERIOD_H4;         // 第二周期(默认 4小时,看中期结构)
input ENUM_TIMEFRAMES  InpTF3          = PERIOD_H1;         // 第三周期(默认 1小时,看短期节奏)

input bool             InpUseClosedBar = true;              // 只用大周期已收盘K线(true=信号不重画,推荐)
input bool             InpShowArrow    = true;              // 是否在共振刚成立的K线画箭头
input int              InpArrowGapPoints = 100;             // 箭头与K线的距离(点,黄金建议 80-200)
input int              InpMaxBars      = 5000;              // 最多计算最近多少根K线(0=全部,越小越快)

input bool             InpShowPanel    = true;              // 是否显示右上角共振显示区
input ENUM_BASE_CORNER InpCorner       = CORNER_RIGHT_UPPER;// 显示区所在角落(默认右上角)
input int              InpXDistance    = 14;                // 显示区离边缘的横向距离(像素)
input int              InpYDistance    = 18;                // 显示区离边缘的纵向距离(像素)
input int              InpFontSize     = 9;                 // 正文字号(建议 9-11)
input string           InpFontName     = "Microsoft YaHei"; // 字体(中文建议 微软雅黑)

input color            InpBullColor    = clrLimeGreen;      // 多头颜色(浅绿,不要用深色)
input color            InpBearColor    = clrTomato;         // 空头颜色(浅红)
input color            InpNeutralColor = clrDarkGray;       // 震荡颜色(浅灰)
input color            InpTitleColor   = clrDimGray;        // 标题与文字颜色
input color            InpPanelBgColor = clrWhiteSmoke;     // 显示区底色(浅色)
input color            InpPanelBorder  = clrSilver;         // 显示区边框色

input bool             InpEnableAlert  = false;             // 共振状态变化时是否弹窗提醒

//+------------------------------------------------------------------+
//| 缓冲区与全局变量                                                   |
//+------------------------------------------------------------------+
#define TF_COUNT 3

double UpBuf[];      // 多头共振箭头
double DnBuf[];      // 空头共振箭头
double StateBuf[];   // 每根K线的共振状态:1=多头共振 -1=空头共振 0=震荡(不画图,只做计算)

int              g_hFast[TF_COUNT];   // 三个周期的快线句柄
int              g_hSlow[TF_COUNT];   // 三个周期的慢线句柄
ENUM_TIMEFRAMES  g_tf[TF_COUNT];      // 三个周期
string           g_tfName[TF_COUNT];  // 周期中文名
int              g_lastDir[TF_COUNT]; // 最新K线上各周期的方向:1 多 / -1 空 / 0 持平

const string     g_prefix = "XAUOF_MTFRES_";   // 面板对象名前缀

//+------------------------------------------------------------------+
//| 把周期枚举转成中文名                                               |
//+------------------------------------------------------------------+
string TFToName(const ENUM_TIMEFRAMES tf)
{
   switch(tf)
   {
      case PERIOD_M1:  return("1分钟 M1");
      case PERIOD_M5:  return("5分钟 M5");
      case PERIOD_M15: return("15分钟 M15");
      case PERIOD_M30: return("30分钟 M30");
      case PERIOD_H1:  return("1小时 H1");
      case PERIOD_H4:  return("4小时 H4");
      case PERIOD_D1:  return("日线 D1");
      case PERIOD_W1:  return("周线 W1");
      case PERIOD_MN1: return("月线 MN1");
      default:         return(EnumToString(tf));
   }
}

//+------------------------------------------------------------------+
//| 方向 -> 文字 / 颜色                                                |
//+------------------------------------------------------------------+
string DirToText(const int dir)
{
   if(dir > 0) return("多头 ↑");
   if(dir < 0) return("空头 ↓");
   return("持平 -");
}

color DirToColor(const int dir)
{
   if(dir > 0) return(InpBullColor);
   if(dir < 0) return(InpBearColor);
   return(InpNeutralColor);
}

//+------------------------------------------------------------------+
//| OnInit                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- 参数基本校验,避免非法值导致句柄创建失败
   int fast = (InpFastPeriod < 1) ? 1 : InpFastPeriod;
   int slow = (InpSlowPeriod < 2) ? 2 : InpSlowPeriod;
   if(fast >= slow)
   {
      Print("参数提示:快线周期应小于慢线周期,当前 快=", fast, " 慢=", slow);
      return(INIT_PARAMETERS_INCORRECT);
   }

   //--- 绑定缓冲区(序号与 plot 序号一一对应)
   SetIndexBuffer(0, UpBuf,    INDICATOR_DATA);
   SetIndexBuffer(1, DnBuf,    INDICATOR_DATA);
   SetIndexBuffer(2, StateBuf, INDICATOR_CALCULATIONS);

   //--- 箭头样式:233 向上实心箭头,234 向下实心箭头
   PlotIndexSetInteger(0, PLOT_ARROW, 233);
   PlotIndexSetInteger(1, PLOT_ARROW, 234);
   //--- 空值只能是 EMPTY_VALUE,绝不能用 0
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   //--- 让箭头颜色跟随参数
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, InpBullColor);
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, InpBearColor);
   PlotIndexSetString(0, PLOT_LABEL, "多头共振");
   PlotIndexSetString(1, PLOT_LABEL, "空头共振");

   //--- 整理三个周期(PERIOD_CURRENT 换成当前图表周期)
   g_tf[0] = (InpTF1 == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpTF1;
   g_tf[1] = (InpTF2 == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpTF2;
   g_tf[2] = (InpTF3 == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpTF3;

   //--- 创建 6 个均线句柄(3 个周期 × 快慢线),只在这里创建一次
   for(int k = 0; k < TF_COUNT; k++)
   {
      g_tfName[k]  = TFToName(g_tf[k]);
      g_lastDir[k] = 0;

      g_hFast[k] = iMA(_Symbol, g_tf[k], fast, 0, InpMethod, InpPrice);
      g_hSlow[k] = iMA(_Symbol, g_tf[k], slow, 0, InpMethod, InpPrice);

      if(g_hFast[k] == INVALID_HANDLE || g_hSlow[k] == INVALID_HANDLE)
      {
         Print("均线句柄创建失败,周期:", EnumToString(g_tf[k]));
         return(INIT_FAILED);
      }
   }

   IndicatorSetString(INDICATOR_SHORTNAME,
                      StringFormat("多周期趋势共振 EMA%d/EMA%d", fast, slow));
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

   //--- 先把显示区底板画出来
   if(InpShowPanel)
      CreatePanelBackground();

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| OnDeinit:清理面板与句柄                                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, g_prefix);
   ChartRedraw();

   for(int k = 0; k < TF_COUNT; k++)
   {
      if(g_hFast[k] != INVALID_HANDLE) IndicatorRelease(g_hFast[k]);
      if(g_hSlow[k] != INVALID_HANDLE) IndicatorRelease(g_hSlow[k]);
   }
}

//+------------------------------------------------------------------+
//| 取出某个大周期的均线数据与对应的K线时间                              |
//| 说明:数组索引 0 = 最老,n-1 = 当前K线(不做 ArraySetAsSeries)      |
//+------------------------------------------------------------------+
bool LoadHTFData(const int k, const datetime fromTime,
                 double &fastArr[], double &slowArr[], datetime &timeArr[], int &n)
{
   n = 0;
   ENUM_TIMEFRAMES tf = g_tf[k];

   int secs = PeriodSeconds(tf);
   if(secs <= 0) return(false);   // 除法前先判断分母

   //--- 估算需要往前取多少根大周期K线(多给 8 根余量)
   long span = (long)(TimeCurrent() - fromTime);
   if(span < 0) span = 0;
   int need = (int)(span / secs) + 8;

   int availF = BarsCalculated(g_hFast[k]);
   int availS = BarsCalculated(g_hSlow[k]);
   if(availF <= InpSlowPeriod + 2 || availS <= InpSlowPeriod + 2)
      return(false);             // 大周期数据还没算完,等下一个 tick

   int avail = (availF < availS) ? availF : availS;
   int barsTF = Bars(_Symbol, tf);
   if(barsTF > 0 && barsTF < avail) avail = barsTF;
   if(need > avail) need = avail;
   if(need < 3) return(false);

   //--- 三份数据必须拷到同样长度,否则索引会错位,最多重试 3 次
   for(int attempt = 0; attempt < 3; attempt++)
   {
      int g1 = CopyBuffer(g_hFast[k], 0, 0, need, fastArr);
      int g2 = CopyBuffer(g_hSlow[k], 0, 0, need, slowArr);
      int g3 = CopyTime(_Symbol, tf, 0, need, timeArr);

      if(g1 <= 0 || g2 <= 0 || g3 <= 0) return(false);

      int m = (g1 < g2) ? g1 : g2;
      if(g3 < m) m = g3;

      if(g1 == m && g2 == m && g3 == m)
      {
         n = m;
         return(true);
      }
      need = m;
      if(need < 3) return(false);
   }
   return(false);
}

//+------------------------------------------------------------------+
//| 计算某个大周期在每一根当前周期K线上的方向                            |
//| dir[] 长度 = rates_total - start,1=快线在上 -1=快线在下 0=无效     |
//+------------------------------------------------------------------+
bool CalcTFDirection(const int k, const datetime &time[],
                     const int start, const int rates_total, int &dir[])
{
   int len = rates_total - start;
   if(len <= 0) return(false);
   if(ArrayResize(dir, len) != len) return(false);
   ArrayInitialize(dir, 0);

   double fastArr[], slowArr[];
   datetime timeArr[];
   int n = 0;
   if(!LoadHTFData(k, time[start], fastArr, slowArr, timeArr, n))
      return(false);

   int offset = (InpUseClosedBar ? 1 : 0);  // 取已收盘的上一根大周期K线
   int idx = 0;                             // 单向游标,随着 i 变大只往前走

   for(int i = start; i < rates_total; i++)
   {
      //--- 找到包含这根小周期K线的大周期K线
      while(idx + 1 < n && timeArr[idx + 1] <= time[i]) idx++;
      if(idx >= n) break;
      if(timeArr[idx] > time[i]) continue;   // 这根K线比大周期历史还老,跳过

      int u = idx - offset;
      if(u < 0 || u >= n) continue;

      double f = fastArr[u];
      double s = slowArr[u];
      if(f == EMPTY_VALUE || s == EMPTY_VALUE || f == 0.0 || s == 0.0) continue;

      int d = 0;
      if(f > s) d = 1;
      else if(f < s) d = -1;

      dir[i - start] = d;

      //--- 最新一根K线的方向单独记下来给右上角面板用
      if(i == rates_total - 1) g_lastDir[k] = d;
   }
   return(true);
}

//+------------------------------------------------------------------+
//| OnCalculate                                                      |
//+------------------------------------------------------------------+
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 < 10) return(0);

   //--- 第一次计算先把箭头缓冲区全部清成 EMPTY_VALUE
   if(prev_calculated == 0)
   {
      ArrayInitialize(UpBuf, EMPTY_VALUE);
      ArrayInitialize(DnBuf, EMPTY_VALUE);
      ArrayInitialize(StateBuf, 0.0);
   }

   //--- 计算起点:索引 0 = 最老K线,rates_total-1 = 当前K线
   int firstAllowed = 1;
   if(InpMaxBars > 0 && rates_total > InpMaxBars)
      firstAllowed = rates_total - InpMaxBars;
   if(firstAllowed < 1) firstAllowed = 1;

   int start = (prev_calculated > 0) ? prev_calculated - 1 : firstAllowed;
   if(start < firstAllowed) start = firstAllowed;
   if(start > rates_total - 1) start = rates_total - 1;

   //--- 逐周期取方向;任何一个周期数据没准备好就返回 0,下次重算
   int dirD1[], dirH4[], dirH1[];
   if(!CalcTFDirection(0, time, start, rates_total, dirD1)) return(0);
   if(!CalcTFDirection(1, time, start, rates_total, dirH4)) return(0);
   if(!CalcTFDirection(2, time, start, rates_total, dirH1)) return(0);

   double gap = InpArrowGapPoints * _Point;
   if(gap < 0) gap = 0;

   for(int i = start; i < rates_total && !IsStopped(); i++)
   {
      //--- 每根K线先清空,保证只有共振成立那一根才有箭头
      UpBuf[i] = EMPTY_VALUE;
      DnBuf[i] = EMPTY_VALUE;

      int p = i - start;
      if(p < 0 || p >= ArraySize(dirD1) || p >= ArraySize(dirH4) || p >= ArraySize(dirH1))
         continue;

      int a = dirD1[p];   // 日线方向
      int b = dirH4[p];   // 4小时方向
      int c = dirH1[p];   // 1小时方向

      //--- 三个周期全部向上 = 多头共振;全部向下 = 空头共振;否则震荡
      int st = 0;
      if(a == 1 && b == 1 && c == 1) st = 1;
      else if(a == -1 && b == -1 && c == -1) st = -1;

      StateBuf[i] = (double)st;

      if(i < 1) continue;
      int prevSt = (int)StateBuf[i - 1];

      //--- 第一根计算的K线没有可靠的“前一根”,不画箭头,避免假信号
      bool firstCalcBar = (i == start && prev_calculated == 0);

      if(InpShowArrow && !firstCalcBar)
      {
         if(st == 1 && prevSt != 1)  UpBuf[i] = low[i]  - gap;   // 多头共振刚成立
         if(st == -1 && prevSt != -1) DnBuf[i] = high[i] + gap;  // 空头共振刚成立
      }
   }

   //--- 更新右上角共振显示区(用最新一根K线的状态)
   int nowState = (int)StateBuf[rates_total - 1];
   if(InpShowPanel) UpdatePanel(nowState);

   //--- 状态变化提醒
   if(InpEnableAlert)
   {
      static int lastAlertState = -99;
      if(lastAlertState != -99 && nowState != lastAlertState && nowState != 0)
         Alert(_Symbol, " 多周期共振:", (nowState > 0 ? "多头共振" : "空头共振"));
      lastAlertState = nowState;
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| 创建显示区底板                                                     |
//+------------------------------------------------------------------+
void CreatePanelBackground()
{
   string name = g_prefix + "BG";
   if(ObjectFind(0, name) < 0)
      ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);

   ObjectSetInteger(0, name, OBJPROP_CORNER,     InpCorner);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE,  InpXDistance);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE,  InpYDistance);
   ObjectSetInteger(0, name, OBJPROP_XSIZE,      182);
   ObjectSetInteger(0, name, OBJPROP_YSIZE,      140);
   ObjectSetInteger(0, name, OBJPROP_BGCOLOR,    InpPanelBgColor);
   ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, name, OBJPROP_COLOR,      InpPanelBorder);
   ObjectSetInteger(0, name, OBJPROP_WIDTH,      1);
   ObjectSetInteger(0, name, OBJPROP_BACK,       false);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_SELECTED,   false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN,     true);
   ObjectSetInteger(0, name, OBJPROP_ZORDER,     0);
}

//+------------------------------------------------------------------+
//| 创建/更新一行文字                                                  |
//+------------------------------------------------------------------+
void SetTextLine(const string suffix, const int x, const int y,
                 const string text, const color clr, const int fontSize)
{
   string name = g_prefix + suffix;
   if(ObjectFind(0, name) < 0)
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);

   ObjectSetInteger(0, name, OBJPROP_CORNER,     InpCorner);
   ObjectSetInteger(0, name, OBJPROP_ANCHOR,     ANCHOR_LEFT_UPPER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE,  x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE,  y);
   ObjectSetInteger(0, name, OBJPROP_COLOR,      clr);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE,   fontSize);
   ObjectSetString(0,  name, OBJPROP_FONT,       InpFontName);
   ObjectSetString(0,  name, OBJPROP_TEXT,       text);
   ObjectSetInteger(0, name, OBJPROP_BACK,       false);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_SELECTED,   false);
   ObjectSetInteger(0, name, OBJPROP_HIDDEN,     true);
   ObjectSetInteger(0, name, OBJPROP_ZORDER,     1);
}

//+------------------------------------------------------------------+
//| 刷新右上角共振显示区                                                |
//+------------------------------------------------------------------+
void UpdatePanel(const int state)
{
   CreatePanelBackground();

   //--- 文字从底板左侧 10 像素处开始排版
   int xText = InpXDistance + 182 - 10;
   int fs    = (InpFontSize < 7) ? 7 : InpFontSize;

   //--- 标题
   SetTextLine("T0", xText, InpYDistance + 8,
               "多周期趋势共振", InpTitleColor, fs + 1);

   //--- 均线说明
   SetTextLine("T1", xText, InpYDistance + 30,
               StringFormat("均线:EMA%d / EMA%d", InpFastPeriod, InpSlowPeriod),
               InpNeutralColor, fs - 1);

   //--- 三个周期明细
   for(int k = 0; k < TF_COUNT; k++)
   {
      SetTextLine(StringFormat("R%d", k),
                  xText, InpYDistance + 50 + k * 18,
                  g_tfName[k] + " : " + DirToText(g_lastDir[k]),
                  DirToColor(g_lastDir[k]), fs);
   }

   //--- 共振结论
   string stText;
   color  stColor;
   if(state > 0)      { stText = "多头共振"; stColor = InpBullColor; }
   else if(state < 0) { stText = "空头共振"; stColor = InpBearColor; }
   else               { stText = "震荡";     stColor = InpNeutralColor; }

   SetTextLine("ST", xText, InpYDistance + 110, "结论: " + stText, stColor, fs + 2);

   //--- 边框跟着状态换色,一眼能看出当前处于什么状态
   ObjectSetInteger(0, g_prefix + "BG", OBJPROP_COLOR, stColor);

   ChartRedraw();
}
//+------------------------------------------------------------------+
MT5 运行截图 · 完整视图带价格轴和时间轴的整张图表(约 150 根 H1 K 线),上面的封面是它最近 80 根 K 线的放大视图
黄金多周期趋势共振指标 在 MT5 上的真实截图

作品说明

先说思路:这是一个纯判读型指标,核心是把 D1 / H4 / H1 三个周期的 EMA20 与 EMA60 方向取出来做「三票一致」判断。难点在跨周期取值——大周期的 K 线时间和 M5 不对齐,所以我先用 CopyBuffer + CopyTime 把大周期的均线值和开盘时间一起拷下来,再用一个单向游标把每根 M5 K 线映射到它所属的大周期 K 线上,这样历史上每一根 M5 都有正确的共振状态,不会错位。

右上角用 OBJ_RECTANGLE_LABEL + 文字标签做显示区:标题、三行周期明细、一行共振结论。配色用浅绿 LimeGreen / 浅红 Tomato / 浅灰 DarkGray,面板底色 WhiteSmoke。另外在共振「刚刚成立」的那一根 K 线画一次箭头,其余 K 线一律 EMPTY_VALUE。

使用说明

安装

  1. MT5 菜单 文件 → 打开数据文件夹 → MQL5\Indicators,把 XAUOF_MTF_Resonance.mq5 放进去。
  2. 打开 MetaEditor 按 F7 编译,确认 0 errors 0 warnings。
  3. 回到 MT5,打开 XAUUSD 的 M5 图表,从导航器里把指标拖上去。首次挂载如果面板是灰的,等几秒让 D1/H4/H1 的历史数据下载完,或者手动切一次周期刷新。

参数怎么调

  • InpFastPeriod / InpSlowPeriod:默认 20/60。想更灵敏可以改 10/30,想更稳可以改 20/120。快线必须小于慢线,否则指标会拒绝加载。
  • InpTF1/2/3:默认 D1 / H4 / H1。日内短打可以换成 H4 / H1 / M15。
  • InpUseClosedBar:默认 true,取大周期已收盘的那根K线做判断,信号定了就不会再变。改成 false 用正在走的大周期K线,反应快半步但会在当前大周期内反复变色。
  • InpArrowGapPoints:箭头离K线的距离。黄金两位小数报价时 100 点 = 1.00 美元,觉得箭头贴太近就加大。
  • InpMaxBars:默认只算最近 5000 根 M5,图表加载快。想看更久远的历史信号改成 0。
  • 颜色默认是浅绿 / 浅红 / 浅灰 + 白烟底色,深色主题下也能看清;要改配色直接改那几个 color 参数。

信号怎么看

  • 右上角显示区四行:标题、均线设置、三个周期各自的方向(多头 ↑ / 空头 ↓)、最下面一行是结论。
  • 三个周期全部 多头 ↑ → 结论显示绿色 多头共振,边框也变绿;全部 空头 ↓ → 红色 空头共振;只要有一个不一致 → 灰色 震荡。
  • 主图上只在共振刚刚成立的那一根 K 线画一次箭头:绿色向上箭头在 K 线下方,红色向下箭头在 K 线上方。没有箭头墙说明逻辑正常。
  • 用法上,绿色共振期只做回调买、红色共振期只做反弹卖,灰色震荡期减少开仓或只做短线。

注意事项

  • 这是纯指标,不会自动下单,箭头是方向过滤器不是精确入场点,建议配合你自己的入场信号(例如 M5 结构突破)使用。
  • 结论依赖日线级别的均线,状态切换本来就慢,一天可能一次都不变,这是正常的。
  • 如果某个大周期历史数据不足(新上市品种、图表历史被清过),该行会显示灰色 持平 -,结论会是震荡。去「图表 → 刷新」或在该周期图上往左翻一下把历史补齐。
  • 把 InpEnableAlert 打开后,共振状态从震荡变成多头/空头时会弹窗,切换图表周期时可能触发一次重算提醒,属正常现象。

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

这是什么

一个挂在 MT5 主图上的判读型指标。它把日线、4小时、1小时三个周期的 EMA20 与 EMA60 关系取出来,看方向是否一致。解决的是「小周期上盯着信号,却不知道大方向站在哪边」这个问题。它不下单,只告诉你现在三个周期是不是站在同一侧。

逻辑原理

每个周期各算两条均线:快线 EMA20 和慢线 EMA60。快线在慢线上方记多头,下方记空头,相等记持平。

三票一致才算共振:三个周期全多头 → 状态为多头共振;全空头 → 空头共振;只要有一个不一致 → 震荡。

跨周期取值是关键。代码用 CopyBuffer 拿大周期均线值,同时用 CopyTime 拿对应的K线开盘时间,再用一个只往前走的游标把当前周期的每根K线映射到它所属的那根大周期K线上,所以历史上每根K线的状态都是当时真实的状态,不会前移错位。三份数据长度不一致时会重试对齐,对不齐就返回等下一个 tick。

InpUseClosedBar 为 true 时取的是大周期已收盘的上一根K线(offset=1),状态定了就不会在当前大周期内反复变。

箭头只画一次:状态刚从非多头变成多头时,在该K线低点下方画绿色向上箭头;刚变成空头时,在高点上方画红色向下箭头。其余K线一律 EMPTY_VALUE,所以图上不会有箭头墙。

右上角是一块 RECTANGLE_LABEL 底板加文字标签:标题、均线设置、三个周期各自的方向、最下面一行结论,边框颜色跟着结论变。

参数说明

  • InpFastPeriod(20):快线周期。数字越小越灵敏。必须小于慢线,否则指标拒绝加载。
  • InpSlowPeriod(60):慢线周期。想更稳可以加大。
  • InpMethod(MODE_EMA):均线类型。
  • InpPrice(PRICE_CLOSE):均线计算用价。
  • InpTF1 / InpTF2 / InpTF3(D1 / H4 / H1):参与判断的三个周期。日内短打可换 H4 / H1 / M15。填 PERIOD_CURRENT 会自动换成当前图表周期。
  • InpUseClosedBar(true):只用大周期已收盘K线。改 false 反应快半步,但当前大周期内状态会来回变。
  • InpShowArrow(true):是否画共振成立箭头。
  • InpArrowGapPoints(100):箭头离K线的距离,单位点。
  • InpMaxBars(5000):最多计算最近多少根K线,0 为全部。
  • InpShowPanel(true):是否显示显示区。
  • InpCorner(右上角)/ InpXDistance(14)/ InpYDistance(18):显示区位置。
  • InpFontSize(9)/ InpFontName(Microsoft YaHei):字号与字体。
  • InpBullColor(LimeGreen)/ InpBearColor(Tomato)/ InpNeutralColor(DarkGray)/ InpTitleColor(DimGray)/ InpPanelBgColor(WhiteSmoke)/ InpPanelBorder(Silver):配色。
  • InpEnableAlert(false):共振状态变化时弹窗。

怎么用

把 mq5 文件放进 MQL5\Indicators,MetaEditor 里 F7 编译,然后从导航器拖到图表上。默认参数是给 M5 图设计的,挂在 XAUUSD 的 M5 上最顺手。

看右上角:三行周期明细都是「多头 ↑」,结论就是绿色多头共振;都是「空头 ↓」是红色空头共振;混着就是灰色震荡。绿色期只做回调买,红色期只做反弹卖,灰色期少动手。箭头是方向确认点,不是精确入场点。

首次挂载面板发灰是正常的,等 D1/H4/H1 历史数据下载完就好。

适用场景

默认 D1/H4/H1 的组合适合黄金、主要货币对这类趋势能走一段的品种,图表周期放在 M5 到H1 都行。做日内更短线的可以把三个周期整体下移。

不适合纯区间震荡行情——那种时候结论大部分时间是灰色,本来也不该重仓。也不适合拿箭头当唯一入场信号用。

风险提示

均线本身滞后,日线级别的状态切换更慢,一天不变一次是常态,不要指望它抓转折。

InpUseClosedBar 设为 false 时,当前大周期内的方向会随价格来回跳,面板和箭头都可能变,等于放弃了不重画这个优点。默认 true 时已收盘的大周期K线不再变化,历史箭头位置是稳定的。

大周期历史数据不足时对应那行显示「持平 -」,结论会落到震荡,这不是看空看多,是数据没到位,刷新一下图表。

箭头位置由 InpArrowGapPoints 固定偏移,不代表挂单价。共振期同样会有回撤,止损自己定。

常见问题

这个指标会重绘吗
默认 InpUseClosedBar 为 true 时,判断用的是大周期已收盘的K线,历史状态和箭头不会变。改成 false 后会用正在走的大周期K线,当前大周期内状态和箭头都可能反复变化。
可以用在 XAUUSD 以外的品种吗
可以,代码里没有品种限制,均线句柄用的是 _Symbol,挂哪个图算哪个。只是 InpArrowGapPoints 是按点算的偏移,换品种时要跟着报价小数位调一下。
MT4 能用吗
不能。这是 MQL5 源码,用了 CopyBuffer、iMA 句柄、OBJ_RECTANGLE_LABEL 这些 MT5 的接口,只能在 MT5 里编译运行。
默认参数适合什么图表周期
三个判断周期默认是 D1 / H4 / H1,挂在 M5 图上最合适,M15 到 H1 也行。想做更短线可以把三个周期整体下移,比如 H4 / H1 / M15。
为什么面板显示「持平 -」,结论一直是震荡
说明那个周期的均线数据还没算够或历史不足。代码在大周期数据量不足时会直接返回,等数据补齐。切一次周期或去「图表 → 刷新」把历史下载下来即可。
有报警功能吗
有,InpEnableAlert 默认关闭,打开后共振状态发生变化且新状态不是震荡时会弹一次 Alert。首次计算不弹,避免挂载就刷一条。

Multi-Timeframe EMA Trend Resonance Indicator for MT5

An MT5 chart indicator that reads the EMA20 / EMA60 relationship on three higher timeframes (D1, H4, H1 by default) and reports whether all three agree. A corner panel shows each timeframe's direction plus a combined bullish, bearish, or neutral verdict, and an arrow is plotted on the single bar where resonance is first established. Timeframes, MA periods, colors, and alerts are all configurable inputs.

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

评论

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

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