MQL5交易工具(第一部分):构建交互式可视化挂单交易助手工具·进阶篇
🛠️

MQL5交易工具(第一部分):构建交互式可视化挂单交易助手工具·进阶篇

(2/3)· 从概念到回测,拆解如何在 MT5 里用图形界面替代繁琐的手动挂单流程

含代码示例实战向 第 2/3 篇
不少交易者在 MT5 里手动填挂单面板,价格层级和点差靠肉眼估,滑点和错单经常发生。把交互逻辑写死在脑子里而非图表上,市场一跳就手忙脚乱。本篇接着把可视化助手的实现与回测摊开讲,少走弯路。

「在MT5图表上画一个可交互按钮」

想给盯盘面板加一个点击按钮,核心是先 ObjectCreate 建 OBJ_BUTTON 对象,失败就打印错误码并退出,成功再逐个设属性。下面这段是创建按钮并定位、设样式的典型写法,复制进 EA 的 OnInit 或自定义函数里就能跑。

MQL5 / C++
if(!ObjectCreate(class="num">0, objName, OBJ_BUTTON, class="num">0, class="num">0, class="num">0)) {
  Print(__FUNCTION__, ": Failed to create Btn: Error Code: ", GetLastError());
  class="kw">return class="kw">false;
}
ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, xD);
ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, yD);
ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, xS);
ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS);
ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontsize);
ObjectSetString(class="num">0, objName, OBJPROP_FONT, font);
ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrTxt);
ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBG);
ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_COLOR, clrBorder);
ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, isBack);
ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, class="kw">false);
ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, class="kw">false);
ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, class="kw">false);
ChartRedraw(class="num">0);
class="kw">return true;
逐行拆一下:ObjectCreate 第1参0表示当前图表,第4、5参0是占位坐标,真正位置靠后面 OBJPROP_XDISTANCE / YDISTANCE 从边角偏移决定。CORNER_LEFT_UPPER 意味着 xD、yD 是相对左上角的像素距离,改这个宏能换锚点。 OBJPROP_BACK 设 true 会把按钮塞到背景层,避免挡 K 线;OBJPROP_SELECTABLE 和 OBJPROP_SELECTED 都置 false,按钮就不会被鼠标误选中拖走。最后 ChartRedraw(0) 强制重绘,否则新对象可能不立即显示。 控制面板背景常用 OBJ_RECTANGLE_LABEL 先铺底:ObjectCreate(0, PANEL_BG, OBJ_RECTANGLE_LABEL, 0, 0, 0) 建矩形标签,再用 XDISTANCE / YDISTANCE 定到 panel_x、panel_y。外汇与贵金属波动剧烈、杠杆高风险,面板只做辅助,信号确认仍靠价格行为本身。

MQL5 / C++
if(!ObjectCreate(class="num">0, objName, OBJ_BUTTON, class="num">0, class="num">0, class="num">0)) {
  Print(__FUNCTION__, ": Failed to create Btn: Error Code: ", GetLastError());
  class="kw">return class="kw">false;
}
ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, xD);
ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, yD);
ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, xS);
ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, yS);
ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontsize);
ObjectSetString(class="num">0, objName, OBJPROP_FONT, font);
ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clrTxt);
ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, clrBG);
ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_COLOR, clrBorder);
ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, isBack);
ObjectSetInteger(class="num">0, objName, OBJPROP_STATE, class="kw">false);
ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTABLE, class="kw">false);
ObjectSetInteger(class="num">0, objName, OBJPROP_SELECTED, class="kw">false);
ChartRedraw(class="num">0);
class="kw">return true;

面板与手数输入框的绘制细节

