MQL5 简介(第 9 部分):理解和使用 MQL5 中的对象(基础篇)
📘

MQL5 简介(第 9 部分):理解和使用 MQL5 中的对象(基础篇)

第 1/3 篇

「MQL5 里的对象到底是什么」

在 MQL5 里,对象不是 K 线本身,而是你往图表上额外画的图形与控件:趋势线、矩形、箭头、文本、按钮都属于这一层。它们和指标缓冲区不同,不随品种数据重算而自动消亡,生命周期由你显式创建和删除,或者一直挂到图表被关掉。 很多新手把对象当成『画上去就完事』的装饰,其实对象可以用 OBJPROP_TIME1、OBJPROP_PRICE1 这类属性绑定到具体坐标,也能通过程序读取鼠标点击位置来动态生成。2025 年 5 月发布的 MQL5 文档第 9 部分明确把『理解和使用对象』单列成章,说明官方已把它从辅助功能抬到核心编程模型。 开 MT5 按 F4 进编辑器,新建脚本粘一段 ObjectCreate 就能验证:对象名若重名会返回 false,图表上却看不到报错弹窗,只在 Experts 日志留一行。这个坑在回测里更隐蔽——测试模式下多数图形对象根本不会渲染,但你用 ObjectsTotal(0) 去数,数量照样在涨。

用图表对象给交易画一条可视路线

MQL5 的图表对象是可以直接丢在报价图上的图形元素,用来承载价格水平、交易区间和文字注释。它不只是装饰:矩形框住支撑阻力,反转点就比裸 K 一眼好看出来;箭头和自定义指标则能把数据层直接压进图表。 我们要落地的这个 EA,核心是把一笔持仓的入場、止损、止盈用图形连成一条路线。它实时刷新,不依赖外部数据源,浮亏浮盈直接画在图上,你扫一眼就知道风险回报比。 EA 对参数修改是即时响应的。你拖动 TP 或 SL,图表上的线段和价格标签立刻跟着变,不会留着旧位置误导你。持仓时间拉长时,图形元素会自动加粗或放大,解决小周期开单、大周期不明显的监控断层。 历史端也能回看:限定日期范围,EA 把过往每笔的盈亏和进出场价绘回图表,放大单笔就能做轻量复盘。外汇和贵金属杠杆高、滑点大,这类可视化只辅助判断,不替代风控。

◍ MT5 图表对象:把仓位状态画在盘面

MQL5 里的图表对象本质是挂在价格窗口上的可视化组件,从最简单的水平线、文本,到通道、箭头都算。它们的作用不是装饰,而是把支撑阻力、趋势方向和持仓盈亏直接烙在图上,让你扫一眼就能判断市况,而不是翻一堆数字。 自定义这些对象的颜色、粗细和位置,是降低漏看信号的有效手段。比如把关键支撑阻力画成粗红实线,在波动剧烈的时段也不容易被忽略;把计划好的策略写成醒目文本注释,相当于给未来的自己留了视觉锚点。 本项目只挑三个最实用的对象落地。趋势线从开仓价连到最新卖价,每次 tick 更新,实时反映持仓以来的价格路径;文本标签每笔 tick 刷新,直接标出 +$100 或 -$50 这样的浮动盈亏;矩形对象则用来圈定风险区——亏损时从入场画到止损,盈利时从入场画到止盈。 这三个对象的创建和修改逻辑,和 MQL5 其他图形对象基本一致。吃透趋势线、文本标签、矩形的写法,后面换斐波那契或箭头对象也只是换函数名的事。外汇和贵金属杠杆高、跳空频繁,这类实时可视化能帮你更快识别逼近止损的概率,但任何图形辅助都不替代风控。

「用锚点把对象钉死在图表上」

在 MT5 里做可视化辅助,核心不是「画出来」,而是「钉在哪」。ObjectCreate() 这一函数决定了对象类型与落点,但真正控制精度的,是它后面那几组 time/price 参数——它们就是锚点。 时间和价格构成图表的二维坐标系:纵轴是 price,横轴是 time。给 ObjectCreate 传 time1/price1 就是首个锚点,趋势线、矩形都从这儿起;time2/price2 是第二锚点,决定线的终点或矩形的对角;通道、三角形这类复杂图形才用得上 time3/price3。文本标签(OBJ_TEXT)只需一组锚点就能定位,比如把「在这里购买」挂在某一根 K 线的特定价位旁。 下面这段可直接丢进脚本跑,它用 2024.08.21 16:00 的 8766.01 和 2024.08.28 08:00 的 8854.51 两个锚点拉出一条趋势线。外汇与贵金属杠杆高、滑点大,锚点取历史时刻做回看验证即可,别拿实盘 tick 直接套。 对象画完只是开始。ObjectSetInteger 改颜色、线宽、线型;ObjectSetDouble 调锚点坐标(比如动态挪趋势线端点);ObjectSetString 换文本标签显示内容。三者配合,才能让 SL 区、TP 区和入场标注在乱序行情里仍一眼可辨。

