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

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

第 2/3 篇

◍ 抓当前图表那张持仓的单子

想在 MT5 里只盯当前图表品种的第一张持仓,核心是先拿 ChartID() 锁定图表,再用 PositionGetString(POSITION_SYMBOL) 跟 ChartSymbol(chart_id) 做比对,避免把别的品种持仓误读进来。 下面这段逻辑用 position_index 输入参数(默认 0,索引从 0 起算)指定取第几张单,循环里用 PositionGetTicket(i) 拿每张单的 ticket,再判断 ticket 是否等于 PositionGetTicket(position_index) 且品种对得上。 匹配成功后,用 PositionGetDouble 取开仓价、SL、TP,用 PositionGetInteger(POSITION_TIME) 强转 int 拿开仓时间,最后 Print 出来。你在策略测试器里跑 EA,终端面板的 Experts 标签会按 index 0 打出类似『Open Price index 0: 1.08562 / SL index 0: 1.08310』的四行记录,可直接核对抓取是否准确。 外汇与贵金属杠杆高,持仓抓取仅作监控用途,任何据此调整仓位的动作都伴随本金回撤可能。

MQL5 / C++
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">// Define the position index for the first position
input class="type">int position_index  = class="num">0; class=class="str">"cmt">// POSITION INDEX(Index starts from class="num">0)
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();
class="type">void OnTick()
  {
  for(class="type">int i = class="num">0; i < PositionsTotal(); i++)
    {
      class="type">class="kw">ulong ticket = PositionGetTicket(i);
      if(PositionGetInteger(POSITION_TICKET) == PositionGetTicket(position_index) && PositionGetString(POSITION_SYMBOL) == ChartSymbol(chart_id))
        {
         open_price = PositionGetDouble(POSITION_PRICE_OPEN);
         stop_loss = PositionGetDouble(POSITION_SL);
         take_profit = PositionGetDouble(POSITION_TP);
         position_open_time = (class="type">int)PositionGetInteger(POSITION_TIME);
         Print("Open Price index ",i,": ",open_price);
         Print("SL index ",i,": ",stop_loss);
         Print("TP index ",i,": ",take_profit);
         Print("Open time index ",i,": ",position_open_time);
        }
    }
  }

「抓持仓要素并画风险收益带」

在 MT5 的 EA 里想可视化某笔持仓的止损盈利区,第一步是把仓位的关键字段抓出来。下面这段代码定义了开仓价、SL、TP、开仓时间四个变量,并用 input 把 position_index 默认设为 1(注意索引从 0 起算,所以实际抓的是第二笔持仓),同时用 ChartID() 锁定当前图表、用 "23:59" 字符串预留一个平仓 zone 时间点。 循环里用 PositionsTotal() 遍历所有持仓,通过 PositionGetTicket(position_index) 比对票据号,再叠加 ChartSymbol(chart_id) 确认品种一致才取值。open_price、stop_loss、take_profit 分别来自 POSITION_PRICE_OPEN / POSITION_SL / POSITION_TP,position_open_time 则把 POSITION_TIME 强转 int。 每抓一笔就用 Print 把四个值打到日志,你直接在 MT5 终端的 Experts 标签里就能看到类似 "Open Price index 1: 1.08432" 的输出,据此判断 EA 有没有认错仓位。外汇与贵金属杠杆高,SL/TP 区域仅作概率参考,实盘须自担风险。 别把索引当摆设 position_index 设成 1 却只有 0 号持仓时,PositionGetTicket(1) 会返回 0,整个 if 不进,画面上一根 zone 都不会画。开 EA 前先确认持仓数 ≥ 2,或改成 0 测第一笔。