在 MT5 里用 ObjectSetInteger 搭一个悬浮交易面板时,背景矩形的尺寸和层级是关键。上面这段把 PANEL_BG 的宽度锁在 250 像素、高度 280 像素,背景色用了 C'070,070,070'(深灰),边框给白色,并且 OBJPROP_BACK 设为 false,意味着它处于前景层、不会被 K 线盖住。 手数输入框 LOT_EDIT 是 OBJ_EDIT 类型,左上角坐标相对面板偏移 (70,40),宽 110 高 25,默认文本直接写死 "0.01"。字体走 Arial、字号 13、文字居中、黑字白底黑边——这套参数在 1080P 屏上刚好不挤,但换到 4K 屏可能得把 XSIZE 加到 140 才不显窄。 关闭按钮用 createButton 封装,传了字符码 203 配合 Wingdings 字体显示叉号,位置贴在 panel_x+209、panel_y+1,尺寸 40×25,底色深灰、文字深红。外汇和贵金属杠杆高,面板上手数框若没做输入校验,误填 10.0 可能瞬间放大风险敞口,建议复制代码后自己加一个 NormalizeDouble 限制。 价格标签 PRICE_LABEL 是 OBJ_LABEL,放在 panel_x+10、panel_y+70,只设了坐标还没填内容,下一步通常在 Tick 事件里用 ObjectSetString 把实时买价刷进去。开 MT5 新建 EA 把这些对象名换成你自己的宏,编译后拖到图表就能看到面板雏形。

MQL5 / C++
ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_XSIZE, class="num">250);              class=class="str">"cmt">//--- Set background width
ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_YSIZE, class="num">280);              class=class="str">"cmt">//--- Set background height
ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_BGCOLOR, C&class="macro">#x27;class="num">070,class="num">070,class="num">070&class="macro">#x27;); class=class="str">"cmt">//--- Set background class="type">color
ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_BORDER_COLOR, clrWhite);  class=class="str">"cmt">//--- Set border class="type">color
ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_BACK, class="kw">false);             class=class="str">"cmt">//--- Set background to foreground

createButton(CLOSE_BTN, CharToString(class="num">203), panel_x + class="num">209, panel_y + class="num">1, class="num">40, class="num">25, clrWhite, clrCrimson, class="num">12, C&class="macro">#x27;class="num">070,class="num">070,class="num">070&class="macro">#x27;, class="kw">false, "Wingdings"); class=class="str">"cmt">//--- Create close button

class=class="str">"cmt">// Lot size input
ObjectCreate(class="num">0, LOT_EDIT, OBJ_EDIT, class="num">0, class="num">0, class="num">0); class=class="str">"cmt">//--- Create lot size edit field
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_XDISTANCE, panel_x + class="num">70); class=class="str">"cmt">//--- Set edit field x-position
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_YDISTANCE, panel_y + class="num">40); class=class="str">"cmt">//--- Set edit field y-position
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_XSIZE, class="num">110);              class=class="str">"cmt">//--- Set edit field width
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_YSIZE, class="num">25);               class=class="str">"cmt">//--- Set edit field height
ObjectSetString(class="num">0, LOT_EDIT, OBJPROP_TEXT, "class="num">0.01");             class=class="str">"cmt">//--- Set class="kw">default lot size text
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_COLOR, clrBlack);         class=class="str">"cmt">//--- Set text class="type">color
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_BGCOLOR, clrWhite);       class=class="str">"cmt">//--- Set background class="type">color
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_BORDER_COLOR, clrBlack);  class=class="str">"cmt">//--- Set border class="type">color
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_ALIGN, ALIGN_CENTER);     class=class="str">"cmt">//--- Center text
ObjectSetString(class="num">0, LOT_EDIT, OBJPROP_FONT, "Arial");            class=class="str">"cmt">//--- Set font
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_FONTSIZE, class="num">13);            class=class="str">"cmt">//--- Set font size
ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_BACK, class="kw">false);             class=class="str">"cmt">//--- Set to foreground

class=class="str">"cmt">// Entry price label
ObjectCreate(class="num">0, PRICE_LABEL, OBJ_LABEL, class="num">0, class="num">0, class="num">0);                  class=class="str">"cmt">//--- Create entry price label
ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_XDISTANCE, panel_x + class="num">10); class=class="str">"cmt">//--- Set label x-position
ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_YDISTANCE, panel_y + class="num">70); class=class="str">"cmt">//--- Set label y-position

