外汇EA编写教程: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客户终端中的订单窗口.

图 1. MetaTrader 5客户终端中的订单窗口.

当所有属性设置完成,选择卖出或者买入,然后双击脚本或者把它拖到图表上来运行脚本,脚本窗口将会打开,模式参数的所需值 (当前交易品种)已经被默认填好了,点击“确定”按钮将会打开一个对话框,显示当前交易品种的所有仓位属性:

图 2. 显示当前交易品种仓位属性的对话框.

图 2. 显示当前交易品种仓位属性的对话框.

另一方面,假如当前交易品种没有持仓,会出现一个提醒对话框:

图 3. 提醒对话框.

图 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. 显示第二个选项仓位属性的对话框

Fig. 4. 显示第二个选项仓位属性的对话框

结论

您可以在上图中看到,对话框有三个按钮,如果您点击了重试,循环计数器会被重设,当前显示在对话框中的交易品种仓位属性会被刷新;如果您点击了继续,程序会处理下一个交易品种;取消按钮用于终止程序。

请注意,仓位属性以上的第一行包含持仓总数信息(仓位总数)和仓位计数器的当前编号(当前)。

就是这样,请随意下载附件中的源代码,它们需要在MetaQuotes语言编辑器中编译。

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/639

附加的文件 |

下载ZIP
printpositionproperties.mq5
(16.2 KB)

 

 


MyFxtop迈投-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投