MQL5 细则手册:在单一窗口中监控多个时间表·进阶篇
(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 必须是编译期常量,若你手动增删周期档位,忘了同步改宏定义,循环越界会直接报数组越界错误,面板加载失败。
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 决定字色。 实盘里这类按钮常用来触发一键平仓或切换周期。外汇和贵金属波动剧烈、杠杆高,按钮脚本若误触可能瞬间发单,建议在策略测试器里先用模拟盘验证回调逻辑,再挂真账户图表。
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 一次性配齐,可直接塞进你的面板初始化函数。
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">// 无提示框
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)
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 是最稳的锚点,避免和小图自身滚动逻辑打架。
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 个常用周期。外汇与贵金属波动剧烈,这类自定义面板仅作辅助,下单前仍需自判风险。
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 偏移。
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]); }