◍ 用 OBJ_LABEL 把入场与止损止盈钉在图表上

在 MT5 自定义面板里,价格标签和 SL/TP 标签都靠 OBJ_LABEL 对象实现,坐标用 XDISTANCE / YDISTANCE 相对窗口左上角像素定位,不随价格轴跳动。 入场标签 PRICE_LABEL 宽度设 230 像素、字号 13、白色 Arial Bold、居中且置顶(OBJPROP_BACK=false),默认文本写「Entry: -」,等成交后再由脚本改写。 SL 标签放在 panel_x+10、panel_y+95,宽 110、字号 12、黄色;TP 标签 x 偏移再 +120 到 panel_x+130,同 y、同尺寸、同字体但颜色沿用默认。两者默认文本分别是「SL: -」「TP: -」,实盘里把具体点数填进去即可。 外汇和贵金属波动大,标签只是辅助读数,真正下单前仍要人工核对止损距离与杠杆风险。

MQL5 / C++
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_XSIZE, class="num">230);              class=class="str">"cmt">//--- Set label width
  ObjectSetString(class="num">0, PRICE_LABEL, OBJPROP_TEXT, "Entry: -");         class=class="str">"cmt">//--- Set class="kw">default text
  ObjectSetString(class="num">0, PRICE_LABEL, OBJPROP_FONT, "Arial Bold");       class=class="str">"cmt">//--- Set font
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_FONTSIZE, class="num">13);            class=class="str">"cmt">//--- Set font size
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_COLOR, clrWhite);         class=class="str">"cmt">//--- Set text class="type">color
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_ALIGN, ALIGN_CENTER);     class=class="str">"cmt">//--- Center text
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_BACK, class="kw">false); class=class="str">"cmt">//--- Set to foreground

  class=class="str">"cmt">// SL and TP labels
  ObjectCreate(class="num">0, SL_LABEL, OBJ_LABEL, class="num">0, class="num">0, class="num">0);                  class=class="str">"cmt">//--- Create stop-loss label
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_XDISTANCE, panel_x + class="num">10); class=class="str">"cmt">//--- Set label x-position
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_YDISTANCE, panel_y + class="num">95); class=class="str">"cmt">//--- Set label y-position
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_XSIZE, class="num">110);              class=class="str">"cmt">//--- Set label width
  ObjectSetString(class="num">0, SL_LABEL, OBJPROP_TEXT, "SL: -");            class=class="str">"cmt">//--- Set class="kw">default text
  ObjectSetString(class="num">0, SL_LABEL, OBJPROP_FONT, "Arial Bold");       class=class="str">"cmt">//--- Set font
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_FONTSIZE, class="num">12);            class=class="str">"cmt">//--- Set font size
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_COLOR, clrYellow);        class=class="str">"cmt">//--- Set text class="type">color
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_ALIGN, ALIGN_CENTER);     class=class="str">"cmt">//--- Center text
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_BACK, class="kw">false);             class=class="str">"cmt">//--- Set to foreground

  ObjectCreate(class="num">0, TP_LABEL, OBJ_LABEL, class="num">0, class="num">0, class="num">0);                   class=class="str">"cmt">//--- Create take-profit label
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_XDISTANCE, panel_x + class="num">130); class=class="str">"cmt">//--- Set label x-position
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_YDISTANCE, panel_y + class="num">95);  class=class="str">"cmt">//--- Set label y-position
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_XSIZE, class="num">110);               class=class="str">"cmt">//--- Set label width
  ObjectSetString(class="num">0, TP_LABEL, OBJPROP_TEXT, "TP: -");             class=class="str">"cmt">//--- Set class="kw">default text
  ObjectSetString(class="num">0, TP_LABEL, OBJPROP_FONT, "Arial Bold");        class=class="str">"cmt">//--- Set font
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_FONTSIZE, class="num">12);             class=class="str">"cmt">//--- Set font size

