MQL5 细则手册:在单一窗口中监控多个时间表·进阶篇
📊

MQL5 细则手册:在单一窗口中监控多个时间表·进阶篇

(2/3)·手工叠图表对象又慢又漏属性,这篇用指标按钮把多周期监控自动化

偏理论进阶 第 2/3 篇

在 MT5 里同时看多个周期,很多人还是开一堆独立窗口来回切。手工加图表对象不仅费时,买价卖价缩进这类属性根本调不了,分析口径天然残缺。

「面板按钮的数组与状态初始化」

在 MT5 自定义面板里,周期切换和图表属性按钮通常先用数组集中管理,而不是逐个写死对象名。下面这段代码把 21 个周期按钮的名称、显示文字、状态分别塞进三个平行数组,索引一一对应,循环创建时直接按下标取用即可。 周期数组覆盖 M1 到 MN 共 21 档,timeframe_button_states 初始全为 false,代表未激活;属性按钮则单独用 property_button_names、property_button_texts、property_button_states 管理,外加 property_button_widths 控制五个键的宽度,分别是 66、68、66、100、101 像素。 chart_object_names 同样按 21 个周期预置了图表子对象名,后续切周期时用它绑定具体图形。这种写法让你改按钮布局只动数组、不碰逻辑,开 MT5 把数组抄进 EA 头文件就能直接跑。 别把数组长度当摆设 TIMEFRAME_BUTTONS 和 PROPERTY_BUTTONS 必须是编译期常量,若你手动增删周期档位,忘了同步改宏定义,循环越界会直接报数组越界错误,面板加载失败。

MQL5 / C++
class="type">color  cOnButtonBorder        =clrLightGray;    class=class="str">"cmt">// Clicked button border class="type">color
class=class="str">"cmt">//--- Array of object names for time frame buttons
class="type">class="kw">string timeframe_button_names[TIMEFRAME_BUTTONS]=
  {
   "button_M1","button_M2","button_M3","button_M4","button_M5","button_M6","button_M10",
   "button_M12","button_M15","button_M20","button_M30","button_H1","button_H2","button_H3",
   "button_H4","button_H6","button_H8","button_H12","button_D1","button_W1","button_MN"
  };
class=class="str">"cmt">//--- Array of text displayed on time frame buttons
class="type">class="kw">string timeframe_button_texts[TIMEFRAME_BUTTONS]=
  {
   "M1","M2","M3","M4","M5","M6","M10",
   "M12","M15","M20","M30","H1","H2","H3",
   "H4","H6","H8","H12","D1","W1","MN"
  };
class=class="str">"cmt">//--- Array of time frame button states
class="type">bool timeframe_button_states[TIMEFRAME_BUTTONS]={class="kw">false};
class=class="str">"cmt">//--- Array of object names for buttons of chart properties
class="type">class="kw">string property_button_names[PROPERTY_BUTTONS]=
  {
   "property_button_date","property_button_price",
   "property_button_ohlc","property_button_askbid",
   "property_button_trade_levels"
  };
class=class="str">"cmt">//--- Array of text displayed on buttons of chart properties
class="type">class="kw">string property_button_texts[PROPERTY_BUTTONS]=
  {
   "Date","Price","OHLC","Ask / Bid","Trade Levels"
  };
class=class="str">"cmt">//--- Array of states for buttons of chart properties
class="type">bool property_button_states[PROPERTY_BUTTONS]={class="kw">false};
class=class="str">"cmt">//--- Array of sizes for buttons of chart properties
class="type">int property_button_widths[PROPERTY_BUTTONS]=
  {
   class="num">66,class="num">68,class="num">66,class="num">100,class="num">101
  };
class=class="str">"cmt">//--- Array of chart object names
class="type">class="kw">string chart_object_names[TIMEFRAME_BUTTONS]=
  {
   "chart_object_m1","chart_object_m2","chart_object_m3","chart_object_m4","chart_object_m5","chart_object_m6","chart_object_m10",
   "chart_object_m12","chart_object_m15","chart_object_m20","chart_object_m30","chart_object_h1","chart_object_h2","chart_object_h3",
   "chart_object_h4","chart_object_h6","chart_object_h8","chart_object_h12","chart_object_d1","chart_object_w1","chart_object_mn"
  };

◍ 在 MT5 图表上用代码挂一个按钮

