MQL5 简介(第 9 部分):理解和使用 MQL5 中的对象(基础篇)
「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 区和入场标注在乱序行情里仍一眼可辨。
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字面量,写错一位小数标的位置就偏出屏。
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 等塞进矩形和标签。外汇与贵金属杠杆高,历史可视化仅辅助复盘,不代表后续胜率。
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