MQL5 / C++
ObjectCreate(chart_id, object_name, object_type, sub_window, time1, price1, time2, price2, time3, price3);
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
class=class="str">"cmt">// Define the first anchor point for the trendline
class=class="str">"cmt">// &class="macro">#x27;time1&class="macro">#x27; is the class="type">class="kw">datetime for the first point, and &class="macro">#x27;price1&class="macro">#x27; is the price at that time
   class="type">class="kw">datetime time1  = D&class="macro">#x27;class="num">2024.08.class="num">21 class="num">16:class="num">00&class="macro">#x27;;
   class="type">class="kw">double   price1 = class="num">8766.01;
class=class="str">"cmt">// Define the second anchor point for the trendline
class=class="str">"cmt">// &class="macro">#x27;time2&class="macro">#x27; is the class="type">class="kw">datetime for the second point, and &class="macro">#x27;price2&class="macro">#x27; is the price at that time
   class="type">class="kw">datetime time2  = D&class="macro">#x27;class="num">2024.08.class="num">28 class="num">08:class="num">00&class="macro">#x27;;
   class="type">class="kw">double   price2 = class="num">8854.51;
class=class="str">"cmt">// Create a trendline object on the chart
class=class="str">"cmt">// &class="macro">#x27;chart_id&class="macro">#x27; is the ID of the chart where the object will be placed
class=class="str">"cmt">// "Trend Line" is the name of the trendline object
class=class="str">"cmt">// &class="macro">#x27;OBJ_TREND&class="macro">#x27; specifies that the object is a trendline
class=class="str">"cmt">// The last four parameters(class="num">0, time1, price1, time2, price2) specify the anchor points of the trendline
   ObjectCreate(chart_id, "Trend Line", OBJ_TREND, class="num">0, time1, price1, time2, price2);
  }
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
class=class="str">"cmt">// Define the time for the text label&class="macro">#x27;s position(August class="num">21, class="num">2024, at class="num">16:class="num">00)
   class="type">class="kw">datetime time1  = D&class="macro">#x27;class="num">2024.08.class="num">21 class="num">16:class="num">00&class="macro">#x27;;
class=class="str">"cmt">// Define the price level for the text label&class="macro">#x27;s position(class="num">8766.01)
   class="type">class="kw">double   price1 = class="num">8766.01;
class=class="str">"cmt">// Create a text object named "Text" on the chart at the specified time and price

在MT5图表上钉死文字与趋势线锚点

想在MT5上把某根K线和某个价位永久标记出来,用OBJ_TEXT和OBJ_TREND是最直接的两类图形对象。下面这段脚本把文字『Buy Here』钉在2024.08.21 16:00的8766.01,又拉了一条虚线趋势到2024.08.28 08:00的8854.51,价差88.50点,这段区间内价格倾向沿线上移。 外汇与贵金属杠杆高,这类手动锚点只作位置参考,不预示方向,实盘验证时请先开模拟 chart 跑一遍。 代码里的ChartID()取的是当前图表句柄,ObjectCreate的第三参0表示绑定在主窗口;若漏了chart_id直接调,对象可能建到错误图表。时间用D'2024.08.21 16:00'字面量,价格用double字面量,写错一位小数标的位置就偏出屏。

MQL5 / C++
  ObjectCreate(chart_id, "Text", OBJ_TEXT, class="num">0, time1, price1);
class=class="str">"cmt">// Set the text content of the object to display "Buy Here"
  ObjectSetString(chart_id, "Text", OBJPROP_TEXT, "Buy Here");
  }
class=class="str">"cmt">// Define the time for the text label&class="macro">#x27;s position(August class="num">21, class="num">2024, at class="num">16:class="num">00)
class="type">class="kw">datetime time1  = D&class="macro">#x27;class="num">2024.08.class="num">21 class="num">16:class="num">00&class="macro">#x27;;
class=class="str">"cmt">// Define the price level for the text label&class="macro">#x27;s position(class="num">8766.01)
class="type">class="kw">double   price1 = class="num">8766.01;
class=class="str">"cmt">// Create a text object named "Text" on the chart at the specified time and price
ObjectCreate(chart_id, "Text", OBJ_TEXT, class="num">0, time1, price1);
class=class="str">"cmt">// Set the text content of the object to display "Buy Here"
ObjectSetString(chart_id, "Text", OBJPROP_TEXT, "Buy Here");
class=class="str">"cmt">// Set the class="type">color of the text object to Medium Blue
ObjectSetInteger(chart_id, "Text", OBJPROP_COLOR, clrMediumBlue);
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
   class="type">class="kw">datetime time1  = D&class="macro">#x27;class="num">2024.08.class="num">21 class="num">16:class="num">00&class="macro">#x27;;
   class="type">class="kw">double   price1 = class="num">8766.01;
class=class="str">"cmt">// Define the second anchor point for the trendline
class=class="str">"cmt">// &class="macro">#x27;time2&class="macro">#x27; is the class="type">class="kw">datetime for the second point, and &class="macro">#x27;price2&class="macro">#x27; is the price at that time
   class="type">class="kw">datetime time2  = D&class="macro">#x27;class="num">2024.08.class="num">28 class="num">08:class="num">00&class="macro">#x27;;
   class="type">class="kw">double   price2 = class="num">8854.51;
