MQL5 Cookbook: 获取仓位属性·进阶篇
持仓属性抓取与异常弹窗处理
这段逻辑干两件事:把当前持仓的关键字段拼进消息框,以及在没有持仓或选仓失败时给出带错误码的警告。外汇和贵金属持仓的库存费、浮动利润随时在变,用 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(具体数值随券商而定)。
"库存费 : "+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)。外汇和贵金属杠杆高,弹窗数据仅用于核对,不代表任何方向判断。
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-- 退回循环重跑一次。这种交互在批量巡检多单时很有用——肉眼核对十几个持仓前先弹窗过一遍。 外汇与贵金属杠杆高,弹窗里的库存费和手续费会随隔日持仓累积,实际成本可能比预览时偏高,下单前自己再核一遍终端数据。
"当前价位: " +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 必须是当前图表或全局池里真实存在的字符串,否则即使重试也会反复进这个分支。 外汇与贵金属杠杆高,这类选择失败若不被拦截,可能让脚本在错误上下文里发出订单——实盘前务必在策略测试器用无持仓品种跑一遍该路径。
MessageBox("错误 ("+IntegerToString(err)+") 当选择仓位 ("+pos_symbol+") !\n\n"+ "也许该交易品种没有持仓. 如果不是这种情况,请重试.", "错误", MB_ICONWARNING);
「画得少,看得清」
对话框里那三个按钮决定了脚本的走向:点“重试”会把循环计数器归零并刷新当前交易品种仓位属性,点“继续”直接跳到下一品种,“取消”则终止整个流程。仓位属性上方第一行同时给出持仓总数与当前计数器编号,扫一眼就知道跑到第几个了。 附件里的 printpositionproperties.mq5 约 16.2 KB,需在 MetaQuotes 语言编辑器编译后跑。开 MT5 加载脚本,对 EURUSD 这类品种实测一下三个按钮的切换逻辑,比看说明来得直接。 外汇与贵金属杠杆高、滑点猛,脚本只负责把仓位属性摆到面板上,不构成任何方向建议;真要挂实盘前先多在策略测试器里绕几圈。