MQL5 / C++
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">// Define the position index for the first position
input class="type">int position_index  = class="num">1;       class=class="str">"cmt">// POSITION INDEX(Index starts from class="num">0)
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();           class=class="str">"cmt">// Store the ID of the current chart
class="type">class="kw">string time = "class="num">23:class="num">59";               class=class="str">"cmt">// Define a specific time as a class="type">class="kw">string
class=class="str">"cmt">// Define the class="type">color for the losing zone
input class="type">color sl_zonez_color  = clrPink; class=class="str">"cmt">// Choose a class="type">color for Losing Zone
class=class="str">"cmt">// Define the class="type">color for the winning zone
input class="type">color tp_zonez_color  = clrSpringGreen; class=class="str">"cmt">// Choose a class="type">color for Winning Zone
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">// Convert the class="type">class="kw">string time to class="type">class="kw">datetime
   class="type">class="kw">datetime close_zone = StringToTime(time);
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">// Check if the position matches the specified index and symbol of the current chart
      if(PositionGetInteger(POSITION_TICKET) == PositionGetTicket(position_index) && PositionGetString(POSITION_SYMBOL) == ChartSymbol(chart_id))
        {
         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
         Print("Open Price index ",i,": ",open_price);
         Print("SL index ",i,": ",stop_loss);
         Print("TP index ",i,": ",take_profit);
         Print("Open time index ",i,": ",position_open_time);
         class=class="str">"cmt">// Create a rectangle to represent the Stop Loss(SL) zone on the chart

用矩形和趋势线把持仓区间画出来

在 MT5 里给已开仓位标视觉区间,最直接的方法是 OBJ_RECTANGLE 矩形加 OBJ_TREND 趋势线。下面这段代码在仓位有 SL/TP 时分别画「SL Zone」「TP zone」两块矩形,无对应止损止盈则跳过该矩形创建。 矩形属性里 OBJPROP_BACK 设成 true 很关键,否则色块会盖住 K 线导致无法看价格行为。OBJPROP_FILL 接受的是颜色值而非布尔,填 sl_zonez_color 即可让区块半透明着色,边框宽度 1 够用不抢视线。 趋势线从 position_open_time 的 open_price 拉到 TimeCurrent() 的实时 ask,等于把建仓点到现在的市价连成一条通道。外汇和贵金属杠杆高,这种可视化仅辅助读盘,不代表任何方向确定性,价格可能随时反向击穿区块。 复制时确认 chart_id 已正确获取(通常用 0 指代当前图表),close_zone 需是时间类型变量,否则矩形右边界会渲染异常。

MQL5 / C++
ObjectCreate(chart_id, "SL Zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, stop_loss);
class=class="str">"cmt">// Create a rectangle to represent the Take Profit(TP) zone on the chart
ObjectCreate(chart_id, "TP zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, take_profit);
class=class="str">"cmt">// Set properties for the SL zone rectangle
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_COLOR, sl_zonez_color); class=class="str">"cmt">// Set class="type">color to the selected SL zone class="type">color
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_STYLE, STYLE_SOLID);    class=class="str">"cmt">// Set style to solid
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_WIDTH, class="num">1);              class=class="str">"cmt">// Set the width of the rectangle border
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_FILL, sl_zonez_color);  class=class="str">"cmt">// Fill the rectangle with the selected SL zone class="type">color
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_BACK, true);            class=class="str">"cmt">// Set the rectangle to appear behind the chart objects
class=class="str">"cmt">// Set properties for the TP zone rectangle
ObjectSetInteger(chart_id, "TP zone", OBJPROP_COLOR, tp_zonez_color); class=class="str">"cmt">// Set class="type">color to the selected TP zone class="type">color
ObjectSetInteger(chart_id, "TP zone", OBJPROP_STYLE, STYLE_SOLID);    class=class="str">"cmt">// Set style to solid
ObjectSetInteger(chart_id, "TP zone", OBJPROP_WIDTH, class="num">1);              class=class="str">"cmt">// Set the width of the rectangle border
ObjectSetInteger(chart_id, "TP zone", OBJPROP_FILL, tp_zonez_color);  class=class="str">"cmt">// Fill the rectangle with the selected TP zone class="type">color
ObjectSetInteger(chart_id, "TP zone", OBJPROP_BACK, true);            class=class="str">"cmt">// Set the rectangle to appear behind the chart objects
}
   }
}
if(stop_loss > class="num">0)
  {
class=class="str">"cmt">// Create a rectangle to represent the Stop Loss(SL) zone on the chart
  ObjectCreate(chart_id, "SL Zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, stop_loss);
  }
if(take_profit > class="num">0)
  {
class=class="str">"cmt">// Create a rectangle to represent the Take Profit(TP) zone on the chart
  ObjectCreate(chart_id, "TP zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, take_profit);
  }
class=class="str">"cmt">// Get the current ask price
class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
class=class="str">"cmt">// Create a trend line object on the chart from the position&class="macro">#x27;s open time and price to the current time and ask price
ObjectCreate(chart_id, "Trend Line", OBJ_TREND, class="num">0, position_open_time, open_price, TimeCurrent(), ask);
class=class="str">"cmt">// Set the class="type">color of the trend line

◍ 用代码把持仓区间画成可视区块

在 MT5 图表上把持仓的盈亏区间直接画出来,比盯着终端数字更直观。下面这段逻辑先给一条名为 Trend Line 的趋势线设了黄色、虚线、2 像素宽,再声明了开仓价、止损、止盈和时间等变量,方便后续定位。 position_index 输入项默认填 1,但注释里写明索引从 0 起算,也就是说默认抓的是账户里第二笔持仓;若你想盯第一笔,得改成 0。sl_zonez_color 用 clrPink 标亏损区,tp_zonez_color 用 clrSpringGreen 标盈利区,line_zonez_color 用 clrYellow 画线,都在 input 里可调。 OnTick 里先取当前卖价 ask,再把字符串 "23:59" 转成 datetime 作为区间截止时间。随后用 for 循环扫 PositionsTotal() 笔持仓,靠 PositionGetTicket(position_index) 匹配指定索引,且要求 POSITION_SYMBOL 等于当前图表品种才继续取数。 外汇与贵金属杠杆高,这类可视化脚本只做辅助参考,信号本身不预示走向,实际成交受滑点与点差影响可能偏离画线区间。

MQL5 / C++
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_COLOR, clrYellow);
class=class="str">"cmt">// Set the style of the trend line to dashed
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_STYLE, STYLE_DASH);
class=class="str">"cmt">// Set the width of the trend line
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_WIDTH, class="num">2);
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">// Define the position index for the first position
input class="type">int position_index  = class="num">1; class=class="str">"cmt">// POSITION INDEX(Index starts from class="num">0)
class=class="str">"cmt">// Get the ID of the current chart
class="type">long chart_id = ChartID();   class=class="str">"cmt">// Store the ID of the current chart
class="type">class="kw">string time = "class="num">23:class="num">59";       class=class="str">"cmt">// Define a specific time as a class="type">class="kw">string
class=class="str">"cmt">// Define the class="type">color for the losing zone
input class="type">color sl_zonez_color   = clrPink; class=class="str">"cmt">// Choose a class="type">color for Losing Zone
class=class="str">"cmt">// Define the class="type">color for the winning zone
input class="type">color tp_zonez_color   = clrSpringGreen; class=class="str">"cmt">// Choose a class="type">color for Winning Zone
class=class="str">"cmt">// Define the class="type">color for the trend line
input class="type">color line_zonez_color = clrYellow; class=class="str">"cmt">// Choose a class="type">color for the line
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
  class=class="str">"cmt">// Get the current ask price
   class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
  class=class="str">"cmt">// Convert the class="type">class="kw">string time to class="type">class="kw">datetime
   class="type">class="kw">datetime close_zone = StringToTime(time);
  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">// Check if the position matches the specified index and symbol of the current chart
      if(PositionGetInteger(POSITION_TICKET) == PositionGetTicket(position_index) && PositionGetString(POSITION_SYMBOL) == ChartSymbol(chart_id))
        {
         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);