「挂单面板的按钮与初始化落点」

在控制面板函数尾部,先给止盈标签 TP_LABEL 设了三项属性:文字染成 clrLime(亮绿)、水平居中、且强制置于前景(OBJPROP_BACK=false),避免被 K 线盖住。 随后一口气铺了六枚交易按钮:Buy Stop / Sell Stop 放在 y+140 这一行,Buy Limit / Sell Limit 落在 y+180,Place Order 与 Cancel 则在 y+240;每枚宽 110、高 30,配色按方向区分(绿系挂多、砖红挂空、钢蓝提交、石板灰取消)。 createControlPanel() 在 OnInit 里被调用一次,紧接着 ChartRedraw(0) 强制重绘,使面板在 EA 加载瞬间就显示出来,函数返回 INIT_SUCCEEDED 表示初始化通过。外汇与贵金属杠杆高,这类一键挂单面板只解决操作效率,不替代入场判断。 OnChartEvent 的骨架也已就位:入参 id 承接事件类型,lparam 以 long 引用方式接收鼠标类坐标,后续按钮点击的分发逻辑会挂在这个事件里。

MQL5 / C++
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_COLOR, clrLime);           class=class="str">"cmt">//--- Set text class="type">color
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_ALIGN, ALIGN_CENTER);      class=class="str">"cmt">//--- Center text
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_BACK, class="kw">false);              class=class="str">"cmt">//--- Set to foreground

  class=class="str">"cmt">// Order type buttons
  createButton(BUY_STOP_BTN, "Buy Stop", panel_x + class="num">10, panel_y + class="num">140, class="num">110, class="num">30, clrWhite, clrForestGreen, class="num">10, clrBlack, class="kw">false, "Arial");    class=class="str">"cmt">//--- Create Buy Stop button
  createButton(SELL_STOP_BTN, "Sell Stop", panel_x + class="num">130, panel_y + class="num">140, class="num">110, class="num">30, clrWhite, clrFireBrick, class="num">10, clrBlack, class="kw">false, "Arial");   class=class="str">"cmt">//--- Create Sell Stop button
  createButton(BUY_LIMIT_BTN, "Buy Limit", panel_x + class="num">10, panel_y + class="num">180, class="num">110, class="num">30, clrWhite, clrForestGreen, class="num">10, clrBlack, class="kw">false, "Arial");  class=class="str">"cmt">//--- Create Buy Limit button
  createButton(SELL_LIMIT_BTN, "Sell Limit", panel_x + class="num">130, panel_y + class="num">180, class="num">110, class="num">30, clrWhite, clrFireBrick, class="num">10, clrBlack, class="kw">false, "Arial"); class=class="str">"cmt">//--- Create Sell Limit button

  class=class="str">"cmt">// Place Order and Cancel buttons
  createButton(PLACE_ORDER_BTN, "Place Order", panel_x + class="num">10, panel_y + class="num">240, class="num">110, class="num">30, clrWhite, clrDodgerBlue, class="num">10, clrBlack, class="kw">false, "Arial"); class=class="str">"cmt">//--- Create Place Order button
  createButton(CANCEL_BTN, "Cancel", panel_x + class="num">130, panel_y + class="num">240, class="num">110, class="num">30, clrWhite, clrSlateGray, class="num">10, clrBlack, class="kw">false, "Arial");           class=class="str">"cmt">//--- Create Cancel button
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit() {

class=class="str">"cmt">// Create control panel
  createControlPanel();   class=class="str">"cmt">//--- Call function to create the control panel
  ChartRedraw(class="num">0);         class=class="str">"cmt">//--- Redraw chart to display panel
  class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">//--- Return successful initialization
}