想在 MT5 图表上动态放一个可点击的按钮,核心是先调 ObjectCreate 用 OBJ_BUTTON 类型把对象建出来,再逐条写属性。下面这段函数签名列出了按钮所需的全部参数,从所属窗口到 Z 轴层级都给了入口。 int window_number, // 窗口编号,主图通常是 0 string name, // 对象唯一名,重复会建失败 string text, // 按钮上显示的文字 ENUM_ANCHOR_POINT anchor, // 锚点方式 ENUM_BASE_CORNER corner, // 贴哪个图角 string font_name, // 字体 int font_size, // 字号 color font_color, // 字色 color background_color, // 背景色 color border_color, // 边框色 int x_size, // 宽 int y_size, // 高 int x_distance, // 距锚点 X int y_distance, // 距锚点 Y long z_order // 层叠顺序 建对象时若返回 true,说明图表里已经多了一个空按钮,接下来用 ObjectSetString / ObjectSetInteger 把文字、字体、颜色写进去。比如 ObjectSetString(chart_id,name,OBJPROP_TEXT,text) 决定按钮显示什么,OBJPROP_FONT 决定字体,OBJPROP_COLOR 决定字色。 实盘里这类按钮常用来触发一键平仓或切换周期。外汇和贵金属波动剧烈、杠杆高,按钮脚本若误触可能瞬间发单,建议在策略测试器里先用模拟盘验证回调逻辑,再挂真账户图表。

MQL5 / C++
class="type">int window_number, class=class="str">"cmt">// window number
class="type">class="kw">string name, class=class="str">"cmt">// object name
class="type">class="kw">string text, class=class="str">"cmt">// displayed name
ENUM_ANCHOR_POINT anchor, class=class="str">"cmt">// anchor point
ENUM_BASE_CORNER corner, class=class="str">"cmt">// chart corner
class="type">class="kw">string font_name, class=class="str">"cmt">// font
class="type">int font_size, class=class="str">"cmt">// font size
class="type">color font_color, class=class="str">"cmt">// font class="type">color
class="type">color background_color, class=class="str">"cmt">// background class="type">color
class="type">color border_color, class=class="str">"cmt">// border class="type">color
class="type">int x_size, class=class="str">"cmt">// width
class="type">int y_size, class=class="str">"cmt">// height
class="type">int x_distance, class=class="str">"cmt">// X-coordinate
class="type">int y_distance, class=class="str">"cmt">// Y-coordinate
class="type">long z_order) class=class="str">"cmt">// Z-order
{
class=class="str">"cmt">//--- If the object has been created successfully
 if(ObjectCreate(chart_id,name,OBJ_BUTTON,window_number,class="num">0,class="num">0))
  {
   class=class="str">"cmt">// set its properties
   ObjectSetString(chart_id,name,OBJPROP_TEXT,text); class=class="str">"cmt">// setting name
   ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); class=class="str">"cmt">// setting font
   ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); class=class="str">"cmt">// setting font class="type">color

按钮对象的图形属性落地写法

在 MT5 里用 ObjectSetInteger 给 GUI 按钮设属性时,每一行都对应一个 OBJPROP_* 宏,少写一行界面就可能错位。下面这段代码把背景色、边框色、锚点、角落、字号、宽高、坐标、可选中状态、按钮态、Z序和 tooltip 一次性配齐,可直接塞进你的面板初始化函数。

MQL5 / C++
ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color);      class=class="str">"cmt">// 设置背景色
ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color);    class=class="str">"cmt">// 设置边框色
ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);                class=class="str">"cmt">// 设置锚点
ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);                class=class="str">"cmt">// 设置图表角落
ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);           class=class="str">"cmt">// 设置字号
ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);                 class=class="str">"cmt">// 设置宽度
ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);                 class=class="str">"cmt">// 设置高度
ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);         class=class="str">"cmt">// 设置X坐标
ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);         class=class="str">"cmt">// 设置Y坐标
ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,class="kw">false);             class=class="str">"cmt">// 对象不可被选中
ObjectSetInteger(chart_id,name,OBJPROP_STATE,class="kw">false);                  class=class="str">"cmt">// 按钮状态(未按下)
ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);               class=class="str">"cmt">// 接收点击事件的Z序
ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");                 class=class="str">"cmt">// 无提示框
逐行看,OBJPROP_SELECTABLE 设 false 后按钮在图上点不中,只走 OnChartEvent 的 OBJEVENT_CLICK 逻辑,避免误拖。OBJPROP_ZORDER 的值若比同区域其他对象大,点击穿透会优先落在这个按钮上——实盘面板叠多层时这是个隐性坑。 顺带一段子窗口创建的函数头,参数顺序固定为窗口号、X/Y 距离、宽、高:
MQL5 / C++
class="type">void CreateChartInSubwindow(class="type">int window_number, class="type">int x_distance, class="type">int y_distance, class="type">int x_size, class="type">int y_size)
外汇与贵金属波动剧烈,这类自定义面板仅辅助观察,任何信号都不构成入场保证,杠杆品种请自行控仓。开 MT5 把上面属性块贴进 EA 初始化,改 background_color 和 corner 两个参数就能看出布局变化。

