English Русский 中文 Español Deutsch 日本語
preview
Aprendendo PrintFormat() e obtendo exemplos prontos para uso

Aprendendo PrintFormat() e obtendo exemplos prontos para uso

MetaTrader 5Exemplos | 20 novembro 2023, 16:35
290 0
Artyom Trishkin
Artyom Trishkin

A saída de valores para o log ou para a tela do monitor é uma operação simples e conhecida, até que seja necessário gerar algo mais complexo do que "Hello, world". Mas, mais cedo ou mais tarde, surge aquela situação em que você precisa gerar uma saída formatada de um valor ou de uma propriedade que não é necessária com frequência. Certamente, você pode acessar a Documentação MQL5 e se lembrar do que esqueceu ou não sabia.

Mas, às vezes, você quer ter uma coleção de receitas prontas para produzir todos os tipos de informações fornecidas pelo terminal MetaTrader 5. Neste artigo, tentaremos entender as nuances da chamada da função PrintFormat e escrever modelos prontos que podem ser simplesmente inseridos em seu código.


Conteúdo


Introdução

Qualquer programa que trabalhe em um terminal deve ser capaz de informar o usuário sobre o seu estado e o estado do seu ambiente. Esses dados são sempre registrados no log do programa, que pode ser visto na guia "Experts" do terminal de negociação. Mais tarde, ao analisar os logs do programa, é importante que todos os registros estejam em um formato conveniente, pois a facilidade de leitura e busca de informações depende disso.

A linguagem MQL5 tem a função Print(), que imprime no log strings ou dados convertidos em strings, da forma como estão escritos nessas strings. Para um breve registro em log, isso é suficiente. Mas se imprimirmos grandes conjuntos de dados no log, é bom que eles sejam formatados de uma forma fácil de entender.

Quando o cabeçalho de dados (descrição) e seu valor correspondente são registrados em uma linha sem nenhuma formatação, a leitura desses dados em uma lista curta não causará dificuldades. Por outro lado, se houver muitos dados, e todos eles se sucederem e tiverem diferentes tamanhos de descrições e valores, tudo se transformará em um longo fluxo de informações. É desejável formatar esses dados e colocá-los em um único formato tabular, em que todos os cabeçalhos tenham a mesma largura (coluna de cabeçalho) e os dados correspondentes aos cabeçalhos estejam localizados à mesma distância do cabeçalho (coluna de dados). E essa possibilidade existe. É a função PrintFormat() que formata e imprime conjuntos de caracteres e valores no log do Expert Advisor de acordo com a de acordo com um formato especificado.


PrintFormat(). O que é e como funciona

A função PrintFormat() tem como entrada uma string de formato que descreve como os dados devem ser exibidos e um conjunto de dados correspondente à string de formato.Esses dados serão colocados na string resultante de acordo com a maneira de exibi-los no log. Para cada um dos valores, é possível especificar um formato de saída distinto. Eis um esquema:

