
MQL5 Cookbook: 获取仓位属性
简介
前一篇文章:"MQL5 Cookbook: 使用不同的打印模式" 向我们展示了如何快速写一个脚本来使用三种不同模式打印所需的信息,现在让我们创建一个脚本来向用户显示所有的仓位属性。
我们需要允许用户从脚本的外部参数中选择对应的选项,如下实现:或者只取得一个(当前)交易品种的仓位属性,或者一个接一个地遍历所有交易品种的所有持仓。这一次,我们会在对话框中查看所需的信息,这非常方便,你们中的一些人可能会觉得这种方法更为有用。
写脚本
程序的开头部分和前一篇文章多少类似 (参见下面的代码)。我们从程序的属性开始,它们之后是使用#define的预定义代码,我们可以使用MQL5InfoString()函数并指定MQL5_PROGRAM_NAME常量为参数,赋值给SCRIPT_NAME变量来为脚本命名,更多有关MQL5InfoString() 函数所有可能值的信息可以在MQL5参考中找到。
我们继续看模式的枚举,如果您为每个标识符写了注释,这些注释的文本将在外部参数的下拉列表中显示。我们将实现两个选项:
- 当前交易品种 - 只显示当前交易品种的仓位属性,还有
- 所有交易品种 - 显示所有交易品种的仓位信息。
这里将会有一个唯一的外部参数(mode)用于选择对应的模式。外部参数之后的注释也会在外部参数窗口上显示出来,这使我们能够创建更有含义的参数名称,同时,短一点的变量名在代码中使用更加方便。
#property copyright "Copyright 2012, http://tol64.blogspot.com" #property link "http://tol64.blogspot.com" #property description "email: hello.tol64@gmail.com" #property version "1.0" #property script_show_inputs //--- #define SCRIPT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // 脚本名称 //--- // 模式枚举 enum ENUM_SYMBOLS_MODE { CURRENT_SYMBOL =0, // 当前交易品种 ALL_SYMBOLS =1 // 所有交易品种 }; //--- // 输入参数 input ENUM_SYMBOLS_MODE mode=CURRENT_SYMBOL; // 模式
代码之后是全局变量,为了使全局变量能够在脚本的任何部分都可以访问,它们应该被放置在函数之外(通常在程序的最前面)。
// 全局变量 long pos_magic=0; // 幻数 string pos_symbol=""; // 交易品种 string pos_comment=""; // 注释 double pos_swap=0.0; // 库存费 double pos_commission=0.0; // 手续费 double pos_price=0.0; // 仓位的当前价格 double pos_cprice=0.0; // 仓位的当前价格 double pos_profit=0.0; // 仓位的利润/亏损 double pos_volume=0.0; // 仓位交易量 double pos_sl=0.0; // 仓位止损价位 double pos_tp=0.0; // 仓位获利价位 datetime pos_time=NULL; // 仓位建仓时间 long pos_id=0; // 仓位编号 ENUM_POSITION_TYPE pos_type=NULL; // 仓位类型 //---
在程序的主函数中,我们只调用一个用户定义的函数,PrintPositionProperties(), 它将进行所有所需的操作:
//+------------------------------------------------------------------+ //| 主函数 | //+------------------------------------------------------------------+ void OnStart() { PrintPositionProperties(); }
现在让我们分步看一下用户定义的PrintPositionProperties() 函数的结构。我们要先为未来工作打好基础,它非常简单,实现上看起来如下:
//+------------------------------------------------------------------+ //| 打开对话框并显示交易品种数据 | //+------------------------------------------------------------------+ void PrintPositionProperties() { int err=0; // 处理错误的变量 //--- // 如果您只需要获取当前交易品种的仓位属性 if(mode==CURRENT_SYMBOL) { } //--- // 如果您需要获取全部交易品种的仓位属性 if(mode==ALL_SYMBOLS) { } }
我们只有两个分支和一个局部变量err,它用于错误处理并且在函数的开始部分声明。现在我们需要写下每个选项的用例,让我们从第一个开始,也就是"如果您只需要获取当前交易品种的仓位信息"。
它非常简单,首先,我们需要检查当前交易品种是否有持仓,这可以通过MQL5中的PositionSelect()函数实现,其唯一参数为交易品种的名称。为了传入当前交易品种的名称,我们需要使用Symbol() 函数或者已经包含当前交易品种名称的预定义变量 _Symbol。如果此交易品种已有持仓,PositionSelect() 将返回一个正值, 如果没有持仓或者出错,则会返回负值。
以下提供了涵盖详细描述的第一个选项的代码:
//--- // 如果已有持仓,那么... if(PositionSelect(_Symbol)) { // ...获取它的属性 GetPositionProperties(); //--- // 打开对话框显示我们获得的全部数据 MessageBox("交易品种 : "+pos_symbol+"\n"+ "注释 : "+pos_comment+"\n"+ "幻数 : "+IntegerToString(pos_magic)+"\n"+ "建仓价位 : "+DoubleToString(pos_price,_Digits)+"\n"+ "当前价位 : "+DoubleToString(pos_cprice,_Digits)+"\n"+ "止损价位 : "+DoubleToString(pos_sl,_Digits)+"\n"+ "获利价位 : "+DoubleToString(pos_tp,_Digits)+"\n"+ "类型 : "+PositionTypeToString(pos_type)+"\n"+ "交易量 : "+DoubleToString(pos_volume,2)+"\n"+ "手续费 : "+DoubleToString(pos_commission,2)+"\n"+ "库存费 : "+DoubleToString(pos_swap,2)+"\n"+ "利润 : "+DoubleToString(pos_profit,2)+"\n"+ "时间 : "+TimeToString(pos_time)+"\n"+ "编号 : "+IntegerToString(pos_id)+"", //--- "消息框",MB_ICONASTERISK); //--- return; } // 如果没有持仓或者出错,则报告 else { err=GetLastError(); // 获取最后注册的错误编号 //--- if(err>0) // 如果有错误 { // 打印相关信息 MessageBox("当选择("+_Symbol+")仓位时出错 ("+IntegerToString(err)+") !\n\n"+ "也许该交易品种没有持仓. 如果不是这种情况,请重试.", "错误", MB_ICONWARNING); //--- return; // 退出函数 } } //---
在以上代码中,我们可以看到两个用户定义的函数-GetPositionProperties()和 PositionTypeToString()。 因为我们必须在整个程序的不同地方获取仓位属性,我们最好建立一个独立的函数以便减少代码量以及使代码有更好的可读性。以下是这个函数的代码。请确保查阅MQL5参考来了解GetPositionProperties()函数中所使用MQL5函数和标识符的更多信息。
//+------------------------------------------------------------------+ //| 获取交易品种属性 | //+------------------------------------------------------------------+ 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 =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); pos_volume =PositionGetDouble(POSITION_VOLUME); pos_commission =PositionGetDouble(POSITION_COMMISSION); pos_swap =PositionGetDouble(POSITION_SWAP); pos_profit =PositionGetDouble(POSITION_PROFIT); pos_time =(datetime)PositionGetInteger(POSITION_TIME); pos_id =PositionGetInteger(POSITION_IDENTIFIER); }
这个用户定义的PositionTypeToString()函数把返回的持仓类型从整数型转换为可读的字符串格式,其代码如下所示:
//+------------------------------------------------------------------+ //| 把仓位类型转换为字符串 | //+------------------------------------------------------------------+ string PositionTypeToString(int position_type) { string str=""; //--- if(position_type==0) { str="买入"; } if(position_type==1) { str="卖出"; } //--- return(str); }
这样,第一个选项,即我们仅查看当前交易品种仓位属性的代码已经完成了。如果您按照文章描述的所有步骤做下来,它甚至可以马上测试了。使用标准工具在MetaTrader 5中建立一个仓位,为了这个目标, 按下F9 键打开订单窗口,在那里你可以在仓位建立之前看到所有必要的选项来设置仓位属性:
图 1. MetaTrader 5客户终端中的订单窗口.
当所有属性设置完成,选择卖出或者买入,然后双击脚本或者把它拖到图表上来运行脚本,脚本窗口将会打开,模式参数的所需值 (当前交易品种)已经被默认填好了,点击“确定”按钮将会打开一个对话框,显示当前交易品种的所有仓位属性:
图 2. 显示当前交易品种仓位属性的对话框.
另一方面,假如当前交易品种没有持仓,会出现一个提醒对话框:
图 3. 提醒对话框.
一切都和计划中一样工作正常,和我们代码中所实现的一样。
让我们回顾一下那些选择查看所有交易品种仓位属性要用到的程序代码,代码和详细的注释如下:
//--- int digits=0; // 小数位数 int mb_res=-1; // 对话框中选择选项的变量 int pos_total=PositionsTotal(); // 终端中的持仓个数 //--- // 在循环中挨个查看所有仓位的属性 for(int i=0; i<pos_total; i++) { ResetLastError(); // 重设最后的错误 //--- pos_symbol=PositionGetSymbol(i); // 读取交易品种名称 digits=(int)SymbolInfoInteger(pos_symbol,SYMBOL_DIGITS); // 取得价格的小数位数 //--- // 如果这个交易品种有持仓,那么... if(PositionSelect(pos_symbol)) { // ...获取它的属性 GetPositionProperties(); //--- // 打开一个对话框显示所有获得的仓位属性 mb_res=MessageBox("全部/当前持仓: "+IntegerToString(pos_total)+"/"+IntegerToString(i+1)+"\n"+ "---------------------------------\n"+ "交易品种: " +pos_symbol+"\n"+ "注释: " +pos_comment+"\n"+ "幻数: " +IntegerToString(pos_magic)+"\n"+ "建仓价位: " +DoubleToString(pos_price,digits)+"\n"+ "当前价位: " +DoubleToString(pos_cprice,digits)+"\n"+ "止损价位: " +DoubleToString(pos_sl,digits)+"\n"+ "获利价位: " +DoubleToString(pos_tp,digits)+"\n"+ "类型: " +PositionTypeToString(pos_type)+"\n"+ "交易量: " +DoubleToString(pos_volume,2)+"\n"+ "手续费: " +DoubleToString(pos_commission,2)+"\n"+ "库存费: " +DoubleToString(pos_swap,2)+"\n"+ "利润: " +DoubleToString(pos_profit,2)+"\n"+ "时间: " +TimeToString(pos_time)+"\n"+ "编号: " +IntegerToString(pos_id)+"", //--- "消息框",MB_CANCELTRYCONTINUE|MB_ICONASTERISK); //--- if(mb_res==IDCANCEL) // 如果您点击了取消或者关闭 { Print("程序 ("+SCRIPT_NAME+") 被用户终止!"); return; } // 退出函数 //--- // 如果您点击了重试 if(mb_res==IDTRYAGAIN) { i--; } // 重设计数器并重试 } else // 如果没有持仓或者出错,则报告 { err=GetLastError(); // 获取最后注册的错误编号 //--- if(err>0) // 如果有错误 { // 打印相关信息 MessageBox("错误 ("+IntegerToString(err)+") 当选择仓位 ("+pos_symbol+") !\n\n"+ "也许该交易品种没有持仓. 如果不是这种情况,请重试.", "错误", MB_ICONWARNING); } } } //---
现在我们只需要测试这个选项,让我们在两个交易品种上建立仓位,(比如AUDUSD和 EURUSD)。当我们运行脚本的时候,在外部参数下拉列表中选择所有交易品种模式并点击确定, 一个对话框会如下显示:
Fig. 4. 显示第二个选项仓位属性的对话框
结论
您可以在上图中看到,对话框有三个按钮,如果您点击了重试,循环计数器会被重设,当前显示在对话框中的交易品种仓位属性会被刷新;如果您点击了继续,程序会处理下一个交易品种;取消按钮用于终止程序。
请注意,仓位属性以上的第一行包含持仓总数信息(仓位总数)和仓位计数器的当前编号(当前)。
就是这样,请随意下载附件中的源代码,它们需要在MetaQuotes语言编辑器中编译。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/639
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.




