Studying PrintFormat() and applying ready-made examples
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
- PrintFormat(). How it works
- Formatted display of account properties
- Displaying integer account properties
- Account number
- Trading account type
- Leverage
- Maximum number of orders
- Minimum collateral mode
- Allowing trading for an account
- Allowing trading for an EA
- Margin calculation mode
- Number of decimal places for account currency
- Flag of position closure by FIFO rule
- Allowing opposing positions on one symbol
- Displaying real account properties
- Account balance
- Account credit
- Current profit
- Account equity
- Reserved collateral
- Available free funds to open a position
- Margin level on an account in %
- Margin Call collateral level
- Margin Stop Out level
- Amount reserved on account to cover margin of pending orders
- Min equity reserved on account to cover min amount of open positions
- Asset size
- Amount of liabilities
- Blocked commissions
- Displaying string account properties
- Client name
- Trade server name
- Deposit currency name
- Name of a company serving an account
- Function that prints all account data to the journal
- Time with milliseconds from tick properties
- Conclusion
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
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use