Русский 中文 Español Deutsch 日本語 Português
preview
Studying PrintFormat() and applying ready-made examples

Studying PrintFormat() and applying ready-made examples

MetaTrader 5Examples | 10 October 2023, 08:50
4 351 0
Artyom Trishkin
Artyom Trishkin

Displaying values in the log or on the monitor screen is a simple and familiar operation until you need to show something more complex than "Hello, world". But sooner or later a situation arises when you need to make a formatted output of a value or property that is not very often in demand. Of course, you can look into the MQL5 help.

But sometimes you want to have a ready-made collection of recipes for displaying all kinds of information provided by the MetaTrader 5 terminal. In this article, we will try to understand the intricacies of calling the PrintFormat function and write ready-made templates you can simply insert into your code.


Contents


Introduction

Any application running in the terminal should be able to inform users about its state and the state of its environment. Such data is always printed in the program log, which you can find in the Experts tab of the trading terminal. Subsequently, when parsing and analyzing program logs, it is important that all entries are in an easy-to-read form, because the ease of reading and searching for information depends on this.

MQL5 language features the Print() function, which prints lines or data converted to a line into the log. This is quite sufficient for short logging. But if we send large amounts of data to the log, then it is desirable that they be formatted in a form that is easy to understand.

When the data header (description) and its corresponding value are written on one line without any formatting, then reading such data in a short list will not cause difficulties. However, if there is a lot of data, and they all follow each other and have different lengths of descriptions and meanings, then all this turns into just a long stream of information. It is advisable to format such data and bring it into a single tabular form, where all headers have the same width (header column), and the data corresponding to the headers will be located at the same distance from the header (data column). The PrintFormat() allows doing just that. It formats and prints sets of characters and values into the EA journal in accordance with the specified format.


PrintFormat(). How it works

The PrintFormat() function input receives a format string that describes the form in which the data should be displayed, and a set of data corresponding to the format string to be located in the resulting string in accordance with the way they are displayed in the log. You can set your own output format for each value. In simple form, it looks like this:

("%Value1 is to be displayed like this%Value2 is to be displayed like this%Value3 is to be displayed like this ... ... %ValueN is to be displayed like this some text", Value1, Value2, Value3, ... ..., ValueN)

As you can see, in the place where certain data needs to be displayed in the text, there should be format lines describing the method for displaying the values of the output data. Each format string is preceded by %, which informs that what follows is a description of the output format. You can write any text between format descriptions (“some text” at the end in the example above). After completing the input of a line with format characters and text, the data is separated by commas in the order in which the output format is described for them in the format line. In the example above, each format description and its corresponding value are marked with the same color.

First, we write the text that should be displayed in the log. Next, inside the text, enter the symbols of the data output format if data should be located in this place.

For example: ("%This text will be located in the 50 character wide column%these double data will be in the next column and left aligned", string_variable_with_text_of_the_first_column, double data_of_the_second_column);

Naturally, you do not need a text to describe all this, since there are special format characters. They should go in a strictly specified order, but not all of them should be present in the format line.

The format string is read from left to right. When the first format specification (if any) is encountered, the value of the first parameter after the format string is converted and displayed according to the given specification. The second format specification causes the second parameter to be converted and displayed, and so on, until the end of the format string.

The format specification has the following form:

         %[flags][width][.precision][{h | l | ll | I32 | I64}]type

Let's look at what is written in the help for each item in the format string and describe it in more detail.

Percentage sign (%) — start a new format string. After this sign, at least one specifier must be specified, and it is important to understand that the type specifier (type) is the only required field for the formatted output. That is, if the '%' sign is entered in a line, then the type of data displayed in this place must be indicated after it. Or another percentage sign in order to write the '%' sign in the text. To show that this is not the beginning of a new format line, but simply a percentage sign inscribed in the text, you need to write the combination: '%%'.

