MQL5 Cookbook: Getting Position Properties

Anatoli Kazharski | 4 March, 2013

Introduction

The previous article called "MQL5 Cookbook: Using Different Print Modes" showed us how we can quickly write a script and print the required information using three different modes. Let us now create a script that will get and display all position properties to the user.

We need to implement it in such a way so as to allow the user to select the appropriate option in the external parameters of the script, as follows: to either only get position properties on one (current) symbol or to run across all open positions (if any) one by one on all symbols. This time, we will view the required information right in the dialog box which is quite convenient and some of you might find this method more useful.


Writing a Script

The beginning of the program is more or less the same as in the previous article (see the code below). We start with the program properties. They are followed by the line with the #define directive and we then assign the program name to the SCRIPT_NAME variable using the MQLInfoString() function and the MQL5_PROGRAM_NAME constant it specifies. More information on all possible values of the MQLInfoString() function can be found in MQL5 Reference.

We continue with enumeration of the modes. If you write a comment for every identifier, the text of such comment will be displayed in the drop-down list in the external parameters. We will implement two options:

There is going to be only one external parameter (mode) to be used to select the appropriate mode. The comment following the external parameter will also be displayed in the window of external parameters. This will allow us to create more meaningful parameter names. At the same time shorter names of variables would be more convenient in terms of code.

#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 MQLInfoString(MQL_PROGRAM_NAME) // Script name
//---
// ENUMERATION OF MODES
enum ENUM_SYMBOLS_MODE
  {
   CURRENT_SYMBOL =0,                     // Current symbol
   ALL_SYMBOLS    =1                      // All symbols
  };
//---
// INPUT PARAMETERS
input ENUM_SYMBOLS_MODE mode=CURRENT_SYMBOL;     // Mode

The code continues with global variables. In order for global variables to be accessed from any part of the script, they should be placed outside of the functions (usually at the very beginning of the program).

// GLOBAL VARIABLES
long                 pos_magic=0;         // Magic number
string               pos_symbol="";       // Symbol
string               pos_comment="";      // Comment
double               pos_swap=0.0;        // Swap
double               pos_commission=0.0;  // Commission
double               pos_price=0.0;       // Current price of the position
double               pos_cprice=0.0;      // Current price of the position
double               pos_profit=0.0;      // Profit/Loss of the position
double               pos_volume=0.0;      // Position volume
double               pos_sl=0.0;          // Stop Loss of the position
double               pos_tp=0.0;          // Take Profit of the position
datetime             pos_time=NULL;       // Position opening time
long                 pos_id=0;            // Position identifier
ENUM_POSITION_TYPE   pos_type=NULL;       // Position type
//---

In the main program function, we will call only one user-defined function, PrintPositionProperties(), that will perform all required operations:

//+------------------------------------------------------------------+
//| MAIN FUNCTION                                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   PrintPositionProperties();
  }

Let us now take a look at the structure of the user-defined PrintPositionProperties() function step by step. We will first form the base for our further work. It is very simple and when implemented looks as follows:

//+------------------------------------------------------------------+
//| OPENING A DIALOG BOX WITH SYMBOL DATA                            |
//+------------------------------------------------------------------+
void PrintPositionProperties()
  {
   int err=0; // Variable for handling errors
//---
// If you need to get position properties on the current symbol only
   if(mode==CURRENT_SYMBOL)
     {
 
     }
//---
// If you need to get position properties on all symbols
   if(mode==ALL_SYMBOLS)
     {
 
     }
  }

We only have two branches and a local variable err which is responsible for handling errors and is declared at the beginning of the function. Now we need to write use case scenarios for each of the options. Let us start with the first one, i.e. "If you need to get position properties on the current symbol only".

It is very simple. First of all, we need to check if there is a position on the current symbol. This can be done by the PositionSelect() function available in MQL5 which takes the symbol name as the only parameter. To pass the current symbol name we need to either use the Symbol() function or the predefined variable _Symbol that already contains the current symbol name. The PositionSelect() function will return a positive result, if a position on that symbol exists, or a negative result, if there is no position or an error has occurred.