("%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)

Como podemos ver, onde quisermos exibir dados no texto, devemos ter strings de formato que descrevam como os valores dos dados devem ser exibidos. Cada string de formato é precedida por um sinal de %, que informa que a seguir está a descrição do formato de exibição. Entre as descrições de formato pode ser escrito qualquer texto (no exemplo acima, está escrito no final como "algum texto"). Depois de terminar de inserir a string com caracteres de formato e texto, os dados são colocados na ordem em que o formato de exibição foi definido na string de formato, separados por vírgula. No exemplo acima, cada descrição de formato e seu valor correspondente são marcados com a mesma cor.

Isso significa que primeiro escrevemos o texto que deve ser exibido no log. Em seguida, dentro do texto, se houver dados nesse ponto, inserimos os caracteres de formato dos dados.

Por exemplo: ("%Este texto estará em uma coluna com largura de 50 caracteres%estes dados double estarão na próxima coluna e alinhados à esquerda", variável_de_string_da_primeira_coluna, double_variável_da_segunda_coluna);

Naturalmente, para descrever tudo isso, não é necessário usar texto, pois existem caracteres de formato especiais. Eles devem estar em uma ordem estritamente definida, mas nem todos eles precisam estar presentes na string de formato.

A string de formato é lida da esquerda para a direita. Quando a primeira especificação de formato é encontrada (se houver), o valor do primeiro parâmetro após a string de formato é convertido e exibido de acordo com a especificação fornecida. A segunda especificação de formato aciona a conversão e exibição do segundo parâmetro e assim por diante, até o final da string de formato.

A especificação de formato tem a seguinte forma:

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

Vamos analisar cada um dos elementos da string de formato conforme descrito na documentação e descrever em mais detalhes.

Símbolo de porcentagem (%) - inicia uma nova string de formato. Após este símbolo, deve ser pelo menos um especificador, sendo importante entender que o especificador de tipo (type) é o único campo obrigatório para a saída formatada. Ou seja, se um '%' for inserido na string, o tipo de dados a ser exibido deve ser especificado após ele. Ou outro símbolo de porcentagem (%) pode ser inserido - para incluir um '%' no texto. Para evitar que isso inicie uma nova string de formato e, em vez disso, insira apenas o símbolo de porcentagem no texto, é necessário escrever a combinação: '%%'.

Então, os sinalizadores (flags):

  • - (sinal de menos): Indica que o texto será alinhado à esquerda dentro da largura especificada. A largura é definida pelo especificador de largura (width) que segue o sinalizador. Se você escrever "%-10", isso significa que o texto será alinhado à esquerda em um campo de 10 caracteres. O texto subsequente nesta linha será colocado a partir da extremidade direita deste mesmo campo de 10 caracteres. Se o texto dentro deste campo de 10 caracteres for maior do que 10 caracteres, o próximo texto será colocado a partir do final deste texto e não do campo. Ou seja, o campo se expande para o comprimento do texto que é colocado nele. O texto não é truncado na largura do campo, pelo contrário, o campo se expande para acomodar o comprimento do texto.
    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            
       */
      }
    
    


  • + (sinal de mais): Para tipos numéricos, o sinal + ou - será sempre exibido, dependendo do valor dos dados a serem exibidos. Por exemplo: +222 ou -12.35. Se duas linhas de texto formatado seguirem uma após a outra e na linha superior os dados a serem exibidos forem positivos, enquanto na linha inferior forem negativos, visualmente os valores serão deslocados um caractere um do outro (devido ao sinal '-'). Abaixo, será explicada um sinalizador que elimina essa inconveniência visual.
    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 são adicionados antes do valor a ser exibido, dentro da largura do campo especificada. Se o sinalizador 0 for usado com um formato de número inteiro (i, u, x, X, o, d) e uma especificação de precisão for definida (por exemplo, %04.d), o 0 será ignorado. Em outras palavras, para tipos inteiros que têm um formato de precisão definido (para exibir pelo menos tantos caracteres), os zeros líderes deste formato (formato 0) não têm prioridade, pois preenchem todo o campo, o que entra em conflito com o formato de precisão.
    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
       */
      }
    
    


  • (espaço em branco): Um espaço é colocado antes do valor a ser exibido, se o valor for numérico e positivo. Cada valor positivo deste campo com esse sinalizador é deslocado para a direita em um caractere. Isso permite alinhar visualmente os valores quando há valores positivos e negativos em uma coluna em diferentes linhas. Um espaço é inserido onde um sinal '-' apareceria para valores negativos.
    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
       */
      }
    
    


  • sinal #

    1. Se usado com os formatos o, x ou X, 0, 0x ou 0X é adicionado antes do valor exibido, respectivamente.
    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. Se usado com os formatos e, E, a ou A, o valor sempre é exibido com um ponto decimal.

    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. Quando usado com os formatos g ou G, o sinalizador determina a presença de um ponto decimal no valor exibido e impede a remoção de zeros à esquerda. O formato g escolhe a representação mais compacta entre os formatos f ou e e exibe o valor no formato escolhido. O formato G é idêntico ao formato g, mas a escolha é feita entre os formatos f e E.

    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          
       */
      }
    
    

    O sinalizador # é ignorado quando usado em conjunto com os formatos c, d, i, u ou s.


    Especificador de largura (width): número mínimo de caracteres exibidos no valor formatado. A interação do especificador com os sinalizadores foi discutida anteriormente. Há um detalhe interessante: se você usar um asterisco (*) como valor de largura, o valor a ser substituído no lugar do asterisco deve ser especificado na lista junto com os dados:

    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          
       */
      }
    
    

    Neste exemplo, a saída não é diferente da anterior, mas aqui especificamos a largura de cada campo numericamente na lista de valores. Isso é útil quando a tabela é impressa dentro de uma função à qual podemos passar os valores de largura para cada coluna da tabela, e eles serão substituídos no lugar dos asteriscos na string de formato.


    Especificador de precisão (.precision): número de dígitos após o ponto decimal. A especificação de precisão pode truncar parte do valor fracionário com ou sem arredondamento.

    Para diferentes tipos de formato (type), a especificação de precisão é aplicada de maneira diferente:

    • a, A:  indica o número de dígitos após o ponto decimal.
      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: indica o número mínimo de dígitos a serem exibidos. Se o número de dígitos no parâmetro correspondente for menor do que a precisão especificada, o valor exibido será preenchido com zeros à esquerda. O valor exibido não é truncado se o número de dígitos a serem exibidos for maior do que a precisão especificada.
      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: indica o número de dígitos a serem exibidos após o ponto decimal. O último dígito exibido é arredondado.
      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: indica o número máximo de dígitos significativos.
      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     
      
         */
        }
      
      
      É importante notar que o número máximo de dígitos significativos não se refere ao número de dígitos após o ponto decimal. Todos os dígitos do número são levados em consideração. Por exemplo, se a largura for definida como 4 e o valor de Digits() for definido como 5, você não verá quatro dígitos após o ponto decimal no valor de preço. Neste exemplo, você verá apenas três dígitos após o ponto decimal (1.273), pois o quarto dígito do número é aquele antes do ponto decimal.


    • s: O número de caracteres a serem exibidos da sequência de caracteres. Se o comprimento da sequência de caracteres exceder o valor de precisão, a sequência de caracteres será truncada na saída.
      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                  
      
         */
        }
      
      

        Especificador de tamanho de dados (h | l | ll | I32 | I64): indica o tamanho dos dados inteiros passados como parâmetro. Ao passar um número inteiro como parâmetro, podemos especificar o tamanho desses dados (int, uint, short, ushort, long, ulong). Abaixo está uma tabela de compatibilidade dos especificadores de tamanho com os tipos de dados:

        Tamanho dos dados
        Especificadores de tamanho
         Especificadores de tipo
          short   h
          d, i, o, x, X
          ushort   h
          u, o, x, X
          int
          l (L pequeno), I32
          d, i, o, x, X
          uint
          l (L pequeno), I32
          u, o, x, X
          long
          ll (dois L's pequenos), I64
          d, i, o, x, X
          ulong
          I64
          u, o, x, X


        Especificador de tipo de dados (type): único campo obrigatório para saída formatada. 

        Símbolo
         Tipo Formato
        c
        int
        Caractere de tipo short (Unicode)
        C
        int
        Caractere de tipo char (ANSI)
        d
        int
        Inteiro decimal com sinal
        i
        int
        Inteiro decimal com sinal
        o
        int
        Inteiro octal sem sinal
        u
        int
        Inteiro decimal sem sinal
        x
        int
        Inteiro hexadecimal sem sinal usando "abcdef"
        X
        int
        Inteiro hexadecimal sem sinal usando "ABCDEF"
        e
        double
        Valor de ponto flutuante no formato [ – ]d.dddd e [sign]ddd, onde d é um dígito decimal, dddd são um ou mais dígitos decimais, ddd é um número de três dígitos que determina o tamanho da exponencial, sign é um sinal de mais ou menos
        E
        double
        Idêntico ao formato e, exceto que o sinal da exponencial é exibido em maiúsculas (E em vez de e)
        f
        double
        Valor de ponto flutuante no formato [ – ]dddd.dddd, onde dddd é um ou mais dígitos decimais. O número de dígitos exibidos antes do ponto decimal depende do valor do número. O número de dígitos após o ponto decimal depende da precisão necessária.
        g
        double
        Valor de ponto flutuante exibido no formato f ou e, dependendo de qual formato é mais compacto.
        G
        double
        Valor de ponto flutuante exibido no formato f ou E, dependendo de qual formato é mais compacto.
        a
        double
        Valor de ponto flutuante no formato [−]0xh.hhhh p±dd, onde h.hhhh é a mantissa em forma de dígitos hexadecimais usando "abcdef", dd é um ou mais dígitos da exponencial. O número de dígitos após o ponto é determinado pela especificação de precisão.
        A
        double
        Valor de ponto flutuante no formato [−]0xh.hhhh P±dd, onde h.hhhh é a mantissa em forma de dígitos hexadecimais usando "ABCDEF", dd é um ou mais dígitos da exponencial. O número de dígitos após o ponto é determinado pela especificação de precisão.
        s
        string
        Saída de uma string


        O tipo de dados permite especificar como gostaríamos de obter o registro no log do terminal. Por exemplo, ao usar os tipos 'c' ou 'C', obtemos um único caractere na saída. O valor passado como parâmetro indica o código desse caractere na tabela Unicode ou ANSI, enquanto o uso desse mesmo valor com outros especificadores de tipo exibirá o próprio valor do parâmetro no formato escolhido, mas não como um caractere:

        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        
           */
          }
        
        

        Nós examinamos brevemente todos os especificadores de formatação para o texto exibido no log. Vamos ver como isso funciona em exemplos específicos de exibição das propriedades da conta de negociação.


        Formatação de exibição das propriedades da conta

        As propriedades da conta, sejam elas inteiras, de ponto flutuante ou de string, podem ser obtidas usando as funções AccountInfoInteger(), AccountInfoDouble() e AccountInfoString(), respectivamente.

        Não é sempre necessário exibir a lista completa de todas as propriedades. Por isso, criaremos uma função para cada propriedade que imprimirá a descrição dessa propriedade no log. Então, a partir das funções prontas que imprimem as descrições das propriedades no log, poderemos montar qualquer função que imprima as propriedades desejadas no log, seja todas ou apenas algumas.

        Na função, passaremos dois parâmetros: a largura do cabeçalho do campo e a margem do cabeçalho do campo em relação à margem esquerda. Começaremos em ordem: propriedades inteiras, seguidas de propriedades de ponto flutuante e, finalmente, propriedades de string.


        Funções para impressão de propriedades inteiras da conta.

        Número da conta:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        

        Na string de formato, começamos usando um asterisco para especificar a margem da linha à esquerda. Nos parâmetros da string, passamos o tamanho do campo de margem (no lugar do asterisco) e um valor de string - uma string vazia (no lugar do caractere s).
        O formato "%*s" preencherá a string vazia passada nos parâmetros com espaços de acordo com o valor da margem, também passado nos parâmetros da string. Isso torna conveniente criar qualquer campo vazio na string com o tamanho necessário, usando espaços em branco. Em seguida, na string de formato, também especificamos o tamanho do campo de cabeçalho com um asterisco, passando no lugar dele o valor da variável w e a string de cabeçalho na variável header. O último parâmetro será o valor do número da conta de AccountInfoInteger() como uma string.


        Tipo de conta:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Tamanho da alavancagem:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Número máximo de ordens:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Modo garantia mínima:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Permitir negociação para a conta:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Permitir negociação para o 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
           */
          }
        
        


        Modo de cálculo de margem:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Número de casas decimais para a moeda da conta:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Sinal de fechamento FIFO:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Permitir posições opostas por símbolo:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Funções para imprimir propriedades de ponto flutuante da conta.

        Saldo da conta:

        //+------------------------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Crédito fornecido:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Lucro atual na conta:

        //+------------------------------------------------------------------+
        //| Print a description of account credit size                       |
        //| 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
           */
          }
        
        


        Fundos próprios na conta:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Fundos de garantia reservados:

        //+------------------------------------------------------------------+
        //| Print a description of account credit size                       |
        //| 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
           */
          }
        
        


        Fundos livres disponíveis para abrir posição:

        //+----------------------------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Nível de garantia da conta em porcentagem:

        //+------------------------------------------------------------------+
        //| 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 %
           */
          }
        
        


        Nível de garantia para acionar Margin Call:

        //+----------------------------------------------------------------------------+
        //| 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 %
           */
          }
        
        


        Nível de garantia para acionar Stop Out:

        //+------------------------------------------------------------------+
        //| 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 %
           */
          }
        
        


        Quantidade reservada na conta para cobrir margem de todas as ordens pendentes:

        //+------------------------------------------------------------------+
        //|  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
           */
          }
        
        


        Quantidade mínima reservada na conta para cobrir o valor mínimo de todas as posições abertas:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Ativos totais:

        //+----------------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Quantidade de passivos:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Comissões bloqueadas:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Funções para impressão de propriedades de string da conta.

        Nome do cliente:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Nome do servidor de negociação:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        //+------------------------------------------------------------------+
        
        


        Nome da moeda do depósito:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Nome de uma empresa que atende a conta:

        //+------------------------------------------------------------------+
        //| 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.
           */
          }
        
        

        Todas as funções apresentadas acima são praticamente idênticas umas às outras. Cada uma delas permite definir o recuo da linha à esquerda e a largura do campo de cabeçalho. Os valores padrão de zero passados para as funções significam que não há recuo, e a largura do campo é igual ao tamanho do cabeçalho + 1 caractere. Assim, essas funções podem ser usadas conforme estão para imprimir as propriedades necessárias da conta no log. Mas quando for necessário criar uma função para imprimir um grupo de propriedades, será necessário definir o recuo e a largura do campo de cabeçalho para obter uma saída de valores bonita e fácil de ler no log.

        Vamos criar um exemplo de tal função que imprime todas as propriedades da conta no log.

        Função para imprimir todas as informações da conta no log:

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

        A função chama sequencialmente todas as funções que imprimem dados das propriedades da conta, na ordem em que essas propriedades estão listadas nas enumerações ENUM_ACCOUNT_INFO_INTEGER, ENUM_ACCOUNT_INFO_DOUBLE e ENUM_ACCOUNT_INFO_STRING.

        Resultado da chamada da função a partir de um script com largura de campo de cabeçalho de 20 caracteres e recuo de 2 caracteres:

        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.
           */
          }
        
        


        Tempo com milissegundos dos detalhes do tick

        A estrutura MqlTick é projetada para obter rapidamente as informações mais solicitadas sobre os preços atuais.

        Uma variável do tipo MqlTick permite obter os valores de Ask, Bid, Last e Volume com uma única chamada à função SymbolInfoTick(). Além disso, a estrutura contém o tempo do tick em milissegundos. O valor de tempo é armazenado em uma variável do tipo long. Ou seja, ao imprimir esses dados no log, simplesmente obtemos um número - a quantidade de milissegundos desde a data de 01/01/1970. Para exibir esses dados em um formato de tempo fácil de entender, é necessário converter esse número em uma data e adicionar o valor em milissegundos a essa data.

        Para obter a data com segundos, você precisa dividir a quantidade de milissegundos por 1000, e para obter os milissegundos do tempo, você precisa pegar o resto da divisão por 1000 da quantidade de milissegundos da data.

        Em geral, isso será semelhante a isto:

        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
           */
          }  
        
        


        Vamos escrever uma função que obtenha o tempo em milissegundos e o imprima no log no formato Data Hora.Ms:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Para obter a data e hora em milissegundos e imprimi-los no log diretamente, você pode usar a seguinte função:

        //+------------------------------------------------------------------+
        //| 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
           */
          }
        
        


        Considerações finais

        Nesta visão geral, examinamos as capacidades do PrintFormat() para impressão de uma string formatada e criamos exemplos de funções para imprimir propriedades da conta que podem ser usadas "como estão" em seus programas. No entanto, há outra maneira de criar saída formatada - a função StringFormat(), que, ao contrário do PrintFormat(), que imprime a string no formato desejado no log, retorna a string formatada no formato especificado. Acredito que seja mais conveniente para a saída de texto formatado, pois cria a string necessária a partir das strings de formato, que podem ser posteriormente usadas em diferentes partes do programa, e não apenas impressas no log. No próximo artigo, discutiremos o StringFormat() e examinaremos suas capacidades.


        Traduzido do russo pela MetaQuotes Ltd.
        Artigo original: https://www.mql5.com/ru/articles/12905

        Desenvolvendo um sistema de Replay (Parte 36): Ajeitando as coisas (II) Desenvolvendo um sistema de Replay (Parte 36): Ajeitando as coisas (II)
        Uma das coisas que mais pode complicar a nossa vida como programadores é o fato de supor as coisas. Neste artigo mostrarei o perigo de fazer suposições. Tanto na parte da programação em MQL5, onde você supõem que um tipo terá um dado tamanho. Assim como no uso do MetaTrader 5, onde você supõem que servidores diferentes funcionam da mesma forma.
        Teoria das Categorias em MQL5 (Parte 13): Eventos de calendário com esquemas de banco de dados Teoria das Categorias em MQL5 (Parte 13): Eventos de calendário com esquemas de banco de dados
        Neste artigo, discutimos como os esquemas de banco de dados podem ser incorporados para categorização em MQL5. Analisaremos brevemente como os conceitos de esquema de banco de dados podem ser combinados com a teoria da categoria na identificação de informações de texto (string) relevantes para a negociação. O foco será em eventos de calendário.
        StringFormat(). Visão geral, exemplos de uso prontos StringFormat(). Visão geral, exemplos de uso prontos
        O artigo é uma continuação da revisão da função PrintFormat(). Veremos brevemente a formatação de strings usando StringFormat() e seu uso posterior no programa. Escreveremos modelos para exibir informações sobre um símbolo no log do terminal. Este artigo será útil tanto para iniciantes quanto para desenvolvedores experientes.
        Relembrando a antiga estratégia de tendência: dois osciladores estocásticos, MA e Fibonacci Relembrando a antiga estratégia de tendência: dois osciladores estocásticos, MA e Fibonacci
        Estratégias de negociação tradicionais. Neste artigo, vamos explorar uma estratégia de acompanhamento de tendências. Essa abordagem é totalmente baseada em análise técnica e faz uso de vários indicadores e ferramentas para gerar sinais e identificar metas de negociação. Os elementos-chave dessa estratégia incluem um oscilador estocástico de 14 períodos, um oscilador estocástico de cinco períodos, uma média móvel de 200 períodos e uma projeção de Fibonacci (para determinar as metas de negociação).