The flags (flags):

  • - (minus sign). The line text will be left aligned within the specified width. The width is specified by the width specifier following the flag. "%-10" means that the text will be aligned to the left edge of the field, which is 10 characters wide. The next text in this line will be located starting from the right edge of the same field of 10 characters. If the text displayed within this 10-character field is larger than 10 characters, then the following text will be located at the end of the text, not the field. In other words, the width of the field will be expanded to the size of the text placed in it. The text is not trimmed along the width of the field. On the contrary, the field expands along the length of the text.
    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- First line with a header of less than 10 characters and data in 20-character fields
    //--- The header and data are pressed to the left edge of their field
       header="10characters";
       value1=10000000;
       value2=20000000;
       PrintFormat("%-10s%-20ld%-20lld",header,(int)value1,(long)value2);
       
    //--- Second line with a header of more than 10 characters and data in 20-character fields
    //--- The header and data are pressed to the left edge of their field
       header="Over10characters";
       value1=10000000;
       value2=20000000;
       PrintFormat("%-10s%-20ld%-20lld",header,(int)value1,(long)value2);
    
       /* Sample output:
          10characters10000000            20000000            
          Over10characters10000000            20000000            
       */
      }
    
    


  • + (plus sign). For signed types, a + or - sign is always displayed depending on the value of the output data. For example: +222 or -12.35. If two lines of formatted text are consecutive, while in the top line in the same data column the value of the output data is positive, and in the bottom line - negative, then visually the values will be shifted relative to each other by one character (by the '-' sign). Below we will consider a flag that eliminates this visual inconvenience.
    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a 16-character field and data in 20-character fields
    //--- The header and data are pressed to the left edge.
    //--- Data values of the second field are displayed with +/- signs
       header="Header1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%-+20ld%-20lld",header,(int)value1,(long)value2);
       
    //--- The second line with a header in a 16-character field and data in 20-character fields
    //--- The header and data are pressed to the left edge.
    //--- Data values of the second field are displayed with +/- signs
       header="Header2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%-+20ld%-20lld",header,(int)value1,(long)value2);
       
       /* Sample output:
          Header1      -10000000           20000000            
          Header2      +10000000           -20000000           
       */
      }
    
    


  • 0 (zero). Zeros are added before the output value within the specified field width. If flag 0 is specified with an integer format (i, u, x, X, o, d) and a precision specification is set (for example, %04.d), then 0 is ignored. In other words, for integer types that are given a precision format (output at least so many characters), leading zeros of this format (format 0) do not have priority, since they fill the entire field, which contradicts the precision format.
    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a 16-character field and data in 20-character fields
    //--- The header and data are pressed to the left edge.
    //--- Data values of the second field are displayed with +/- signs
    //--- The data values of the third field are pressed to the right edge with leading zeros added.
       header="Header1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%-+20ld%020lld",header,(int)value1,(long)value2);
       
    //--- The second line with a header in a 16-character field and data in 20-character fields
    //--- The header and data of the second field are pressed to the left edge.
    //--- Data values of the second field are displayed with +/- signs
    //--- The data values of the third field are pressed to the right edge with leading zeros added.
       header="Header2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%-+20ld%020lld",header,(int)value1,(long)value2);
       
       /* Sample output:
          Header1      -10000000           00000000000020000000
          Header2      +10000000           -0000000000020000000
       */
      }
    
    


  • (space). The output value is preceded by a space if the value is signed and positive. Each positive data value of a field with this flag is shifted to the right by one character. This allows us to visually align values if there are positive and negative values in different rows in the same column. The space is placed instead of the '-' character of negative data.
    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a 16-character field and data in 20-character fields
    //--- The header and data of the second field are pressed to the left edge.
    //--- Data values of the third field are pressed to the right edge
    //--- For the second and third fields from the left, a space is added for positive values.
       header="Header1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%- 20ld% 20lld",header,(int)value1,(long)value2);
       
    //--- The second line with a header in a 16-character field and data in 20-character fields
    //--- The header and data of the second field are pressed to the left edge.
    //--- Data values of the third field are pressed to the right edge
    //--- For the second and third fields from the left, a space is added for positive values.
       header="Header2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%- 20ld% 20lld",header,(int)value1,(long)value2);
       
       /* Sample output:
          Header1      -10000000                       20000000
          Header2       10000000                      -20000000
       */
      }
    
    


  • # sign.

    1. When used in conjunction with the o, x or X format, then 0, 0x or 0X are added before the output value, respectively.
    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- First line with a header and data in 16-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed in decimal format
    //--- Data values of the third field are displayed in octal format with 0 added before the value
       header="Header1";
       value1=10000;
       value2=10000;
       PrintFormat("%-16s(DEC) %-16ld(OCT) %-#16lo",header,(uint)value1,(uint)value2);
       
    //--- Second line with header and data in 16-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed in hexadecimal format with 0x added before the value
    //--- Data values of the third field are displayed in hexadecimal format with 0X added before the value
       header="Header2";
       value1=10000;
       value2=10000;
       PrintFormat("%-16s(hex) %-#16lx(HEX) %-#16lX",header,(uint)value1,(uint)value2);
       
       /* Sample output:
          Header1      (DEC) 10000           (OCT) 023420          
          Header2      (hex) 0x2710          (HEX) 0X2710          
       */
      }
    
    


    2. When used in conjunction with the e, E, a or A format, the value is always output with a decimal point.

    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a 16-character field and data in 22-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'e' format
    //--- Data values of the third field are displayed together with the 'E' format
       header="Header1";
       value1=255;
       value2=1024;
       PrintFormat("%-16s(e) %-22e(E) %-#22E",header,(double)value1,(double)value2);
       
    //--- The second line with a header in a 16-character field and data in 22-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'a' format
    //--- Data values of the third field are displayed together with the 'A' format
       header="Header2";
       value1=255;
       value2=1024;
       PrintFormat("%-16s(a) %-#22a(A) %-#22A",header,(double)value1,(double)value2);
       
       /* Sample output:
          Header1      (e) 2.550000e+02          (E) 1.024000E+03          
          Header2      (a) 0x1.fe00000000000p+7  (A) 0X1.0000000000000P+10 
       */
      }
    
    


    3. When used in conjunction with the g or G format, the flag determines the presence of a decimal point in the output value and prevents cutting off leading zeros. The g format selects the most compact type of display f or e and displays the entry in the selected format. The G format is identical to the g format, but the choice is between the f and E formats.

    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a 16-character field and data in 22-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'f' format with default precision
    //--- Data values of the third field are displayed together with the 'g' format
       header="Header1";
       value1=Point();
       value2=DBL_MAX;
       PrintFormat("%-16s(f) %-22f(g) %-#22g",header,(double)value1,(double)value2);
       
    //--- The second line with a header in a 16-character field and data in 22-character fields
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'f' format with 5-character precision
    //--- Data values of the third field are displayed together with the 'G' format
       header="Header2";
       value1=Point();
       value2=EMPTY_VALUE;
       PrintFormat("%-16s(f) %-#22.5f(G) %-#22G",header,(double)value1,(double)value2);
       
       /* Sample output:
          Header1      (f) 0.000010              (g) 1.79769e+308          
          Header2      (f) 0.00001               (G) 1.79769E+308          
       */
      }
    
    

    # flag is ignored when used in conjunction with the formats c, d, i, u and s.


    Width specifier (width). The minimum number of characters of the formatted value to print. We discussed the work of the specifier together with the flags above. There is one interesting nuance: if you specify an asterisk (* sign) as the width value, then the value specified in the list along with the data should replace the asterisk:

    void OnStart()
      {
    //--- Declare the variables to be printed
       string   header="";  // Data header
       double   value1=0;   // First value
       double   value2=0;   // Second value
       
    //--- The first line with a header in a *-character field (16) and data in *-character fields (22)
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'f' format with default precision
    //--- Data values of the third field are displayed together with the 'g' format
       header="Header1";
       value1=Point();
       value2=DBL_MAX;
       PrintFormat("%-*s(f) %-*f(g) %-#*g",16,header,22,(double)value1,22,(double)value2);
       
    //--- The second line with a header in a *-character field (16) and data in *-character fields (22)
    //--- The header and data of all fields are pressed to the left edge.
    //--- Data values of the second field are displayed together with the 'f' format with 5-character precision
    //--- Data values of the third field are displayed together with the 'G' format
       header="Header2";
       value1=Point();
       value2=EMPTY_VALUE;
       PrintFormat("%-*s(f) %-#*.5f(G) %-#*G",16,header,22,(double)value1,22,(double)value2);
       
       /* Sample output:
          Header1      (f) 0.000010              (g) 1.79769e+308          
          Header2      (f) 0.00001               (G) 1.79769E+308          
       */
      }
    
    

    In this example, the output is no different from the previous one, but here we specify the width of each field as a numeric parameter in the list of values. This is convenient if the table is displayed inside a function into which we can pass the width values for each column of the table. They will be substituted for the asterisks in the format string.


    Precision specifier (.precision). Number of digits after the decimal point. The precision specification can trim part of the fractional value with or without rounding.

    For different format types (type), the precision specification is applied in different ways:

    • a, A.  Specifies the number of digits after the decimal point.
      void OnStart()
        {
      //--- Declare the variables to be printed
         string   header="";  // Data header
         double   value1=0;   // First value
         double   value2=0;   // Second value
         
      //--- The first line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'a' format with default precision
      //--- Data values of the third field are displayed together with the 'A' format with default precision
         header="Header1";
         value1=Point();
         value2=DBL_MAX;
         PrintFormat("%-16s(a) %-22a(A) %-#22A",header,(double)value1,(double)value2);
         
      //--- The second line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'a' format with 5-character precision
      //--- Data values of the third field are displayed together with the 'A' format with 7-character precision
         header="Header2";
         value1=Point();
         value2=EMPTY_VALUE;
         PrintFormat("%-16s(a) %-#22.5a(A) %-#22.7A",header,(double)value1,(double)value2);
         
         /* Sample output:
            Header1      (a) 0x1.4f8b588e368f1p-17 (A ) 0X1.FFFFFFFFFFFFFP+1023
            Header2      (a) 0x1.4f8b6p-17         (A) 0X2.0000000P+1023     
         */
        }
      
      


    • d, i, u, o, x, X. Specifies the minimum number of displayed digits. If the number of digits in the corresponding parameter is less than the specified precision, then the output value is supplemented on the left with zeros. The displayed value is not truncated if the number of output digits is greater than the specified precision
      void OnStart()
        {
      //--- Declare the variables to be printed
         string   header="";  // Data header
         double   value1=0;   // First value
         double   value2=0;   // Second value
         
      //--- The first line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'd' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'i' format with 11-character precision
         header="Header1";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(d) %-22.4d(i) %-#22.11i",header,(int)value1,(int)value2);
         
      //--- The second line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'u' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'o' format with 11-character precision
         header="Header2";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(u) %-#22.4u(o) %-#22.11o",header,(double)value1,(double)value2);
         
      //--- The third line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'x' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'X' format with 11-character precision
         header="Header3";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(x) %-#22.4x(X) %-#22.11X",header,(double)value1,(double)value2);
         
         /* Sample output:
            Header1      (d) 2147483647            (i) 02147483647           
            Header2      (u) 4290772992            (o) 037760000000          
            Header3      (x) 0xffc00000            (X) 0X000FFC00000         
         */
        }
      
      


    • e, E, f. Specifies the number of displayed digits after the decimal point. The last digit displayed is rounded
      void OnStart()
        {
      //--- Declare the variables to be printed
         string   header="";  // Data header
         double   value1=0;   // First value
         double   value2=0;   // Second value
         
      //--- The first line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'e' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'E' format with 11-character precision
         header="Header1";
         value1=DBL_MAX;
         value2=DBL_MAX;
         PrintFormat("%-16s(e) %-22.4e(E) %-#22.11E",header,(double)value1,(double)value2);
         
      //--- The second line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'f' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'f' format with 11-character precision
         header="Header2";
         value1=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(f) %-#22.4f(f) %-#22.11f",header,(double)value1,(double)value2);
         
         /* Sample output:
            Header1      (e) 1.7977e+308           (E) 1.79769313486E+308    
            Header2      (f) 1.2729                (f) 1.27286000000         
         */
        }
      
      

    • g, G. Specifies the maximum number of significant digits
      void OnStart()
        {
      //--- Declare the variables to be printed
         string   header="";  // Data header
         double   value1=0;   // First value
         double   value2=0;   // Second value
         
      //--- The first line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'g' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'G' format with 11-character precision
         header="Header1";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-22.4g(G) %-#22.11G",header,(double)value1,(double)value2);
         
      //--- The second line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'g' format with 4-character precision
      //--- Data values of the third field are displayed together with the 'G' format with 11-character precision
         header="Header2";
         value1=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         value2=DBL_MAX;
         PrintFormat("%-16s(g) %-#22.4g(G) %-#22.11G",header,(double)value1,(double)value2);
         
         /* Sample output:
            Header1      (g) 1.798e+308            (G) 1.2731600000          
            Header2      (g) 1.273                 (G) 1.7976931349E+308     
      
         */
        }
      
      
      Keep in mind that the maximum number of significant digits does not mean the number of decimal places. All digits of the number are taken into account here. If the specified bit depth is 4 digits, in the case of the Digits() value of five, we will not see four digits after the decimal point in the price value. In this example we see only three decimal places (1.273) since the fourth digit of the number here is the digit preceding the decimal point.


    • s. The number of displayed line characters. If the line length exceeds the precision value, then the line is truncated during the output
      void OnStart()
        {
      //---
      
      //--- Declare the variables to be printed
         string   header="";  // Data header
         double   value1=0;   // First value
         double   value2=0;   // Second value
         
      //--- The first line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'g' format with 4-character precision
      //--- Data values of the third field are displayed together with the 's' format with 11-character precision
         header="Header1";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-22.4g(s) %-#22.11s",header,(double)value1,(string)value2);
         
      //--- The second line with a header in a 16-character field and data in 22-character fields
      //--- The header and data of all fields are pressed to the left edge.
      //--- Data values of the second field are displayed together with the 'g' format with 5-character precision
      //--- Data values of the third field are displayed together with the 's' format with 4-character precision
         header="Header2";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-#22.5g(s) %-#22.4s",header,(double)value1,(string)value2);
         
         /* Sample output:
            Header1      (g) 1.798e+308            (s) 1.2872                
            Header2      (g) 1.7977e+308           (s) 1.28                  
      
         */
        }
      
      

        Data size specifier (h | l | ll | I32 | I64). Specifies the size of the integer data passed as a parameter. We can specify the size of this data (int, uint, short, ushort, long, ulong) by passing an integer as a parameter. Below is a table of compatibility between size specifiers and data types:

        Data size
        Size specifiers
         Type specifiers
          short   h
          d, i, o, x, X
          ushort   h
          u, o, x, X
          int
          l (lower-case L), I32
          d, i, o, x, X
          uint
          l (lower-case L), I32
          u, o, x, X
          long
          ll (two lower-case Ls), I64
          d, i, o, x, X
          ulong
          I64
          u, o, x, X


        Data type specifier (type). The only required field for formatted output. 

        Symbol
         Type Format
        c
        int
        short type symbol (Unicode)
        C
        int
        char type symbol (ANSI)
        d
        int
        Signed decimal integer
        i
        int
        Signed decimal integer
        o
        int
        Unsigned octal integer
        u
        int
        Unsigned decimal integer
        x
        int
        Unsigned hexadecimal integer using "abcdef"
        X
        int
        Unsigned hexadecimal integer using "ABCDEF"
        e
        double
        A real value in the [ – ]d.dddd e [sign]ddd format, where d is one decimal digit, dddd is one or more decimal digits, ddd is a three-digit number defining the size of the exponent, while 'sign' is a plus or minus sign
        E
        double
        Identical to e format, except that the exponent sign is capitalized (E instead of e)
        f
        double
        A real value in the [ – ]dddd.dddd format, where dddd is one or more decimal digits. The number of digits displayed before the decimal point depends on the value of the number. The number of places after the decimal point depends on the required precision.
        g
        double
        A real value output in f or e format, depending on which output is more compact.
        G
        double
        A real value output in f or E format, depending on which output is more compact.
        a
        double
        A real value in the [−]0xh.hhhh p±dd format, where h.hhhh is the mantissa in hexadecimal digits using "abcdef", dd is one or more exponent digits. The number of decimal places is determined by the precision specification
        A
        double
        A real value in the [−]0xh.hhhh P±dd format, where h.hhhh is the mantissa in hexadecimal digits using "ABCDEF", dd is one or more exponent digits. The number of decimal places is determined by the precision specification
        s
        string
        Line output


        The data type allows us to specify in what form we want to receive an entry in the terminal log. For example, when using 'c' or 'C' types, the output is one character. The value passed by parameters specifies the Unicode or ANSI table code for that character, while using the same value with other type specifiers will display the parameter value itself in the chosen format, but not the character:

        void OnStart()
          {
        //--- Declare the variables to be printed
           string   header="";  // Data header
           char     value1=0;   // First value
           char     value2=0;   // Second value
           
        //--- The first line with a header in a 16-character field and data in 10-character fields
        //--- The header and data of all fields are pressed to the left edge.
        //--- Data values of the second field are displayed together with the 'c' format
        //--- Data values of the third field are displayed together with the 'C' format
           header="Header1";
           value1=65;
           value2=66;
           PrintFormat("%-16s(c) %-10c(C) %-10C",header,(char)value1,(char)value2);
           
        //--- The second line with a header in a 16-character field and data in 10-character fields
        //--- The header and data of all fields are pressed to the left edge.
        //--- Data values of the second field are displayed together with the 'c' format
        //--- Data values of the third field are displayed together with the 'C' format
           header="Header2";
           value1=67;
           value2=68;
           PrintFormat("%-16s(c) %-10c(C) %-10C",header,(char)value1,(char)value2);
           
        //--- The third line with a header in a 16-character field and data in 10-character fields
        //--- The header and data of all fields are pressed to the left edge.
        //--- Data values of the second field are displayed together with the 'd' format
        //--- Data values of the third field are displayed together with the 'i' format
           header="Header3";
           value1=65;
           value2=66;
           PrintFormat("%-16s(d) %-10d(i) %-10i",header,(int)value1,(int)value2);
           
           /* Sample output:
              Header1      (c) A         (C) B         
              Header2      (c) C         (C) D         
              Header3      (d) 65        (i) 66        
           */
          }
        
        

        We have had a brief look at all formatting specifiers for a text displayed in the log. Let's look at what this looks using specific examples of displaying the properties of a trading account.


        Formatted display of account properties

        We can obtain integer, real and string properties using the AccountInfoInteger(), AccountInfoDouble() and AccountInfoString() functions, respectively.

        It is not always necessary to display a complete list of all properties. Therefore, for each property we will make a function that prints a description of this property in the log. After that, it will be possible to assemble any function, that sends the required properties (either all of them, or selected ones) to the log, from the ready-made functions.

        We will pass two parameters to the function - the width of the header field and the indentation of the header field from the left edge. Let's start in the following order: integer, real and finally string properties.


        Functions for printing integer account properties.

        Account number:

        //+------------------------------------------------------------------+
        //| Print a description of the account number into the journal       |
        //+------------------------------------------------------------------+
        void AccountLoginPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Login:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LOGIN));
           /* Sample output:
              Login: 68008618
           */
          }
        
        

        In the format string, firstindicate the size of the line indent from the left edge with an asterisk. In the line parameters, pass the size of the indent field (in place of the asterisk) and string value - an empty string (in place of the s character).
        The "%*s" format supplements the empty string passed in the parameters with spaces in accordance with the indentation value also passed in the string parameters. Thus, it is convenient to make any empty fields from space characters in a line of the required size. Then, in the format line, we also indicate the size of the header field with an asterisk, passing the value of the w variable in its place and the header line in the header variable. The last parameter is the account index value from AccountInfoInteger() as a line.


        Trading account type:

        //+------------------------------------------------------------------+
        //| Print a trading account type into the journal                    |
        //+------------------------------------------------------------------+
        void AccountTradeModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the value of the trading account type
           ENUM_ACCOUNT_TRADE_MODE trade_mode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
        //--- "Cut out" the name of the trading account type from the line obtained from enum
           string mode=StringSubstr(EnumToString(trade_mode),19);
        //--- Convert the characters of the resulting line to lower case and replace the first letter from small to capital
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Trade mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Sample output:
              Trade mode: Demo
           */
          }
        
        


        Leverage size:

        //+------------------------------------------------------------------+
        //| Print a description of the provided leverage size in the journal |
        //+------------------------------------------------------------------+
        void AccountLeveragePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Leverage:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s1:%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LEVERAGE));
           /* Sample output:
              Leverage: 1:100
           */
          }
        
        


        Maximum number of orders:

        //+------------------------------------------------------------------+
        //| Print a description of the maximum allowed                       |
        //| number of active pending orders                                  |
        //+------------------------------------------------------------------+
        void AccountLimitOrdersPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Limit orders:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
           /* Sample output:
              Limit orders: 200
           */
          }
        
        


        Minimum collateral mode:

        //+------------------------------------------------------------------+
        //| Print a description of the mode for setting a minimal            |
        //| accepted level of collateral in the journal                      |
        //+------------------------------------------------------------------+
        void AccountMarginSOModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the value of the mode for setting the minimum available collateral
           ENUM_ACCOUNT_STOPOUT_MODE so_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
        //--- "Cut out" the mode name from the line obtained from enum 
           string mode=StringSubstr(EnumToString(so_mode),21);
        //--- Convert the characters of the resulting line to lower case and replace the first letter from small to capital
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="StopOut mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Sample output:
              StopOut mode: Percent
           */
          }
        
        


        Allowing trading for an account:

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| of allowing trading for the current account in the journal       |
        //+------------------------------------------------------------------+
        void AccountTradeAllowedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Trade allowed:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- Depending on the bool value of the property, pass the "Yes" or "No" line as a parameter
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) ? "Yes" : "No"));
           /* Sample output:
              Trade allowed: Yes
           */
          }
        
        


        Trading permission for an EA:

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| allowing trading for an EA                                       |
        //+------------------------------------------------------------------+
        void AccountTradeExpertPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Trade expert:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- Depending on the bool value of the property, pass the "Yes" or "No" line as a parameter
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ? "Yes" : "No"));
           /* Sample output:
              Trade expert: Yes
           */
          }
        
        


        Margin calculation mode:

        //+------------------------------------------------------------------+
        //| Print a description of the margin calculation mode in the journal|
        //+------------------------------------------------------------------+
        void AccountMarginModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the value of the margin calculation mode
           ENUM_ACCOUNT_MARGIN_MODE  margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
        //--- "Cut out" the mode name from the line obtained from enum 
           string mode=StringSubstr(EnumToString(margin_mode),20);
        //--- Convert the characters of the resulting line to lower case and replace the first letter from small to capital
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Replace all underscore characters with space in the resulting line
           StringReplace(mode,"_"," ");
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Sample output:
              Margin mode: Retail hedging
           */
          }
        
        


        Number of decimal places for account currency:

        //+------------------------------------------------------------------+
        //| Print a description of the number of                             |
        //| decimal places for an account currency                           |
        //+------------------------------------------------------------------+
        void AccountCurrencyDigitsPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Currency digits:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS));
           /* Sample output:
              Currency digits: 2
           */
          }
        
        


        Flag of position closure by FIFO rule:

        //+------------------------------------------------------------------+
        //| Print a description of the flag indicating                       |
        //| that positions can only be closed using the FIFO rule            |
        //+------------------------------------------------------------------+
        void AccountFIFOClosePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="FIFO close:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- Depending on the bool value of the property, pass the "Yes" or "No" line as a parameter
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_FIFO_CLOSE) ? "Yes" : "No"));
           /* Sample output:
              FIFO close: No
           */
          }
        
        


        Allowing opposing positions on one symbol:

        //+------------------------------------------------------------------+
        //| Print a description of the flag indicating                       |
        //| opposite positions are allowed on a single symbol                |
        //+------------------------------------------------------------------+
        void AccountHedgeAllowedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Hedge allowed:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- Depending on the bool value of the property, pass the "Yes" or "No" line as a parameter
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_HEDGE_ALLOWED) ? "Yes" : "No"));
           /* Sample output:
              Hedge allowed: Yes
           */
          }
        
        


        Functions for printing real account properties.

        Account balance:

        //+------------------------------------------------------------------------------------+
        //| Print a description of the account balance in the deposit currency in the journal  |
        //+------------------------------------------------------------------------------------+
        void AccountBalancePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the balance, the number of decimal places for the symbol and its name
           double ballance=AccountInfoDouble(ACCOUNT_BALANCE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Balance:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,ballance,currency);
           /* Sample output:
              Balance: 10015.00 USD
           */
          }
        
        


        Account credit:

        //+------------------------------------------------------------------+
        //| Print a description of account credit size                       |
        //| in a deposit currency                                            |
        //+------------------------------------------------------------------+
        void AccountCreditPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the credit, the number of decimal places for the symbol and its name
           double credit=AccountInfoDouble(ACCOUNT_CREDIT);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Credit:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,credit,currency);
           /* Sample output:
              Credit: 0.00 USD
           */
          }
        
        


        Current profit on the account :

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| of the current profit in the deposit currency                    |
        //+------------------------------------------------------------------+
        void AccountProfitPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the current profit, the number of decimal places for the symbol and its name
           double profit=AccountInfoDouble(ACCOUNT_PROFIT);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Profit:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,profit,currency);
           /* Sample output:
              Profit: 0.00 USD
           */
          }
        
        


        Account equity:

        //+------------------------------------------------------------------+
        //| Print a description of the value of                              |
        //| equity on an account in a deposit currency                       |
        //+------------------------------------------------------------------+
        void AccountEquityPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the equity, the number of decimal places for the symbol and its name
           double equity=AccountInfoDouble(ACCOUNT_EQUITY);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Equity:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,equity,currency);
           /* Sample output:
              Equity: 10015.00 USD
           */
          }
        
        


        Reserved collateral:

        //+------------------------------------------------------------------+
        //| Print a description of                                           |
        //| reserved collateral funds on the account in a deposit currency   |
        //+------------------------------------------------------------------+
        void AccountMarginPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the reserved collateral, the number of decimal places for the symbol and its name
           double margin=AccountInfoDouble(ACCOUNT_MARGIN);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin,currency);
           /* Sample output:
              Margin: 0.00 USD
           */
          }
        
        


        Available free funds to open a position:

        //+--------------------------------------------------------------------------------------+
        //| Print a description of the free funds,                                               |
        //| available for opening a position on an account in a deposit currency, in the journal |
        //+--------------------------------------------------------------------------------------+
        void AccountMarginFreePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the reserved collateral, the number of decimal places for the symbol and its name
           double margin_free=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin free:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_free,currency);
           /* Sample output:
              Margin free: 10015.00 USD
           */
          }
        
        


        Collateral level on an account in %:

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| of the collateral level on an account in %                       |
        //+------------------------------------------------------------------+
        void AccountMarginLevelPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin level:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- The value is set with 'digits' equal to 2 and the fact that the property is displayed in % is specified
           PrintFormat("%*s%-*s%-.2f %%",indent,"",w,header,AccountInfoDouble(ACCOUNT_MARGIN_LEVEL));
           /* Sample output:
              Margin level: 0.00 %
           */
          }
        
        


        Margin Call collateral level:

        //+----------------------------------------------------------------------------+
        //| Print a description of the collateral level,                               |
        //| at which a deposit to an account is required (Margin Call), in the journal |
        //+----------------------------------------------------------------------------+
        void AccountMarginSOCallPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the MarginCall level values, the number of decimal places for the symbol and its name
           double margin_so_call=AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- If the level of collateral for MarginCall is calculated as %,
        //--- specify 'currency' in % rather than in account currency, while 'digits' will be equal to 2
           if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT)
             {
              currency="%";
              digits=2;
             }
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin Call:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value obtained above
           PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_call,currency);
           /* Sample output:
              Margin Call: 50.00 %
           */
          }
        
        


        Margin Stop Out level:

        //+------------------------------------------------------------------+
        //| Print a description of the collateral level,                     |
        //| upon reaching which                                              |
        //| the most loss-making position is forcefully closed (Stop Out)    |
        //+------------------------------------------------------------------+
        void AccountMarginStopOutPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the StopOut level values, the number of decimal places for the symbol and its name
           double margin_so_so=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- If the level of collateral for StopOut is calculated as %,
        //--- specify 'currency' in % rather than in account currency, while 'digits' will be equal to 2
           if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT)
             {
              currency="%";
              digits=2;
             }
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin Stop Out:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value obtained above
           PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_so,currency);
           /* Sample output:
              Margin Stop Out: 30.00 %
           */
          }
        
        


        Amount reserved on account to cover margin of all pending orders:

        //+------------------------------------------------------------------+
        //| Print a description of the funds                                 |
        //| reserved on the account for security                             |
        //| of a guarantee amount for all pending orders                     |
        //+------------------------------------------------------------------+
        void AccountMarginInitialPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name
           double margin_initial=AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin initial:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_initial,currency);
           /* Sample output:
              Margin initial: 0.00 USD
           */
          }
        
        


        Min equity reserved on account to cover min amount of open positions:

        //+------------------------------------------------------------------+
        //| Print a description of the funds                                 |
        //| reserved on the account for security                             |
        //| of the min amount of all open positions                          |
        //+------------------------------------------------------------------+
        void AccountMarginMaintenancePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the amount of the reserved funds, the number of decimal places for the symbol and its name
           double margin_maintenance=AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Margin maintenance:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_maintenance,currency);
           /* Sample output:
              Margin maintenance: 0.00 USD
           */
          }
        
        


        Asset size:

        //+----------------------------------------------------------------------------+
        //| Print a description of the current asset size on the account in the journal|
        //+----------------------------------------------------------------------------+
        void AccountAssetsPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the current asset size on the account, the number of decimal places for the symbol and its name
           double assets=AccountInfoDouble(ACCOUNT_ASSETS);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Assets:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,assets,currency);
           /* Sample output:
              Assets: 0.00 USD
           */
          }
        
        


        Amount of liabilities:

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| of the current liabilities on the account                        |
        //+------------------------------------------------------------------+
        void AccountLiabilitiesPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the current liabilities on the account, the number of decimal places for the symbol and its name
           double liabilities=AccountInfoDouble(ACCOUNT_LIABILITIES);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Liabilities:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,liabilities,currency);
           /* Sample output:
              Liabilities: 0.00 USD
           */
          }
        
        


        Blocked commissions:

        //+------------------------------------------------------------------+
        //| Print a description                                              |
        //| of the current sum of blocked commissions on an account          |
        //+------------------------------------------------------------------+
        void AccountComissionBlockedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Get the current blocked commissions on the account, the number of decimal places for the symbol and its name
           double commission_blocked=AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Comission blocked:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
        //--- To display the value correctly, replace the asterisk in the format line with the digits value for the symbol
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,commission_blocked,currency);
           /* Sample output:
              Comission blocked: 0.00 USD
           */
          }
        
        


        Functions for printing string account properties.

        Client name:

        //+------------------------------------------------------------------+
        //| Print a description of the client name into the journal          |
        //+------------------------------------------------------------------+
        void AccountNamePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Name:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_NAME));
           /* Sample output:
              Name: Artem
           */
          }
        
        


        Trade server name:

        //+------------------------------------------------------------------+
        //| Print a description of the trade server name into the journal    |
        //+------------------------------------------------------------------+
        void AccountServerPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Server:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_SERVER));
           /* Sample output:
              Server: MetaQuotes-Demo
           */
          }
        //+------------------------------------------------------------------+
        
        


        Deposit currency name:

        //+------------------------------------------------------------------+
        //| Print a description of a deposit currency name                   |
        //+------------------------------------------------------------------+
        void AccountCurrencyPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Currency:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_CURRENCY));
           /* Sample output:
              Currency: USD
           */
          }
        
        


        Name of a company serving an account:

        //+------------------------------------------------------------------+
        //| Print a description of the company name,                         |
        //| serving an account, into the journal                             |
        //+------------------------------------------------------------------+
        void AccountCompanyPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Company:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the property value in the log with a header with the required width and indentation
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_COMPANY));
           /* Sample output:
              Company: MetaQuotes Software Corp.
           */
          }
        
        

        All the functions presented above are almost identical to each other. Each has the ability to set the line indent from the left edge and the width of the header field. Default values of zero passed to the function mean there is no indent and the margin width is equal to the size of the header line + 1 character. Thus, these functions can be used as is to displayed the required account properties. But when you need to create a function to display a group of properties, then you will need the indentation and width of the header field for a neat and easy-to-read output of values in the journal.

        Let's create an example of such a function that displays all account properties in the journal.

        The function that prints all account data to the journal:

        //+------------------------------------------------------------------+
        //| Print account data into the journal                              |
        //+------------------------------------------------------------------+
        void AccountInfoPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Display descriptions of integer properties according to their location in ENUM_ACCOUNT_INFO_INTEGER
           Print("AccountInfoInteger properties:");
           AccountLoginPrint(header_width,indent);
           AccountTradeModePrint(header_width,indent);
           AccountLeveragePrint(header_width,indent);
           AccountLimitOrdersPrint(header_width,indent);
           AccountMarginSOModePrint(header_width,indent);
           AccountTradeAllowedPrint(header_width,indent);
           AccountTradeExpertPrint(header_width,indent);
           AccountMarginModePrint(header_width,indent);
           AccountCurrencyDigitsPrint(header_width,indent);
           AccountFIFOClosePrint(header_width,indent);
           AccountHedgeAllowedPrint(header_width,indent);
        //--- Display descriptions of real properties according to their location in ENUM_ACCOUNT_INFO_DOUBLE
           Print("AccountInfoDouble properties:");
           AccountBalancePrint(header_width,indent);
           AccountCreditPrint(header_width,indent);
           AccountProfitPrint(header_width,indent);
           AccountEquityPrint(header_width,indent);
           AccountMarginPrint(header_width,indent);
           AccountMarginFreePrint(header_width,indent);
           AccountMarginLevelPrint(header_width,indent);
           AccountMarginSOCallPrint(header_width,indent);
           AccountMarginStopOutPrint(header_width,indent);
           AccountMarginInitialPrint(header_width,indent);
           AccountMarginMaintenancePrint(header_width,indent);
           AccountAssetsPrint(header_width,indent);
           AccountLiabilitiesPrint(header_width,indent);
           AccountComissionBlockedPrint(header_width,indent);
        //--- Display descriptions of string properties according to their location in ENUM_ACCOUNT_INFO_STRING
           Print("AccountInfoString properties:");
           AccountNamePrint(header_width,indent);
           AccountServerPrint(header_width,indent);
           AccountCurrencyPrint(header_width,indent);
           AccountCompanyPrint(header_width,indent);
          }
        
        

        The function calls in succession all functions that print account property data, in the order in which these properties appear in the enumerations ENUM_ACCOUNT_INFO_INTEGER, ENUM_ACCOUNT_INFO_DOUBLE and ENUM_ACCOUNT_INFO_STRING.

        The result of calling the function from the script with the header field width of 20 characters and indentation of 2 characters:

        void OnStart()
          {
        //--- Print trading account properties in the journal
           AccountInfoPrint(20,2);
           /* Sample output:
              AccountInfoInteger properties:
                Login:              68008618
                Trade mode:         Demo
                Leverage:           1:100
                Limit orders:       200
                StopOut mode:       Percent
                Trade allowed:      Yes
                Trade expert:       Yes
                Margin mode:        Retail hedging
                Currency digits:    2
                FIFO close:         No
                Hedge allowed:      Yes
              AccountInfoDouble properties:
                Balance:            10015.00 USD
                Credit:             0.00 USD
                Profit:             2.11 USD
                Equity:             10017.11 USD
                Margin:             25.61 USD
                Margin free:        9991.50 USD
                Margin level:       39114.06 %
                Margin Call:        50.00 %
                Margin Stop Out:    30.00 %
                Margin initial:     0.00 USD
                Margin maintenance: 0.00 USD
                Assets:             0.00 USD
                Liabilities:        0.00 USD
                Comission blocked:  0.00 USD
              AccountInfoString properties:
                Name:               Artem
                Server:             MetaQuotes-Demo
                Currency:           USD
                Company:            MetaQuotes Software Corp.
           */
          }
        
        


        Time with milliseconds from tick properties

        The MqlTick structure is designed for obtaining the most needed data on the current prices in a timely manner.

        A variable of the MqlTick type allows getting Ask, Bid, Last and Volume values in one call of the SymbolInfoTick() function. In addition, the structure contains the tick time in milliseconds. The time value is given in a variable of long type. In other words, when printing this data in the log, we will simply get a certain number - the number of milliseconds that have passed since 01.01.1970. To display this data in a human-readable time format, you need to convert this number to a date and add milliseconds to the resulting date.

        To get a date with seconds, you need to divide the number of milliseconds by 1000, and to get milliseconds of time, you need to take the remainder of the number of milliseconds of the date divided by 1000.

        In general, it looks like this:

        void OnStart()
          {
        //---
           MqlTick tick;
           if(SymbolInfoTick(Symbol(),tick))
             {
              string time_str=string((datetime)tick.time_msc / 1000)+"."+string(tick.time_msc % 1000);
              Print("time_str=",time_str);
             }
           /* Sample output:
              time_str=2023.07.10 18:49:36.463
           */
          }  
        
        


        Let's write the function that receives time in milliseconds and displays the time in the Date Time.Msc format:

        //+------------------------------------------------------------------+
        //| Print the time in the Date Time.Msc format in the journal        |
        //+------------------------------------------------------------------+
        void TimeMSCPrint(const long time_msc,const uint header_width=0,const uint indent=0)
          {
        //--- Define the header text and the width of the header field
        //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
           string header="Time msc:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Print the date and time in the journal with a header with the required width and indentation, milliseconds with 3 digit precision 
           PrintFormat("%*s%-*s%-s.%.3lu",indent,"",w,header,string((datetime)time_msc / 1000),time_msc % 1000);
           /* Sample output:
              Time msc: 2023.07.10 19:49:05.233
           */
          }
        
        


        To directly obtain the date and time in milliseconds and display it in the journal, you can use the following function:

        //+------------------------------------------------------------------+
        //| Print the time in the Date Time.Msc format for a symbol          |
        //+------------------------------------------------------------------+
        void TimeMSCPrint(const string symbol,const uint header_width=0,const uint indent=0)
          {
        //--- Get time from the tick
           MqlTick tick;
           if(!SymbolInfoTick(symbol,tick))
             {
              Print(__FUNCTION__,": SymbolInfoTick error: ",(string)GetLastError());
              return;
             }
        //--- Print the time in milliseconds using the first version of the function
           TimeMSCPrint(tick.time_msc,header_width,indent);
           /* Sample output:
              Time msc: 2023.07.10 20:07:08.202
           */
          }
        
        


        Conclusion

        In this article, we looked at PrintFormat() ability to print a formatted line and created sample functions for printing account properties you can use "as is" in your programs. But there is another way to create formatted output - the StringFormat() function. Unlike PrintFormat(), which prints a line in the required format to the journal, it returns a formatted line in the specified format. I consider it more convenient for displaying formatted text, since it creates the desired line from format lines. This line can then be used in different places in the program, and not just output to the journal. In the next article, I will consider StringFormat() and look at its features.


        Translated from Russian by MetaQuotes Ltd.
        Original article: https://www.mql5.com/ru/articles/12905

        Classification models in the Scikit-Learn library and their export to ONNX Classification models in the Scikit-Learn library and their export to ONNX
        In this article, we will explore the application of all classification models available in the Scikit-Learn library to solve the classification task of Fisher's Iris dataset. We will attempt to convert these models into ONNX format and utilize the resulting models in MQL5 programs. Additionally, we will compare the accuracy of the original models with their ONNX versions on the full Iris dataset.
        How to create a simple Multi-Currency Expert Advisor using MQL5 (Part 2): Indicator Signals: Multi Timeframe Parabolic SAR Indicator How to create a simple Multi-Currency Expert Advisor using MQL5 (Part 2): Indicator Signals: Multi Timeframe Parabolic SAR Indicator
        The Multi-Currency Expert Advisor in this article is Expert Advisor or trading robot that can trade (open orders, close orders and manage orders for example: Trailing Stop Loss and Trailing Profit) for more than 1 symbol pair only from one symbol chart. This time we will use only 1 indicator, namely Parabolic SAR or iSAR in multi-timeframes starting from PERIOD_M15 to PERIOD_D1.
        Alternative risk return metrics in MQL5 Alternative risk return metrics in MQL5
        In this article we present the implementation of several risk return metrics billed as alternatives to the Sharpe ratio and examine hypothetical equity curves to analyze their characteristics.
        GUI: Tips and Tricks for creating your own Graphic Library in MQL GUI: Tips and Tricks for creating your own Graphic Library in MQL
        We'll go through the basics of GUI libraries so that you can understand how they work or even start making your own.