MQL5 / C++
ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color);      class=class="str">"cmt">// setting background class="type">color
ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color);    class=class="str">"cmt">// setting border class="type">color
ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);                class=class="str">"cmt">// setting anchor point
ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);                class=class="str">"cmt">// setting chart corner
ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);           class=class="str">"cmt">// setting font size
ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);                 class=class="str">"cmt">// setting width
ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);                 class=class="str">"cmt">// setting height
ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);         class=class="str">"cmt">// setting X-coordinate
ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);         class=class="str">"cmt">// setting Y-coordinate
ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,class="kw">false);             class=class="str">"cmt">// object is not available for selection
ObjectSetInteger(chart_id,name,OBJPROP_STATE,class="kw">false);                  class=class="str">"cmt">// button state(clicked/unclicked)
ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);               class=class="str">"cmt">// Z-order for getting the click event
ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");                  class=class="str">"cmt">// no tooltip

class="type">void CreateChartInSubwindow(class="type">int window_number, class="type">int x_distance, class="type">int y_distance, class="type">int x_size, class="type">int y_size)

「在主图里嵌一个迷你副图」

想在 MT5 主图表上塞一个独立的小图表对象(OBJ_CHART),用来同屏比对别的周期或品种,关键就在函数参数和后续属性设置。下面这段结构把对象名、标的、周期、缩放和各类刻度开关一次性传进去,读者可以直接抄去改。 参数里 symbol 和 timeframe 决定小图加载什么数据,subchart_scale 控制 K 线压缩密度,show_ask_bid / show_levels 这类布尔值则决定要不要把盘口和交易位画上去。实盘外汇或贵金属挂这种对象时,注意多品种同屏会多吃一点终端资源,行情跳动快时可能略有延迟。 创建成功后必须用 ObjectSetInteger 落坐标和尺寸:OBJPROP_XDISTANCE 和 YDISTANCE 是左上角偏移像素,OBJPROP_XSIZE / YSIZE 是宽高。Corner 设成 CORNER_LEFT_UPPER 是最稳的锚点,避免和小图自身滚动逻辑打架。