「把止损止盈画成图表上的实体区」

持仓一开出来,先把开仓时间抓到手:用 PositionGetInteger(POSITION_TIME) 强转成 int 存进 position_open_time,后面画对象全靠这个锚点。 如果 stop_loss 大于 0,就调 ObjectCreate 画一个名为 "SL Zone" 的 OBJ_RECTANGLE,时间轴从 position_open_time 拉到 close_zone,价格轴从 open_price 到 stop_loss;take_profit 同理画 "TP zone",边界到 take_profit。这两块矩形就是肉眼可见的止损 / 止盈触发带。 外观全靠 ObjectSetInteger 堆出来:颜色用 sl_zonez_color / tp_zonez_color,线型 STYLE_SOLID,边框宽度 1,OBJPROP_FILL 填同色,OBJPROP_BACK 设 true 让矩形沉到 K 线后面不挡视野。外汇与贵金属杠杆高,SL/TP 区只作空间参考,实际滑点可能让成交偏离该带。 最后一条 OBJ_TREND 从开仓点连到 TimeCurrent() 与 ask 价,命名 "Trend Line",把持仓成本到现价的斜率直接晒在图上,方便你一眼判断浮盈浮亏的倾斜方向。

MQL5 / C++
position_open_time = (class="type">int)PositionGetInteger(POSITION_TIME);
if(stop_loss > class="num">0)
  {
  ObjectCreate(chart_id, "SL Zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, stop_loss);
  }
if(take_profit > class="num">0)
  {
  ObjectCreate(chart_id, "TP zone", OBJ_RECTANGLE, class="num">0, position_open_time, open_price, close_zone, take_profit);
  }
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_COLOR, sl_zonez_color);
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_WIDTH, class="num">1);
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_FILL, sl_zonez_color);
ObjectSetInteger(chart_id, "SL Zone", OBJPROP_BACK, true);
ObjectSetInteger(chart_id, "TP zone", OBJPROP_COLOR, tp_zonez_color);
ObjectSetInteger(chart_id, "TP zone", OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(chart_id, "TP zone", OBJPROP_WIDTH, class="num">1);
ObjectSetInteger(chart_id, "TP zone", OBJPROP_FILL, tp_zonez_color);
ObjectSetInteger(chart_id, "TP zone", OBJPROP_BACK, true);
ObjectCreate(chart_id, "Trend Line", OBJ_TREND, class="num">0, position_open_time, open_price, TimeCurrent(), ask);

把持仓盈亏钉在趋势线上

给图表上的趋势线做完外观设定后,下一步是把当前持仓的浮动盈亏直接标在图里,省得切仓位窗口看数字。下面这段逻辑先取 POSITION_PROFIT,再按正负拼成带符号的字符串,最后用 OBJ_TEXT 画到 ask 价位置。 盈利为正或零时,DoubleToString 保留 2 位小数,StringFormat 套上 +$ 前缀;亏损则先用 MathAbs 转正数再格式化,前缀换成 -$。颜色上,正利润用 clrMediumBlue、负利润用 clrRed,一眼能分出方向。 外汇和贵金属杠杆高,浮盈浮亏随时翻转,这种图上标注只作实时参考,不代表平仓结果。开 MT5 把这段接进 EA 的 OnTick,就能在盯盘时直接看到线旁的金额。

MQL5 / C++
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_COLOR, line_zonez_color);
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(chart_id, "Trend Line", OBJPROP_WIDTH, class="num">2);
class=class="str">"cmt">// Calculate the profit of the current position
class="type">class="kw">double profit = PositionGetDouble(POSITION_PROFIT);
class=class="str">"cmt">// Variables to store the formatted profit text
class="type">class="kw">string curent_profits;
class="type">class="kw">string profit_to_string;
class=class="str">"cmt">// Check if the profit is positive or zero
if(profit >= class="num">0)
  {
   class=class="str">"cmt">// Convert the profit to a class="type">class="kw">string with class="num">2 decimal places
   profit_to_string = DoubleToString(profit, class="num">2);
   class=class="str">"cmt">// Format the profit as a positive amount with a &class="macro">#x27;+&class="macro">#x27; sign
   curent_profits = StringFormat("+$%s", profit_to_string);
   }
