MQL5 Cookbook: 获取仓位属性·进阶篇
📘

MQL5 Cookbook: 获取仓位属性·进阶篇

第 2/2 篇

持仓属性抓取与异常弹窗处理

这段逻辑干两件事:把当前持仓的关键字段拼进消息框,以及在没有持仓或选仓失败时给出带错误码的警告。外汇和贵金属持仓的库存费、浮动利润随时在变,用 DoubleToString(...,2) 保留两位小数能避免 MT5 弹窗里出现一长串浮点噪声。 代码里 MessageBox 的 MB_ICONASTERISK 与 MB_ICONWARNING 区分了「信息展示」和「出错提示」两种场景;后者会调用 GetLastError() 拿到具体编号,比如返回 4756(持仓选择失败)时提示可能是该品种无持仓。 GetPositionProperties() 这个函数用 PositionGetString / Integer / Double 三类接口分别取符号、魔术码、开仓价、当前价、SL/TP、成交量与佣金。实际验证时,开 MT5 策略测试器挂一个 XAUUSD 0.1 手买单,跑完这段代码能在弹窗看到 pos_volume 精确到 0.1、pos_commission 通常不为 0(具体数值随券商而定)。

MQL5 / C++
              "库存费            : "+DoubleToString(pos_swap,class="num">2)+"\n"+
              "利润            : "+DoubleToString(pos_profit,class="num">2)+"\n"+
              "时间            : "+TimeToString(pos_time)+"\n"+
              "编号    : "+IntegerToString(pos_id)+"",
              class=class="str">"cmt">//---
              "消息框",MB_ICONASTERISK);
              class=class="str">"cmt">//---
              class="kw">return;
              }
      class=class="str">"cmt">// 如果没有持仓或者出错,则报告
      else
        {
         err=GetLastError(); class=class="str">"cmt">// 获取最后注册的错误编号
         class=class="str">"cmt">//---
         if(err>class="num">0) class=class="str">"cmt">// 如果有错误
           {
            class=class="str">"cmt">// 打印相关信息
            MessageBox("当选择("+_Symbol+")仓位时出错 ("+IntegerToString(err)+")  !\n\n"+
                        "也许该交易品种没有持仓. 如果不是这种情况,请重试.",
                        "错误",
                        MB_ICONWARNING);
            class=class="str">"cmt">//---
            class="kw">return; class=class="str">"cmt">// 退出函数
           }
        }
      class=class="str">"cmt">//---
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 获取交易品种属性                                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void GetPositionProperties()
  {
   pos_symbol      =PositionGetString(POSITION_SYMBOL);
   pos_comment     =PositionGetString(POSITION_COMMENT);
   pos_magic       =PositionGetInteger(POSITION_MAGIC);
   pos_price       =PositionGetDouble(POSITION_PRICE_OPEN);
   pos_cprice      =PositionGetDouble(POSITION_PRICE_CURRENT);
   pos_sl          =PositionGetDouble(POSITION_SL);
   pos_tp          =PositionGetDouble(POSITION_TP);
   pos_type        =(class="type">ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
   pos_volume      =PositionGetDouble(POSITION_VOLUME);
   pos_commission  =PositionGetDouble(POSITION_COMMISSION);

「逐仓遍历与属性弹窗的实现细节」

在 MT5 的 EA 或脚本里,想看清当前账户每一笔持仓的底细,核心是先拿 PositionsTotal() 得到终端持仓总数,再用 for 循环从 0 到 pos_total-1 逐个索引。每次循环先用 PositionGetSymbol(i) 取出第 i 个仓位的交易品种名,再用 SymbolInfoInteger(pos_symbol, SYMBOL_DIGITS) 拿该品种报价小数位,后续格式化价格才不会错位。 拿到位后必须调 PositionSelect(pos_symbol) 把该仓设为“当前仓”,之后 PositionGetDouble / PositionGetInteger 才能读到正确属性。代码里把持仓的 swap、profit、开仓时间、仓位 ID 分别存进变量,开仓时间用 (datetime) 强转,ID 用 POSITION_IDENTIFIER 取,都是实盘排查滑点和对冲逻辑时常盯的字段。 仓位类型只有 0 和 1 两种枚举值,对应“买入”和“卖出”,用 PositionTypeToString() 转成中文串方便对话框展示。循环内每读一个仓就 ResetLastError() 清一次错误码,避免上一次失败污染本次判断。 最后用 MessageBox 把全部/当前序号、品种、注释、幻数、建仓价拼成字符串弹窗。这个做法在调试 EA 时很直接:你跑一个脚本就能在弹窗里看到第 3/5 个仓的黄金 XAUUSD 建仓价精确到小数点后 2 位(digits 由品种决定,黄金通常 2,外汇主流 4~5)。外汇和贵金属杠杆高,弹窗数据仅用于核对,不代表任何方向判断。

MQL5 / C++
  pos_swap        =PositionGetDouble(POSITION_SWAP);
  pos_profit      =PositionGetDouble(POSITION_PROFIT);
  pos_time        =(class="type">class="kw">datetime)PositionGetInteger(POSITION_TIME);
  pos_id          =PositionGetInteger(POSITION_IDENTIFIER);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 把仓位类型转换为字符串                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string PositionTypeToString(class="type">int position_type)
  {
   class="type">class="kw">string str="";
class=class="str">"cmt">//---
   if(position_type==class="num">0) { str="买入";  }
   if(position_type==class="num">1) { str="卖出"; }
class=class="str">"cmt">//---
   class="kw">return(str);
  }
class=class="str">"cmt">//---
       class="type">int digits=class="num">0; class=class="str">"cmt">// 小数位数
       class="type">int mb_res=-class="num">1; class=class="str">"cmt">// 对话框中选择选项的变量
       class="type">int pos_total=PositionsTotal(); class=class="str">"cmt">// 终端中的持仓个数
       class=class="str">"cmt">//---
       class=class="str">"cmt">// 在循环中挨个查看所有仓位的属性
       for(class="type">int i=class="num">0; i<pos_total; i++)
         {
          ResetLastError(); class=class="str">"cmt">// 重设最后的错误
          class=class="str">"cmt">//---
          pos_symbol=PositionGetSymbol(i); class=class="str">"cmt">// 读取交易品种名称
          digits=(class="type">int)SymbolInfoInteger(pos_symbol,SYMBOL_DIGITS); class=class="str">"cmt">// 取得价格的小数位数
          class=class="str">"cmt">//---
          class=class="str">"cmt">// 如果这个交易品种有持仓,那么...
          if(PositionSelect(pos_symbol))
            {
             class=class="str">"cmt">// ...获取它的属性
             GetPositionProperties();
             class=class="str">"cmt">//---
             class=class="str">"cmt">// 打开一个对话框显示所有获得的仓位属性
             mb_res=MessageBox("全部/当前持仓: "+IntegerToString(pos_total)+"/"+IntegerToString(i+class="num">1)+"\n"+
                               "---------------------------------\n"+
                               "交易品种: "        +pos_symbol+"\n"+
                               "注释: "            +pos_comment+"\n"+
                               "幻数: "    +IntegerToString(pos_magic)+"\n"+
                               "建仓价位: "        +DoubleToString(pos_price,digits)+"\n"+

◍ 把持仓明细塞进弹窗

这段脚本把当前持仓的关键字段拼成一段字符串,直接丢进 MT5 的消息框里展示,比去交易面板逐个看省事得多。 拼接时用 DoubleToString 控制小数位:价格类用 digits(品种精度),交易量、手续费、库存费、利润统一留 2 位。PositionTypeToString 把持仓类型转成可读文字,TimeToString 把开仓时间格式化,最后用 IntegerToString 输出持仓编号。 消息框带了 MB_CANCELTRYCONTINUE 组合,用户点「取消」脚本就 Print 终止信息并 return;点「重试」则 i-- 退回循环重跑一次。这种交互在批量巡检多单时很有用——肉眼核对十几个持仓前先弹窗过一遍。 外汇与贵金属杠杆高,弹窗里的库存费和手续费会随隔日持仓累积,实际成本可能比预览时偏高,下单前自己再核一遍终端数据。

MQL5 / C++
              "当前价位: " +DoubleToString(pos_cprice,digits)+"\n"+
              "止损价位: "      +DoubleToString(pos_sl,digits)+"\n"+
              "获利价位: "   +DoubleToString(pos_tp,digits)+"\n"+
              "类型: "         +PositionTypeToString(pos_type)+"\n"+
              "交易量: "        +DoubleToString(pos_volume,class="num">2)+"\n"+
              "手续费: "     +DoubleToString(pos_commission,class="num">2)+"\n"+
              "库存费: "         +DoubleToString(pos_swap,class="num">2)+"\n"+
              "利润: "        +DoubleToString(pos_profit,class="num">2)+"\n"+
              "时间: "         +TimeToString(pos_time)+"\n"+
              "编号: "     +IntegerToString(pos_id)+"",
              class=class="str">"cmt">//---
              "消息框",MB_CANCELTRYCONTINUE|MB_ICONASTERISK);
              class=class="str">"cmt">//---
              if(mb_res==IDCANCEL) class=class="str">"cmt">// 如果您点击了取消或者关闭
                 { Print("程序 ("+SCRIPT_NAME+") 被用户终止!"); class="kw">return; } class=class="str">"cmt">// 退出函数
              class=class="str">"cmt">//---
              class=class="str">"cmt">// 如果您点击了重试  
              if(mb_res==IDTRYAGAIN) { i--; } class=class="str">"cmt">// 重设计数器并重试
            }
            else class=class="str">"cmt">// 如果没有持仓或者出错,则报告
             {
              err=GetLastError(); class=class="str">"cmt">// 获取最后注册的错误编号
              class=class="str">"cmt">//---
              if(err>class="num">0) class=class="str">"cmt">// 如果有错误
               {
               class=class="str">"cmt">// 打印相关信息

持仓选择失败时的告警弹窗

在 MT5 的仓位遍历逻辑里,若按交易品种筛选持仓时返回了非零错误码,说明本次 Select 操作未拿到有效持仓句柄。此时直接弹窗比静默失败更安全,能避免后续对该 pos_symbol 做平仓或加仓时误伤其他品种。 下面这段 MQL5 片段就是典型的防御式提示:把错误码和品种名拼进 MessageBox,用 MB_ICONWARNING 给出黄色感叹号。你在 EA 里复制时,注意 pos_symbol 必须是当前图表或全局池里真实存在的字符串,否则即使重试也会反复进这个分支。 外汇与贵金属杠杆高,这类选择失败若不被拦截,可能让脚本在错误上下文里发出订单——实盘前务必在策略测试器用无持仓品种跑一遍该路径。

MQL5 / C++
MessageBox("错误 ("+IntegerToString(err)+") 当选择仓位 ("+pos_symbol+") !\n\n"+
              "也许该交易品种没有持仓. 如果不是这种情况,请重试.",
              "错误",
              MB_ICONWARNING);

「画得少,看得清」

对话框里那三个按钮决定了脚本的走向:点“重试”会把循环计数器归零并刷新当前交易品种仓位属性,点“继续”直接跳到下一品种,“取消”则终止整个流程。仓位属性上方第一行同时给出持仓总数与当前计数器编号,扫一眼就知道跑到第几个了。 附件里的 printpositionproperties.mq5 约 16.2 KB,需在 MetaQuotes 语言编辑器编译后跑。开 MT5 加载脚本,对 EURUSD 这类品种实测一下三个按钮的切换逻辑,比看说明来得直接。 外汇与贵金属杠杆高、滑点猛,脚本只负责把仓位属性摆到面板上,不构成任何方向建议;真要挂实盘前先多在策略测试器里绕几圈。

常见问题

用仓位总数函数拿持仓数量,循环里用按索引取仓位ticket,再用对应属性函数读开仓价、手数等;注意每次循环前重新获取总数避免遗漏。
多是选中持仓失败或属性函数返回了无效值;弹窗前先判断ticket是否有效,失败就跳告警而不是继续填数据。
可以,小布能直接读取账户持仓并生成可视化明细,省去手动抓取属性和做界面的重复劳动。
贵金属杠杆和跳空风险更高,读持仓别只看浮亏,要结合点值和保证金;所有结论都只是概率倾向,不是确定性。
至少带上失败时的循环索引、期望ticket和错误码;这样后续对照日志能快速定位是遍历越界还是ticket失效。