MQL5 / C++
class="type">class="kw">string name, class=class="str">"cmt">// object name
class="type">class="kw">string symbol, class=class="str">"cmt">// symbol
ENUM_TIMEFRAMES timeframe, class=class="str">"cmt">// time frame
class="type">int subchart_scale, class=class="str">"cmt">// bar scale
class="type">bool show_dates, class=class="str">"cmt">// show date scale
class="type">bool show_prices, class=class="str">"cmt">// show price scale
class="type">bool show_ohlc, class=class="str">"cmt">// show OHLC prices
class="type">bool show_ask_bid, class=class="str">"cmt">// show ask/bid levels
class="type">bool show_levels, class=class="str">"cmt">// show trade levels
class="type">class="kw">string tooltip) class=class="str">"cmt">// tooltip
{
class=class="str">"cmt">//--- If the object has been created successfully
 if(ObjectCreate(class="num">0,name,OBJ_CHART,window_number,class="num">0,class="num">0))
  {
   class=class="str">"cmt">//--- Set the properties of the chart object
   ObjectSetInteger(class="num">0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER); class=class="str">"cmt">// chart corner
   ObjectSetInteger(class="num">0,name,OBJPROP_XDISTANCE,x_distance); class=class="str">"cmt">// X-coordinate
   ObjectSetInteger(class="num">0,name,OBJPROP_YDISTANCE,y_distance); class=class="str">"cmt">// Y-coordinate
   ObjectSetInteger(class="num">0,name,OBJPROP_XSIZE,x_size); class=class="str">"cmt">// width
   ObjectSetInteger(class="num">0,name,OBJPROP_YSIZE,y_size); class=class="str">"cmt">// height
   ObjectSetInteger(class="num">0,name,OBJPROP_CHART_SCALE,subchart_scale); class=class="str">"cmt">// bar scale
   ObjectSetInteger(class="num">0,name,OBJPROP_DATE_SCALE,show_dates); class=class="str">"cmt">// date scale

◍ 子图对象与周期按钮的属性落地

在 MT5 里用 ObjectCreate 拉出子图后,真正决定它长什么样的全是后续的对象属性写入。下面这段把价格刻度、绑定品种、周期、悬浮提示一口气设完,再把对象压到前景并禁掉选中,避免误点拖乱布局。 ObjectSetInteger(0,name,OBJPROP_PRICE_SCALE,show_prices); // 价格刻度显隐 ObjectSetString(0,name,OBJPROP_SYMBOL,symbol); // 绑定品种 ObjectSetInteger(0,name,OBJPROP_PERIOD,timeframe); // 子图周期 ObjectSetString(0,name,OBJPROP_TOOLTIP,tooltip); // 悬浮提示 ObjectSetInteger(0,name,OBJPROP_BACK,false); // 前景显示 ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); // 禁止选中 ObjectSetInteger(0,name,OBJPROP_COLOR,clrWhite); // 白色描边 拿到子图句柄后要用 ChartSetInteger 调图表级属性:OHLC 线、交易位、买卖盘线都能单独开关,最后用 ChartRedraw 刷新才生效。实盘里把 CHART_COLOR_LAST 设成 clrLimeGreen、CHART_COLOR_STOP_LEVEL 设成 clrRed,止损位和成交价一眼能分。 周期按钮的排布是纯坐标活儿:左边距 x_dist=1、底距 y_dist=125,单键 28×20 像素。循环里每满 7 个(i%7==0)就把 x_dist 重置为 1 换到下一行,这样最多两行就能铺完 14 个常用周期。外汇与贵金属波动剧烈,这类自定义面板仅作辅助,下单前仍需自判风险。

MQL5 / C++
ObjectSetInteger(class="num">0,name,OBJPROP_PRICE_SCALE,show_prices);  class=class="str">"cmt">// price scale
ObjectSetString(class="num">0,name,OBJPROP_SYMBOL,symbol);            class=class="str">"cmt">// symbol
ObjectSetInteger(class="num">0,name,OBJPROP_PERIOD,timeframe);        class=class="str">"cmt">// time frame
ObjectSetString(class="num">0,name,OBJPROP_TOOLTIP,tooltip);          class=class="str">"cmt">// tooltip
ObjectSetInteger(class="num">0,name,OBJPROP_BACK,class="kw">false);              class=class="str">"cmt">// object in the foreground
ObjectSetInteger(class="num">0,name,OBJPROP_SELECTABLE,class="kw">false);        class=class="str">"cmt">// object is not available for selection
ObjectSetInteger(class="num">0,name,OBJPROP_COLOR,clrWhite);          class=class="str">"cmt">// white class="type">color
class=class="str">"cmt">//--- Get the chart object identifier
class="type">long subchart_id=ObjectGetInteger(class="num">0,name,OBJPROP_CHART_ID);
class=class="str">"cmt">//--- Set the special properties of the chart object
ChartSetInteger(subchart_id,CHART_SHOW_OHLC,show_ohlc);                class=class="str">"cmt">// OHLC
ChartSetInteger(subchart_id,CHART_SHOW_TRADE_LEVELS,show_levels);     class=class="str">"cmt">// trade levels
ChartSetInteger(subchart_id,CHART_SHOW_BID_LINE,show_ask_bid);        class=class="str">"cmt">// bid level
ChartSetInteger(subchart_id,CHART_SHOW_ASK_LINE,show_ask_bid);        class=class="str">"cmt">// ask level
ChartSetInteger(subchart_id,CHART_COLOR_LAST,clrLimeGreen);           class=class="str">"cmt">// class="type">color of the level of the last executed deal 
ChartSetInteger(subchart_id,CHART_COLOR_STOP_LEVEL,clrRed);           class=class="str">"cmt">// class="type">color of Stop order levels  
class=class="str">"cmt">//--- Refresh the chart object
ChartRedraw(subchart_id);
}
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Adding time frame buttons                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void AddTimeframeButtons()
  {
   class="type">int x_dist =class="num">1;    class=class="str">"cmt">// Indent from the left side of the chart
   class="type">int y_dist =class="num">125;  class=class="str">"cmt">// Indent from the bottom of the chart
   class="type">int x_size =class="num">28;   class=class="str">"cmt">// Button width
   class="type">int y_size =class="num">20;   class=class="str">"cmt">// Button height
class=class="str">"cmt">//---
   for(class="type">int i=class="num">0; i<TIMEFRAME_BUTTONS; i++)
     {
      class=class="str">"cmt">//--- If class="num">7 buttons have already been added to the same row, set the coordinates for the next row
      if(i%class="num">7==class="num">0)
        {
         x_dist=class="num">1;

图表属性按钮的排版与销毁

属性按钮的纵向布局用 y_dist 控制,初始距底部 41 像素、按钮高 20,每排满 3 个后 y_dist 减 21,也就是下一排比上一排高 1 像素间隙,这种硬偏移在 MT5 里能直接看出排版是否错位。 横向则靠 x_dist 累加:每个按钮宽度取 property_button_widths[i],加 1 像素间隔,循环里 x_dist+=property_button_widths[i]+1 一句就决定了下一颗钮的起点,改这个 +1 能调密排还是疏排。 销毁逻辑极简,DeleteTimeframeButtons 与 DeletePropertyButtons 都只是按名字数组遍历 DeleteObjectByName,没有释放资源外的多余动作;若你在脚本里动态改名,这套按名删除会漏删,需要自己先同步命名数组。 外汇与贵金属图表加载这类自定义面板时波动滑点可能触发重绘,建议先在模拟盘验证按钮锚点是否随 corner 偏移。

MQL5 / C++
class="type">void AddPropertyButtons()
  {
   class="type">int x_dist =class="num">1;   class=class="str">"cmt">// 图表左侧缩进 class="num">1 像素
   class="type">int y_dist =class="num">41; class=class="str">"cmt">// 图表底部缩进 class="num">41 像素
   class="type">int x_size =class="num">66; class=class="str">"cmt">// 按钮宽 class="num">66
   class="type">int y_size =class="num">20; class=class="str">"cmt">// 按钮高 class="num">20
class=class="str">"cmt">//---
   for(class="type">int i=class="num">0; i<PROPERTY_BUTTONS; i++)
     {
      class=class="str">"cmt">// 前三个按钮排完,换下一行坐标
      if(i==class="num">3)
        {
         x_dist=class="num">1;
         y_dist-=class="num">21;
        }
      class=class="str">"cmt">// 加一个按钮
      CreateButton(class="num">0,class="num">0,property_button_names[i],property_button_texts[i],
                   ANCHOR_LEFT_LOWER,CORNER_LEFT_LOWER,"Arial",class="num">8,
                   cOffButtonFont,cOffButtonBackground,cOffButtonBorder,
                   property_button_widths[i],y_size,x_dist,y_dist,class="num">3);
      class=class="str">"cmt">// 下一个按钮的 X 坐标
      x_dist+=property_button_widths[i]+class="num">1;
     }
  }

class="type">void DeleteTimeframeButtons()
  {
   for(class="type">int i=class="num">0; i<TIMEFRAME_BUTTONS; i++)
      DeleteObjectByName(timeframe_button_names[i]);
  }

class="type">void DeletePropertyButtons()
  {
   for(class="type">int i=class="num">0; i<PROPERTY_BUTTONS; i++)
      DeleteObjectByName(property_button_names[i]);
  }
交给小布盯盘看多周期
这些多周期同窗的诊断逻辑小布盯盘已内置,打开对应品种页就能直接看跨周期共振,不用自己写指标。

常见问题

理论上不限制数量,但手工添加越多越卡且属性难统一,用程序批量生成更稳。
像买价卖价线、右侧缩进、交易价位等由终端内部控制,标准属性框不暴露接口,必须借对象编程写入。
主程序通过 #resource 包含子指标后,发布只需一个 ex5,用户不丢依赖文件,部署更干净。
常规跨周期同屏观察小布盯盘已覆盖,复杂自定义交互才需要照本文自己撸控件。
防止删除主图指标时子窗口对象残留,需在反初始化里显式清理释放句柄。