使用MQL5轻松创建图形面板·进阶篇
(2/3)·从标识认知到两种实现路线,搞懂面板类如何替你省下重复造轮子的时间
「面板交互的事件分发逻辑」
在 MT5 图表面板上做手动下单工具,核心是把图表事件路由到正确的处理函数。下面这段初始化与 OnChartEvent 骨架,定义了卖按钮纵坐标、三个对象名(文本框 txttVol、买按钮 buyBtn、卖按钮 sellBtn)以及默认手数 0.01。 初始化时先调用 createPanel() 画出控件,随后用 ObjectDelete(0,...) 按名字清理旧对象,避免重复加载时残留。手数变量 lotSize 设为 double 型 0.01,是后续开仓函数的传入值。 OnChartEvent 里分两条路:若 id 为 CHARTEVENT_OBJECT_ENDEDIT 且 sparam 等于 txtName,说明交易者在文本框改了手数,先用 ObjectGetString 取回文本交给 setLot() 解析,再把文本框重设回 lotSize 的字符串形式。若 id 为 CHARTEVENT_OBJECT_CLICK,则按 sparam 判断点的是 buyBtn 还是 sellBtn:命中买按钮就把按钮状态置 false 并调 openTrade(ORDER_TYPE_BUY, lotSize);命中卖按钮同样复位状态,调 openTrade 开空。外汇与贵金属保证金交易杠杆高,面板一键下单可能迅速放大亏损,实盘前务必在策略测试器用 0.01 手验一遍事件触发。 把这段代码贴进 EA 的 OnChartEvent,你能在 MT5 里点按钮即触发对应 order 调用;若点击无反应,优先检查对象名字符串是否与 createPanel 内绘制时完全一致。
const class="type">int sellY=txtY+ySpace+btnHeight; const class="type">class="kw">string txtName="txttVol"; const class="type">class="kw">string buyName="buyBtn"; const class="type">class="kw">string sellName="sellBtn"; class="type">class="kw">double lotSize=class="num">0.01; createPanel(); ObjectDelete(class="num">0,txtName); ObjectDelete(class="num">0,buyName); ObjectDelete(class="num">0,sellName); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Interaction function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { class=class="str">"cmt">//--- If the event id is equal to the end of text editing in the panel and the class="type">class="kw">string type event is equal to the text name if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam==txtName) { class=class="str">"cmt">//--- lotTxt class="type">class="kw">string variable will be equal to the returned class="kw">property value by using the ObjectGetString function class="type">class="kw">string lotTxt=ObjectGetString(class="num">0, txtName, OBJPROP_TEXT); class=class="str">"cmt">//--- call setLot function that we will create later with the lotTxt value setLot(lotTxt); class=class="str">"cmt">//Setting the class="kw">property value by using the ObjectSetString ObjectSetString(class="num">0, txtName, OBJPROP_TEXT, class="type">class="kw">string(lotSize)); class=class="str">"cmt">//--- Use class="kw">return class="kw">return; } class=class="str">"cmt">//--- If the event id is equal to the object click to check if we click the buy button else if(id==CHARTEVENT_OBJECT_CLICK) { class=class="str">"cmt">//We will check if the class="type">class="kw">string param is equal to buyname if(sparam==buyName) { class=class="str">"cmt">//--- Setting the value of the class="kw">property by using the ObjectSetInteger ObjectSetInteger(class="num">0, buyName, OBJPROP_STATE, class="kw">false); class=class="str">"cmt">//Calling the created openTrade to open a buy order. openTrade(ORDER_TYPE_BUY, lotSize); class=class="str">"cmt">//--- Use class="kw">return class="kw">return; } class=class="str">"cmt">//--- If the event id is equal to the object click to check if we click the sell button class=class="str">"cmt">//--- We will check if the class="type">class="kw">string param is equal to sellname else if(sparam==sellName) { class=class="str">"cmt">//--- Setting the value of the class="kw">property by using the ObjectSetInteger ObjectSetInteger(class="num">0, sellName, OBJPROP_STATE, class="kw">false); class=class="str">"cmt">//Calling the created openTrade to open a sell order
面板重建时先清旧对象再画编辑框
在 MT5 脚本里动态刷新交易面板,第一步必须是清场。createPanel() 开头连续调用 ObjectDelete(0, txtName)、ObjectDelete(0, buyName)、ObjectDelete(0, sellName),把上一轮残留的文本框和按钮对象从图表 0(当前图表)删掉,否则同名的 Edit 对象会叠加且属性不更新。 清完之后才调用 EditCreate 重画。注意它的第一个参数是 chart_ID = 0,表示绑定当前图表主窗口(sub_window 也填 0);坐标用 txtX / txtY 变量传,宽高用 txtWidth / txtHeight,这样面板位置可以随锚点函数 panelLoc 切换左上、右下等角落。 编辑框里显示的文本是 string(lotSize),也就是把手数变量实时转成字符串画上去;字体写死 "Arial"、字号 10、ALIGN_LEFT 左对齐,背景白、文字和边框黑。read_only 传 false 意味着这个框允许交易者直接改手数,改完回车就能驱动后面的 openTrade 逻辑。外汇和贵金属杠杆高,面板改手数后下单前务必人工核对,滑点和重报价可能导致实际成交手数与输入不符。
class="type">void createPanel() { class=class="str">"cmt">//--- Delete objects of txtName, buyName, and sellName ObjectDelete(class="num">0, txtName); ObjectDelete(class="num">0, buyName); ObjectDelete(class="num">0, sellName); class=class="str">"cmt">//--- calling the EditCreate function EditCreate( class=class="str">"cmt">// Parameters: class="num">0, class=class="str">"cmt">// const class="type">long (chart_ID): to specify the chart&class="macro">#x27;s ID, we will use(class="num">0). txtName, class=class="str">"cmt">// const class="type">class="kw">string (name): to specify the button name, we will use(txtName) class="num">0, class=class="str">"cmt">// const class="type">int (sub_window): to specify the subwindow index, we will use(class="num">0) for the main window txtX, class=class="str">"cmt">// const class="type">int (x): to specify the X coordinate, we will use(txtX) txtY, class=class="str">"cmt">// const class="type">int (y): to specify the Y coordinate, we will use(txtY) txtWidth, class=class="str">"cmt">// const class="type">int (width):to specify the button width, we will use(txtWidth) txtHeight, class=class="str">"cmt">// const class="type">int (height): to specify the button height, we will use(txtHeight) class="type">class="kw">string(lotSize), class=class="str">"cmt">// const class="type">class="kw">string (text): to specify the text, we will use(lotSize) "Arial", class=class="str">"cmt">// const class="type">class="kw">string (font): to specify the font, we will use "Arial" class="num">10, class=class="str">"cmt">// const class="type">int (font_size): to specify the font size, we will use(class="num">10) ALIGN_LEFT, class=class="str">"cmt">// const ENUM_ALIGN_MODE(align_mode): to specify the position of text, we will use(ALIGN_LEFT) class="kw">false, class=class="str">"cmt">// const class="type">bool (read_only=class="kw">false): to specify the ability to edit, we will be(class="kw">false) panelLoc, class=class="str">"cmt">// const ENUM_BASE_CORNER(corner): to specify the chart corner for anchoring, we will call panelLoc function clrBlack, class=class="str">"cmt">// const class="type">color (clr): to specify the text class="type">color, we will specify clrBlack clrWhite, class=class="str">"cmt">// const class="type">color (back_clr): to specify the background class="type">color, we will specify clrWhite clrBlack, class=class="str">"cmt">// const class="type">color (border_clr): to specify the border class="type">color, we will specify clrBlack class="kw">false class=class="str">"cmt">// const class="type">bool (back=class="kw">false): in the background, we will set class="kw">false
◍ 给买卖按钮传参的实盘写法
在 MT5 面板里画可点击的 Buy / Sell 按钮,核心就是反复调用 ButtonCreate,把坐标、尺寸、配色和锚定角一次性喂进去。下面这段是针对 buy 按钮的实际传参,sell 按钮只是把名字、坐标和背景色换掉,结构完全一致。 注意 chart_ID 用 0 代表当前图表,sub_window 用 0 锁死主窗口,z_order 也填 0——这意味着鼠标点击优先级走默认层,不会盖住 K 线交互。字体写死 Arial、字号 10,按钮文字色 clrBlack、背景 clrGreen,边框 clrBlack,state 与 back / selection / hidden 全为 false,保证按钮常态可见且不被误移动。 外汇与贵金属波动剧烈,这类一键下单面板只解决「点得准」,不解决「该不该点」,实盘前务必在策略测试器里先跑通事件回调。
ButtonCreate( class=class="str">"cmt">// Parameters: class="num">0, class=class="str">"cmt">// const class="type">long (chart_ID): to specify the chart&class="macro">#x27;s ID, we will use(class="num">0) buyName, class=class="str">"cmt">// const class="type">class="kw">string (name): to specify the button name, we will use(buyName) for the buy button class="num">0, class=class="str">"cmt">// const class="type">int (sub_window): to specify the subwindow index, we will use(class="num">0) for the main window buyX, class=class="str">"cmt">// const class="type">int (x): to specify the X coordinate, we will use(buyX) for buy buyY, class=class="str">"cmt">// const class="type">int (y): to specify the Y coordinate, we will use(buyY) for buy btnWidth, class=class="str">"cmt">// const class="type">int (width): to specify the button width, we will use(btnWidth) for buy btnHeight, class=class="str">"cmt">// const class="type">int (height): to specify the button height, we will use(btnHeight) for buy panelLoc, class=class="str">"cmt">// const ENUM_BASE_CORNER(corner): to specify the chart corner for anchoring, we will call panelLoc function for buy button "Buy", class=class="str">"cmt">// const class="type">class="kw">string (text): to specify the text, we will use("Buy") for the buy button "Arial", class=class="str">"cmt">// const class="type">class="kw">string (font): to specify the font, we will use "Arial" class="num">10, class=class="str">"cmt">// const class="type">int (font_size): to specify the font size, we will use(class="num">10) clrBlack, class=class="str">"cmt">// const class="type">color (clr): to specify the text class="type">color, we will specify clrBlack clrGreen, class=class="str">"cmt">// const class="type">color (back_clr): to specify the background class="type">color, we will specify clrGreen for the buy button clrBlack, class=class="str">"cmt">// const class="type">color (border_clr): to specify the border class="type">color, we will specify clrBlack class="kw">false, class=class="str">"cmt">// const class="type">bool (state): to specify if the object is pressed or released, we will specify class="kw">false class="kw">false, class=class="str">"cmt">// const class="type">bool (back=class="kw">false): in the background, we will set class="kw">false class="kw">false, class=class="str">"cmt">// const class="type">bool (selection=class="kw">false): highlight to move, we will set class="kw">false class="kw">false, class=class="str">"cmt">// const class="type">bool (hidden): hidden in the object list, we will set class="kw">false class="num">0); class=class="str">"cmt">// const class="type">long (z_order=class="num">0): priority for mouse click, we will use(class="num">0) for buy button
「用 ButtonCreate 钉死 Sell 按钮的锚点与配色」
在 MT5 面板里挂一个可点击的卖出按钮,核心就是 ButtonCreate 这一串参数。图表 ID 传 0 代表当前图表,子窗口传 0 锁定主图,坐标 sellX / sellY 配合 panelLoc 决定它贴在左上还是右下角。 下面这段是创建卖出按钮的实际调用,逐行拆开看每个槽位在控什么: ButtonCreate( 0, // 图表 ID:0 即当前活跃图表 sellName, // 按钮对象名:用 sellName 变量区分多按钮 0, // 子窗口序号:0 为主图表窗口 sellX, // X 坐标:卖出按钮的水平位置 sellY, // Y 坐标:卖出按钮的垂直位置 btnWidth, // 按钮宽度像素 btnHeight, // 按钮高度像素 panelLoc, // 锚定角:由 panelLoc 函数返回 ENUM_BASE_CORNER "Sell", // 按钮文字:写死 "Sell" "Arial", // 字体:Arial 10, // 字号:10 clrBlack, // 文字色:黑 clrRed, // 背景色:红,卖单视觉警示 clrBlack, // 边框色:黑 false, // 初始状态:未按下 false, // 不放背景层 false, // 不允许选中拖动 false, // 对象列表里可见
- ; // 鼠标点击优先级:0 为普通层
setLot 这段虽小但容易漏判:StringToDouble 转手数后若小于 0 直接 Print 报错并返回,不改写 lotSize。外汇与贵金属杠杆高,手数校验失败若默默继续,可能挂出非预期仓位,实盘前务必在策略测试器里点一下面板输负值验证分支。
ButtonCreate( class="num">0, sellName, class="num">0, sellX, sellY, btnWidth, btnHeight, panelLoc, "Sell", "Arial", class="num">10, clrBlack, clrRed, clrBlack, class="kw">false, class="kw">false, class="kw">false, class="kw">false, class="num">0); } class="type">void setLot(class="type">class="kw">string lotTxt) { class="type">class="kw">double newLot=StringToDouble(lotTxt); if(newLot<class="num">0) { Print("Invaid Volume Specified"); class="kw">return; } lotSize=newLot; }
用 OBJ_EDIT 在图表上落一个可编辑框
想在 MT5 图表上塞一个能手动改字的输入框,核心就是 OBJ_EDIT 对象。下面这个函数把坐标、尺寸、字体、对齐方式全参数化了,默认藏在背景层(hidden=true)且不参与鼠标选中,适合做内部状态显示或低调的交互控件。 函数头里 width 默认 50、height 默认 18、font_size 默认 10,这组数值在 1920×1080 屏上刚好是一行 Arial 小字的紧凑占位;若你做黄金 1 分钟图的悬浮标签,把 height 提到 22 可能更不容易挤字。 代码前半段先 ResetLastError() 清掉旧错误码,再用 ObjectCreate 以 (0,0) 为临时锚点建对象——注意 OBJ_EDIT 的创建不依赖时间/价格坐标,x、y 后面要靠 ObjectSetInteger 单独推。外汇与贵金属波动剧烈,这类图形对象仅作辅助,实盘仍属高风险。
class="type">bool EditCreate(const class="type">long chart_ID=class="num">0, const class="type">class="kw">string name="Edit", const class="type">int sub_window=class="num">0, const class="type">int x=class="num">0, const class="type">int y=class="num">0, const class="type">int width=class="num">50, const class="type">int height=class="num">18, const class="type">class="kw">string text="Text", const class="type">class="kw">string font="Arial", const class="type">int font_size=class="num">10, const ENUM_ALIGN_MODE align=ALIGN_CENTER, const class="type">bool read_only=class="kw">false, const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, const class="type">color clr=clrBlack, const class="type">color back_clr=clrWhite, const class="type">color border_clr=clrNONE, const class="type">bool back=class="kw">false, const class="type">bool selection=class="kw">false, const class="type">bool hidden=true, const class="type">long z_order=class="num">0) { class=class="str">"cmt">//--- Reset the error value by using ResetLastError() ResetLastError(); class=class="str">"cmt">//--- Create an edit field if(!ObjectCreate(chart_ID, name, OBJ_EDIT, sub_window, class="num">0, class="num">0)) {