class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert onchart event function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnChartEvent(
  const class="type">int id,         class=class="str">"cmt">//--- Event ID
  const class="type">long& lparam,   class=class="str">"cmt">//--- Long parameter(e.g., x-coordinate for mouse)

点击挂单按钮后的事件与面板显隐

在 MT5 的图表事件回调里,捕捉到 CHARTEVENT_OBJECT_CLICK 且 sparam 等于 BUY_STOP_BTN 时,就把内部变量 selected_order_type 置为 "BUY_STOP"。这一步是图形面板和订单逻辑的连接点:用户点哪个按钮,后续下单函数就走哪条分支。 showTool() 负责把一整套面板对象从背景层拉出来。它连续对 PANEL_BG、LOT_EDIT、PRICE_LABEL、SL_LABEL、TP_LABEL 以及四个挂单按钮和确认/取消/关闭按钮调用 ObjectSetInteger(..., OBJPROP_BACK, false),共 12 次隐藏反转,确保这些对象处于可交互的前层。 工具横坐标按 chart_width - 400 - 50 算:400 是 REC1 矩形宽度,50 是右边距。若 selected_order_type 是 BUY_STOP 或 BUY_LIMIT,则按“TP 在上、入场在中、SL 在下”的布局,用 createButton 在 (tool_x, 20) 画一个宽 350、高 30、绿底黑字 Arial Black 的矩形。外汇与贵金属挂单受滑点和流动性影响,这类按钮触发只是概率优势的起点,不等于成交必成。

MQL5 / C++
const class="type">class="kw">double& dparam, class=class="str">"cmt">//--- Double parameter(e.g., y-coordinate for mouse)
const class="type">class="kw">string& sparam  class=class="str">"cmt">//--- String parameter(e.g., object name)
) {
  if(id == CHARTEVENT_OBJECT_CLICK) {     class=class="str">"cmt">//--- Handle object click events
    class=class="str">"cmt">// Handle order type buttons
    if(sparam == BUY_STOP_BTN) {         class=class="str">"cmt">//--- Check if Buy Stop button clicked
      selected_order_type = "BUY_STOP"; class=class="str">"cmt">//--- Set order type to Buy Stop
    }
  }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Show main tool                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void showTool() {
  class=class="str">"cmt">// Hide panel
  ObjectSetInteger(class="num">0, PANEL_BG, OBJPROP_BACK, class="kw">false);        class=class="str">"cmt">//--- Hide panel background
  ObjectSetInteger(class="num">0, LOT_EDIT, OBJPROP_BACK, class="kw">false);        class=class="str">"cmt">//--- Hide lot edit field
  ObjectSetInteger(class="num">0, PRICE_LABEL, OBJPROP_BACK, class="kw">false);     class=class="str">"cmt">//--- Hide price label
  ObjectSetInteger(class="num">0, SL_LABEL, OBJPROP_BACK, class="kw">false);        class=class="str">"cmt">//--- Hide SL label
  ObjectSetInteger(class="num">0, TP_LABEL, OBJPROP_BACK, class="kw">false);        class=class="str">"cmt">//--- Hide TP label
  ObjectSetInteger(class="num">0, BUY_STOP_BTN, OBJPROP_BACK, class="kw">false);    class=class="str">"cmt">//--- Hide Buy Stop button
  ObjectSetInteger(class="num">0, SELL_STOP_BTN, OBJPROP_BACK, class="kw">false);   class=class="str">"cmt">//--- Hide Sell Stop button
  ObjectSetInteger(class="num">0, BUY_LIMIT_BTN, OBJPROP_BACK, class="kw">false);   class=class="str">"cmt">//--- Hide Buy Limit button
  ObjectSetInteger(class="num">0, SELL_LIMIT_BTN, OBJPROP_BACK, class="kw">false);  class=class="str">"cmt">//--- Hide Sell Limit button
  ObjectSetInteger(class="num">0, PLACE_ORDER_BTN, OBJPROP_BACK, class="kw">false); class=class="str">"cmt">//--- Hide Place Order button
  ObjectSetInteger(class="num">0, CANCEL_BTN, OBJPROP_BACK, class="kw">false);      class=class="str">"cmt">//--- Hide Cancel button
  ObjectSetInteger(class="num">0, CLOSE_BTN, OBJPROP_BACK, class="kw">false);       class=class="str">"cmt">//--- Hide Close button

  class=class="str">"cmt">// Create main tool class="num">150 pixels from the right edge
  class="type">int chart_width = (class="type">int)ChartGetInteger(class="num">0, CHART_WIDTH_IN_PIXELS); class=class="str">"cmt">//--- Get chart width
  class="type">int tool_x = chart_width - class="num">400 - class="num">50;                              class=class="str">"cmt">//--- Calculate tool x-position(class="num">400 is REC1 width, class="num">50 is margin)

  if(selected_order_type == "BUY_STOP" || selected_order_type == "BUY_LIMIT") { class=class="str">"cmt">//--- Check for buy orders
    class=class="str">"cmt">// Buy orders: TP at top, entry in middle, SL at bottom
    createButton(REC1, "", tool_x, class="num">20, class="num">350, class="num">30, clrWhite, clrGreen, class="num">13, clrBlack, class="kw">false, "Arial Black"); class=class="str">"cmt">//--- Create TP rectangle

◍ 买卖方向下的矩形链坐标推导

在 MT5 面板里画风险区块,核心是把第一个矩形的锚点读出来,再按固定偏移堆出后续区块。买单调法以 REC1 为基准:先取它的 XDISTANCE、YDISTANCE、XSIZE、YSIZE 四个整型属性,后续 REC2~REC5 的 x 距离和宽度直接沿用,y 距离则逐级累加前一个矩形的高度。 具体看,REC2 的 y 偏移 = REC1.y + REC1.ys,高度锁 100;REC3 接在 REC2 下方、高度 30;REC4 再叠 100、REC5 再叠 30。这样一条竖向风险带就出来了,视觉上 SL、入场、TP 分区清晰,外汇和贵金属品种因点值波动大,这种分区能帮交易者快速读穿订单暴露面,但杠杆风险依旧高,参数只作参考。 卖单分支反过来:以 REC5 红块(SL 区)为顶,yd5 读出后,REC2 从其下沿接出、高度 100,REC3 高度 30,REC4 再 100。代码里 createButton 给 REC5 传了 x=20、宽 350、高 30、红底白字,说明卖单的止损条固定在面板左上区域,其余区块跟随递推。 开 MT5 把这段接进你的 EA,改 ys2/ys3 的数值就能压扁或拉长止损、进场提示区,验证不同品种下面板会不会挤到一起。

MQL5 / C++
xd1 = (class="type">int)ObjectGetInteger(class="num">0, REC1, OBJPROP_XDISTANCE); class=class="str">"cmt">//--- Get REC1 x-distance
yd1 = (class="type">int)ObjectGetInteger(class="num">0, REC1, OBJPROP_YDISTANCE); class=class="str">"cmt">//--- Get REC1 y-distance
xs1 = (class="type">int)ObjectGetInteger(class="num">0, REC1, OBJPROP_XSIZE);     class=class="str">"cmt">//--- Get REC1 x-size
ys1 = (class="type">int)ObjectGetInteger(class="num">0, REC1, OBJPROP_YSIZE);     class=class="str">"cmt">//--- Get REC1 y-size

xd2 = xd1;       class=class="str">"cmt">//--- Set REC2 x-distance
yd2 = yd1 + ys1; class=class="str">"cmt">//--- Set REC2 y-distance
xs2 = xs1;       class=class="str">"cmt">//--- Set REC2 x-size
ys2 = class="num">100;       class=class="str">"cmt">//--- Set REC2 y-size
xd3 = xd2;       class=class="str">"cmt">//--- Set REC3 x-distance
yd3 = yd2 + ys2; class=class="str">"cmt">//--- Set REC3 y-distance
xs3 = xs2;       class=class="str">"cmt">//--- Set REC3 x-size
ys3 = class="num">30;        class=class="str">"cmt">//--- Set REC3 y-size

xd4 = xd3;       class=class="str">"cmt">//--- Set REC4 x-distance
yd4 = yd3 + ys3; class=class="str">"cmt">//--- Set REC4 y-distance
xs4 = xs3;       class=class="str">"cmt">//--- Set REC4 x-size
ys4 = class="num">100;       class=class="str">"cmt">//--- Set REC4 y-size
xd5 = xd4;       class=class="str">"cmt">//--- Set REC5 x-distance
yd5 = yd4 + ys4; class=class="str">"cmt">//--- Set REC5 y-distance
xs5 = xs4;       class=class="str">"cmt">//--- Set REC5 x-size
ys5 = class="num">30;        class=class="str">"cmt">//--- Set REC5 y-size
 }
 else { class=class="str">"cmt">//--- Handle sell orders
 class=class="str">"cmt">// Sell orders: SL at top, entry in middle, TP at bottom
 createButton(REC5, "", tool_x, class="num">20, class="num">350, class="num">30, clrWhite, clrRed, class="num">13, clrBlack, class="kw">false, "Arial Black"); class=class="str">"cmt">//--- Create SL rectangle

 xd5 = (class="type">int)ObjectGetInteger(class="num">0, REC5, OBJPROP_XDISTANCE); class=class="str">"cmt">//--- Get REC5 x-distance
 yd5 = (class="type">int)ObjectGetInteger(class="num">0, REC5, OBJPROP_YDISTANCE); class=class="str">"cmt">//--- Get REC5 y-distance
 xs5 = (class="type">int)ObjectGetInteger(class="num">0, REC5, OBJPROP_XSIZE);     class=class="str">"cmt">//--- Get REC5 x-size
 ys5 = (class="type">int)ObjectGetInteger(class="num">0, REC5, OBJPROP_YSIZE);     class=class="str">"cmt">//--- Get REC5 y-size

 xd2 = xd5;       class=class="str">"cmt">//--- Set REC2 x-distance
 yd2 = yd5 + ys5; class=class="str">"cmt">//--- Set REC2 y-distance
 xs2 = xs5;       class=class="str">"cmt">//--- Set REC2 x-size
 ys2 = class="num">100;       class=class="str">"cmt">//--- Set REC2 y-size
 xd3 = xd2;       class=class="str">"cmt">//--- Set REC3 x-distance
 yd3 = yd2 + ys2; class=class="str">"cmt">//--- Set REC3 y-distance
 xs3 = xs2;       class=class="str">"cmt">//--- Set REC3 x-size
 ys3 = class="num">30;        class=class="str">"cmt">//--- Set REC3 y-size

 xd4 = xd3;       class=class="str">"cmt">//--- Set REC4 x-distance
 yd4 = yd3 + ys3; class=class="str">"cmt">//--- Set REC4 y-distance
让小布替你跑这套
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到挂单层级与点差实时反馈,把重复劳动交给小布,你专注决策。

常见问题

给面板背景、手数框、订单按钮等分配唯一常量标识,后续修改布局或扩展功能时不用全局搜字符串,降低出错概率,也方便多人维护代码。
回测基于历史 tick 与你的价位触发逻辑,若 EA 正确读取拖拽对象价格并下单,触发可能接近实盘,但点差与延迟仍可能使结果偏向乐观,需结合多周期验证。
小布目前提供品种页的层级与点差可视化,不自载第三方 EA;你可参考本文交互逻辑,把小布的盘口反馈作为手动或半自动挂单的辅助依据。
在按钮事件里读取 LotEdit 手数与拖拽价格对象,调用 trade.BuyStop 并传入对应参数即可,注意校验最小止损距离与订单有效性。
外汇贵金属杠杆高、波动剧烈,可视化仅降低操作失误,不预示方向;任何挂单都可能因跳空无法成交,仓位管理仍需独立判断。