The code with detailed comments for the first option is provided below:

//---
      // If a position exists, then...
      if(PositionSelect(_Symbol))
        {
         // ...get its properties
         GetPositionProperties();
         //---
         // Open a dialog box to display all the data we obtained
         MessageBox("Symbol        : "+pos_symbol+"\n"+
                    "Comment       : "+pos_comment+"\n"+
                    "Magic Number  : "+IntegerToString(pos_magic)+"\n"+
                    "Price Open    : "+DoubleToString(pos_price,_Digits)+"\n"+
                    "Current Price : "+DoubleToString(pos_cprice,_Digits)+"\n"+
                    "Stop Loss     : "+DoubleToString(pos_sl,_Digits)+"\n"+
                    "Take Profit   : "+DoubleToString(pos_tp,_Digits)+"\n"+
                    "Type          : "+PositionTypeToString(pos_type)+"\n"+
                    "Volume        : "+DoubleToString(pos_volume,2)+"\n"+
                    "Commission    : "+DoubleToString(pos_commission,2)+"\n"+
                    "Swap          : "+DoubleToString(pos_swap,2)+"\n"+
                    "Profit        : "+DoubleToString(pos_profit,2)+"\n"+
                    "Time          : "+TimeToString(pos_time)+"\n"+
                    "Identifier    : "+IntegerToString(pos_id)+"",
                    //---
                    "Message Box",MB_ICONASTERISK);
         //---
         return;
        }
      // If there is no position or an error has occurred, report it
      else
        {
         err=GetLastError(); // Get the code of the last registered error
         //---
         if(err>0) // If there is an error
           {
            // Print the relevant message
            MessageBox("Error ("+IntegerToString(err)+") when selecting a position ("+_Symbol+") !\n\n"+
                       "It is possible that there is no position on this symbol. If this is not the case, please try again.",
                       "Error",
                       MB_ICONWARNING);
            //---
            return; // Exit the function
           }
        }
      //---

In the code above, we can see two more user-defined functions - GetPositionProperties() and PositionTypeToString(). Since we will have to get position properties in various points throughout the program, it will be good to create a separate function in order to reduce the amount of code and thus make it more readable. Below is the code of this function. Be sure to check MQL5 Reference for additional information on the MQL5 functions and identifiers used in GetPositionProperties().

//+------------------------------------------------------------------+
//| GETTING SYMBOL PROPERTIES                                        |
//+------------------------------------------------------------------+
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);
  }

The user-defined PositionTypeToString() function converts position type returned as an integer to a string to read format, as shown in the code below:

//+------------------------------------------------------------------+
//| CONVERTING POSITION TYPE TO A STRING                             |
//+------------------------------------------------------------------+
string PositionTypeToString(int position_type)
  {
   string str="";
//---
   if(position_type==0) { str="buy";  }
   if(position_type==1) { str="sell"; }
//---
   return(str);
  }

So the code for the first option whereby we can view position properties only on the current symbol is ready. It can even be tested right now if you have followed all steps described in the article. Open a position in MetaTrader 5 using standard tools. For this purpose, press F9 and the Order window will open where you can find all necessary options to set position properties before it opens:

Fig. 1. The Order window in the MetaTrader 5 client terminal.

Fig. 1. The Order window in the MetaTrader 5 client terminal.

When all properties have been set, select either Sell or Buy and run the script by double-clicking or dragging it onto the chart. A script window will open. The required value (Current symbol) of the Mode parameter has already been set by default. A click on the OK button will open a dialog box displaying all position properties on the current symbol:

Fig. 2. Dialog box with position properties on the current symbol.

Fig. 2. Dialog box with position properties on the current symbol.

Otherwise, if there is no position on the current symbol, an alert box will appear:

Fig. 3. Alert box.