class=class="str">"cmt">// Create a trend line object on the chart with the name "Trend Line"
class=class="str">"cmt">// The trend line will be drawn from time1/price1 to time2/price2
   ObjectCreate(chart_id, "Trend Line", OBJ_TREND, class="num">0, time1, price1, time2, price2);
class=class="str">"cmt">// Set the style of the trend line to a dashed line
   ObjectSetInteger(chart_id, "Trend Line", OBJPROP_STYLE, STYLE_DASH);
class=class="str">"cmt">// Set the width of the trend line to class="num">2
   ObjectSetInteger(chart_id, "Trend Line", OBJPROP_WIDTH, class="num">2);
  }
class=class="str">"cmt">// Create a text object named "Text" on the chart at the specified time and price
ObjectCreate(chart_id, "Text", OBJ_TEXT, class="num">0, time1, price1);
class=class="str">"cmt">// Set the text content of the object to display "Buy Here"
ObjectSetString(chart_id, "Text", OBJPROP_TEXT, "Buy Here");

◍ 把持仓与历史画进图表对象

在 MT5 图表上实时呈现仓位风险回报,核心是用矩形框出 SL/TP 区域、用趋势线连开场价与现价、用文本标签标出入场价和浮动盈亏。SL 矩形锚点 1 取入场价与开仓时间,锚点 2 落在 SL 价位并横向拉到当日 23:59,每天自动延展覆盖风险区;TP 矩形同理只把第二锚点换到 TP 价位,这样一眼能看出价格逼近哪条线。 直接循环 PositionsTotal() 抓数据会踩两个坑:EA 分不清当前循环的是哪个具体仓位,且不过滤品种时会把其他符号的仓位也画到本图。加一个输入参数让用户指定仓位索引,并在取数前比对图表交易品种,才能保住可视化的准确性。 下面这段代码在 OnTick 里遍历未平仓位,用 PositionGetDouble / PositionGetInteger 把开场价、SL、TP、开仓时间读出来,正式画对象前先 Print 到终端核对。若 SL 或 TP 不大于 0 就跳过对应矩形创建,避免无效锚点把图搞乱。 历史部分靠 HistorySelect(date1, date2) 拉取指定区间成交,用 HistoryDealGetTicket(i) 逐笔区分开仓与平仓记录,再把 deal_open_price、deal_close_price、deal_sl、deal_tp、deal_profit 等塞进矩形和标签。外汇与贵金属杠杆高,历史可视化仅辅助复盘,不代表后续胜率。

MQL5 / C++
class=class="str">"cmt">// Variables to store position details
class="type">class="kw">double open_price;          class=class="str">"cmt">// Variable to store the entry price of the position
class="type">class="kw">double stop_loss;           class=class="str">"cmt">// Variable to store the Stop Loss level of the position
class="type">class="kw">double take_profit;         class=class="str">"cmt">// Variable to store the Take Profit level of the position
class="type">class="kw">datetime position_open_time; class=class="str">"cmt">// Variable to store the open time of the position
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">// Loop through all open positions
   for(class="type">int i = class="num">0; i < PositionsTotal(); i++)
     {
      class=class="str">"cmt">// Get the ticket number of the position at index &class="macro">#x27;i&class="macro">#x27;
      class="type">class="kw">ulong ticket = PositionGetTicket(i);
      class=class="str">"cmt">// Retrieve and store the entry price of the position
      open_price = PositionGetDouble(POSITION_PRICE_OPEN);
      class=class="str">"cmt">// Retrieve and store the Stop Loss level of the position
      stop_loss = PositionGetDouble(POSITION_SL);
      class=class="str">"cmt">// Retrieve and store the Take Profit level of the position
      take_profit = PositionGetDouble(POSITION_TP);
      class=class="str">"cmt">// Retrieve and store the open time of the position
      position_open_time = (class="type">int)PositionGetInteger(POSITION_TIME);
      class=class="str">"cmt">// Print the retrieved values for debugging or verification

常见问题

对象是挂在图表上的可视元素(如趋势线、文字、箭头),不占程序内存变量,而是存在图表坐标里,刷新或重绘都可能丢失,需用代码显式创建和管理。
用ObjectCreate建趋势线对象,设好两个时间/价格锚点,再调颜色线宽;跑起来后盘面会多出一条线,方便回看进出场逻辑。
小布能直接读取当前品种页已画的图表对象并标注含义,省去你逐行翻代码核对锚点,打开对应品种页即可看到诊断。
多半是锚点用的相对坐标或没设OBJPROP_SELECTABLE=false,图表重绘时对象被清掉;用具体时间和价格钉死锚点才能固定。
遍历持仓与历史,用ObjectCreate按每笔开平时间价位点画箭头或线段,并写文字备注;这样盘面直接显示盈亏位,不用切终端窗口。