建仓时,如果需要,您可以在注释中指定智能交易系统的名称。老实说,我不太明白您想获得什么以及为什么。您是否在处理交易历史记录,并在分析历史记录时,希望通过编程/可视化方式确定哪些交易是由哪个智能交易系统执行的?如果是,那么可以使用注释或神奇数字。
当使用 30 个智能交易系统,甚至 30 个不同的货币对时,不可能跟踪所有情况 - 我希望它能自己发生
你好,阿纳托利、
我刚刚才发现这两篇 "食谱",非常感谢你们的努力。
我注意到,像这样的程序/脚本似乎无法识别特定货币对是否有一个以上的仓位。
例如,如果我在欧元兑美元上开了两个仓位(一个在 1.2250 卖出,另一个在 1.2200 卖出),那么它只能识别第一个仓位,而不能识别第二个仓位。我不确定这是否是因为程序/脚本必须告诉程序/脚本这是一个允许对冲的账户?您是否有关于脚本识别同一货币对 多个仓位的文章?
非常感谢
丁戈
你好,阿纳托利、
我刚刚才发现这两篇文章的'食谱',非常感谢你们的努力。
我注意到这样的程序/脚本似乎无法识别特定货币对是否有一个以上的头寸。
例如,如果我在欧元兑美元上开了两个仓位(一个在 1.2250 卖出,另一个在 1.2200 卖出),那么它只能识别第一个仓位,而不能识别第二个仓位。我不确定这是否是因为程序/脚本必须告诉程序/脚本这是一个允许对冲的账户?您是否有关于脚本识别同一货币对 多个仓位的文章?
非常感谢
Dingo
嘿
我知道你发布这个帖子已经有一段时间了。的确,我认为第一种方法只能读取给定符号 pos 中的第一笔订单。如果要读取某个特定符号的所有交易,您需要将第二种方法调整为脚本(所有交易),然后添加一个 if "过滤器",只有当订单符号与当前给定符号相同时,才会执行。
希望对您有所帮助。
-费尔南多