class=class="str">"cmt">// Check if the profit is negative
else
   if(profit < class="num">0)
     {
      class=class="str">"cmt">// Convert the negative profit to a positive number
      class="type">class="kw">double profit_to_positive = MathAbs(profit);
      class=class="str">"cmt">// Convert the positive profit to a class="type">class="kw">string with class="num">2 decimal places
      profit_to_string = DoubleToString(profit_to_positive, class="num">2);
      class=class="str">"cmt">// Format the profit as a negative amount with a &class="macro">#x27;-&class="macro">#x27; sign
      curent_profits = StringFormat("-$%s", profit_to_string);
      }
class=class="str">"cmt">// Create a text label on the chart to display the current profit
class="type">class="kw">string text_object_name = "Profit";
ObjectCreate(chart_id, text_object_name, OBJ_TEXT, class="num">0, TimeCurrent(), ask);
ObjectSetString(chart_id, text_object_name, OBJPROP_TEXT, curent_profits);
class=class="str">"cmt">// Set the class="type">color of the profit text based on whether the profit is positive or negative
if(profit > class="num">0)
  {
   ObjectSetInteger(chart_id, text_object_name, OBJPROP_COLOR, clrMediumBlue); class=class="str">"cmt">// Positive profit in blue
   }
else
   if(profit < class="num">0)
     {
      ObjectSetInteger(chart_id, text_object_name, OBJPROP_COLOR, clrRed); class=class="str">"cmt">// Negative profit in red
      }

常见问题

用持仓遍历接口按品种名过滤,匹配到 symbol 相同且持仓魔术码一致的就取出 ticket,只处理这一张。
用矩形对象把开仓到止损画为风险区、开仓到止盈画为收益区,颜色分开,挂上持仓 ticket 做绑定。
可以,小布能读取当前持仓要素并在图表生成风险收益带与止盈止损实体区,打开对应品种页即可直接看。
在趋势线末端用文本对象贴入实时 profit 数值,每 tick 刷新,避免切窗口算账。
对象没设时间为0且价格用错点数换算,需按报价精度转点值并用整图锚定才跨周期不变形。