Fig. 3. Alert box.

Everything seems to be working as planned and as implemented in the code.

Let us now review the program code that is going to be used if you choose to view all open position properties. The code with detailed comments is shown below:

//---
      int digits=0; // Number of decimal places
      int mb_res=-1; // Variable with the option selected in the dialog box
      int pos_total=PositionsTotal(); // Number of open positions in the terminal
      //---
      // View properties of all positions in a loop one by one
      for(int i=0; i<pos_total; i++)
        {
         ResetLastError(); // Reset the last error
         //---
         pos_symbol=PositionGetSymbol(i); // Get the symbol name
         digits=(int)SymbolInfoInteger(pos_symbol,SYMBOL_DIGITS); // Get the number of digits in the price
         //---
         // If a position on this symbol exists, then...
         if(PositionSelect(pos_symbol))
           {
            // ...get its properties
            GetPositionProperties();
            //---
            // Open a dialog box to display all position properties obtained
            mb_res=MessageBox("Total Positions/Current: "+IntegerToString(pos_total)+"/"+IntegerToString(i+1)+"\n"+
                              "---------------------------------\n"+
                              "Symbol: "        +pos_symbol+"\n"+
                              "Comment: "       +pos_comment+"\n"+
                              "Magic Number: "  +IntegerToString(pos_magic)+"\n"+
                              "Price Open: "    +DoubleToString(pos_price,digits)+"\n"+
                              "Current Price: " +DoubleToString(pos_cprice,digits)+"\n"+
                              "Stop Loss: "     +DoubleToString(pos_sl,digits)+"\n"+
                              "Take Profit: "   +DoubleToString(pos_tp,digits)+"\n"+
                              "Type: "          +PositionTypeToString(pos_type)+"\n"+
                              "Volume: "        +DoubleToString(pos_volume,2)+"\n"+
                              "Commission: "    +DoubleToString(pos_commission,2)+"\n"+
                              "Swap: "          +DoubleToString(pos_swap,2)+"\n"+
                              "Profit: "        +DoubleToString(pos_profit,2)+"\n"+
                              "Time: "          +TimeToString(pos_time)+"\n"+
                              "Identifier: "    +IntegerToString(pos_id)+"",
                              //---
                              "Message Box",MB_CANCELTRYCONTINUE|MB_ICONASTERISK);
            //---
            if(mb_res==IDCANCEL) // If you have clicked Cancel or Close
              { Print("The program ("+SCRIPT_NAME+") has been terminated by the user!"); return; } // Exit the function
            //---
            // If you have clicked Retry   
            if(mb_res==IDTRYAGAIN) { i--; } // Reset the counter to retry
           }
         else // If there is no position or an error has occurred, report it
           {
            err=GetLastError(); // Get the code of the last registered error
            //---
            if(err>0) // If there is an error
              {
               // Print the relevant message
               MessageBox("Error ("+IntegerToString(err)+") when selecting a position ("+pos_symbol+") !\n\n"+
                          "It is possible that there is no position on this symbol. If this is not the case, please try again.",
                          "Error",
                          MB_ICONWARNING);
              }
           }
        }
      //---

Now we only need to test this option. Let us, for example, open positions on two symbols (AUDUSD and EURUSD). Once we run the script, select the All symbols mode in the drop-down list in the external parameters and click OK, a dialog box will open as shown below:

Fig. 4. Dialog box with position properties for the second option.

Fig. 4. Dialog box with position properties for the second option.


Conclusion

As you can see in the figure above, there are three buttons in the dialog box. If you click Retry, the loop counter will be reset and position properties for the symbol currently displayed in the dialog box will be refreshed. If you click Continue, the program will proceed to the next symbol. The Cancel button serves to terminate the program.

It should also be noted that the first line above the list of position properties contains information on the total number of open positions (Total Positions) and current number of the position counter (Current).

That's about it. Feel free to download the source code file attached below which will need to be compiled in MetaEditor.