English 中文 Español Deutsch 日本語 Português
preview
Изучаем PrintFormat() и берем готовые к использованию примеры

Изучаем PrintFormat() и берем готовые к использованию примеры

MetaTrader 5Примеры | 12 июля 2023, 12:52
931 27
Artyom Trishkin
Artyom Trishkin

Вывод значений в лог или на экран монитора является простой и привычной операцией — до тех пор, пока не понадобится вывести нечто более сложное, чем "Hello, world". Но рано или поздно возникает ситуация, когда нужно сделать форматированный вывод значения или свойства, которые не очень часто востребованы. Конечно, можно залезть в справку по MQL5 и вспомнить то, что забыл или не знал.

Но иногда хочется, чтобы где-то был готовый сборник рецептов по выводу всевозможной информации, предоставляемой терминалом MetaTrader 5. В этой cтатье мы постараемся разобрать тонкости вызова функции PrintFormat и написать готовые шаблоны, которые можно просто вставить в свой код.


Содержание


Введение

Любая программа, работающая в терминале, должна уметь сообщать пользователю о своём состоянии и состоянии своего окружения. Такие данные всегда пишутся в лог программы, который можно увидеть во вкладке торгового терминала "Эксперты". В последующем при разборе и анализе логов программы важно, чтобы все записи были в удобном для восприятия виде, ведь от этого зависит удобство чтения и поиска информации.

В языке MQL5 есть функция Print(), распечатывающая в журнал строки или же преобразованные в строку данные, в том виде, в котором они записаны в этих строках. Для краткого логирования этого вполне достаточно. Но если мы выводим в журнал большие массивы данных, то желательно, чтобы они были отформатированы в удобном для восприятия виде.

Когда заголовок данных (описание) и соответствующее ему значение написаны в одну строку без какого-либо форматирования, то в коротком списке чтение таких данных не вызовет затруднений. Другое дело, если данных много, и все они идут друг за другом и имеют разные длины описаний и значений— тогда всё это превращается в просто длинный поток информации. Такие данные желательно отформатировать и привести к единому табличному виду, где все заголовки имеют одинаковую ширину (столбец заголовков), и данные, соответствующие заголовкам, будут располагаться на единой для всех дистанции от заголовка (столбец данных). И такая возможность есть. Это функция PrintFormat(), форматирующая и печатающая наборы символов и значений в журнал экспертов в соответствии с заданным форматом.


PrintFormat(). Что это и как работает

На вход функции PrintFormat() подаётся форматная строка, описывающая в каком виде нужно выводить данные, и набор данных, соответствующих строке формата, которые и будут расположены в результирующей строке в соответствии с тем, какой для них прописан способ отображения в журнале. Для каждого из значений можно задать свой формат вывода. Схематично это выглядит так:

("%Значение1 вывести так-то%Значение2 вывести так-то%Значение3 вывести так-то ... ... %ЗначениеN вывести так-то какой-то текст", Значение1, Значение2, Значение3, ... ..., ЗначениеN)

Как видим, в том месте, где в тексте нужно вывести некие данные, там должны располагаться форматные строки с описанием способа вывода значений выводимых данных. Каждая форматная строка предваряется знаком %, который и сообщает о том, что далее идёт описание формата вывода. Между описаниями форматов можно писать любой текст (в примере выше он записан в конце как "какой-то текст"). После завершения ввода строки с форматными символами и текстом, через запятую располагаются данные в том порядке, в котором для них описан формат вывода в форматной строке. В примере выше каждое описание формата и соответствующее ему значение помечены одним и тем же цветом.

Т.е. сначала мы пишем текст, который должен быть выведен в журнал. Далее внутри текста, если в этом месте должны располагаться данные, вписываем символы формата вывода данных.

Например: ("%Этот текст будет в столбце с шириной 50 символов%эти double-данные будут в следующем столбце и выровнены по левому краю", string_переменная_с_текстом_первого_столбца, double- данные_второго_столбца);

Естественно, чтобы всё это описать, не нужен текст, а есть специальные форматные символы. Идти они должны в строго заданном порядке, но не обязательно все они должны присутствовать в строке формата.

Строка формата читается слева направо. Когда встречается первая спецификация формата (если она есть), то значение первого параметра после строки формата преобразовывается и выводится согласно заданной спецификации. Вторая спецификация формата вызывает преобразование и вывод второго параметра и так далее, до конца строки формата.

Спецификация формата имеет следующую форму:

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

Рассмотрим по каждому из пунктов форматной строки что написано в справке и опишем подробнее.

Знак процента (%) — начинает новую форматную строку. После этого значка должен быть прописан хотя бы один спецификатор, при этом важно понимать, что спецификатор типа (type) является единственным обязательным полем для форматированного вывода. Т.е., если в строку вписан знак '%', то обязательно должен после него быть указан тип выводимых в этом месте данных. Либо ещё один знак процента — чтобы в тексте прописать знак '%'. А чтобы это не было началом новой форматной строки, а просто в текст вписан знак процентов, нужно написать комбинацию: '%%'.

Итак, флаги (flags):

  • - (знак минус). Указывает на то, что текст строки будет выровнен по левому краю в пределах заданной ширины. Ширина задаётся спецификатором width, следующим за флагом. Если написано "%-10", то это означает, что текст будет выравниваться по левому краю поля, имеющего ширину 10 символов. Следующий текст в этой строке будет располагаться, начиная от правого края этого же поля в 10 символов. Если текст, выводимый в пределах этого 10-символьного поля, будет иметь размер, больше, чем 10 символов, то следующий за ним текст будет располагаться от конца этого текста, а не поля. Т.е., ширина поля будет расширена до размеров помещённого в него текста. Текст не урезается по ширине поля, наоборот — поле расширяется по длине текста.
    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком менее 10 символов и данными в 20-символьных полях
    //--- Заголовок и данные прижимаются к левому краю своего поля
       header="10символов";
       value1=10000000;
       value2=20000000;
       PrintFormat("%-10s%-20ld%-20lld",header,(int)value1,(long)value2);
       
    //--- Вторая строка с заголовком более 10 символов и данными в 20-символьных полях
    //--- Заголовок и данные прижимаются к левому краю своего поля
       header="Больше10символов";
       value1=10000000;
       value2=20000000;
       PrintFormat("%-10s%-20ld%-20lld",header,(int)value1,(long)value2);
    
       /* Пример вывода:
          10символов10000000            20000000            
          Больше10символов10000000            20000000            
       */
      }
    


  • + (знак плюс). Для знаковых типов всегда выводится знак + или - в зависимости от значения выводимых данных. Например: +222 или -12.35. Если две строки форматированного текста идут подряд, в верхней строке в одном и том же столбце данных значение выводимых данных положительное, а в нижней строке — отрицательное, то визуально значения будут сдвинуты относительно друг друга на один символ (на знак '-'). Ниже будет рассмотрен флаг, устраняющий данное визуальное неудобство.
    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные прижимаются к левому краю.
    //--- Значения данных второго поля выводятся со знаками +/-
       header="Заголовок1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%-+20ld%-20lld",header,(int)value1,(long)value2);
       
    //--- Вторая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные прижимаются к левому краю.
    //--- Значения данных второго поля выводятся со знаками +/-
       header="Заголовок2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%-+20ld%-20lld",header,(int)value1,(long)value2);
       
       /* Пример вывода:
          Заголовок1      -10000000           20000000            
          Заголовок2      +10000000           -20000000           
       */
      }
    


  • 0 (ноль). Перед выводимым значением добавляются нули в пределах заданной ширины поля. Если указан флаг 0 с целочисленным форматом (i, u, x, X, o, d) и задана спецификация точности (например, %04.d), то 0 игнорируется. Иными словами — для целочисленных типов, которым задан формат точности (выводить не менее стольких-то символов), лидирующие нули этого формата (формат 0) не имеют приоритета, так как заполняют всё поле, что противоречит формату точности.
    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные прижимаются к левому краю.
    //--- Значения данных второго поля выводятся со знаками +/-
    //--- Значения данных третьего поля прижимаются к правому краю с добавлением ведущих нулей.
       header="Заголовок1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%-+20ld%020lld",header,(int)value1,(long)value2);
       
    //--- Вторая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные второго поля прижимаются к левому краю.
    //--- Значения данных второго поля выводятся со знаками +/-
    //--- Значения данных третьего поля прижимаются к правому краю с добавлением ведущих нулей.
       header="Заголовок2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%-+20ld%020lld",header,(int)value1,(long)value2);
       
       /* Пример вывода:
          Заголовок1      -10000000           00000000000020000000
          Заголовок2      +10000000           -0000000000020000000
       */
      }
    


  • (пробел). Перед выводимым значением ставится пробел, если значение является знаковым и положительным. Каждое положительное значение данных поля с этим флагом смещается вправо на один символ. Это позволяет визуально выровнять значения, если в одном столбце в разных строках имеются положительные и отрицательные значения. Символ пробела ставится на место символа '-' данных с отрицательным значением.
    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные второго поля прижимаются к левому краю.
    //--- Значения данных третьего поля прижимаются к правому краю
    //--- Для второго и третьего поля слева добавляется пробел для положительных величин.
       header="Заголовок1";
       value1=-10000000;
       value2=20000000;
       PrintFormat("%-16s%- 20ld% 20lld",header,(int)value1,(long)value2);
       
    //--- Вторая строка с заголовком в 16-символьном поле и данными в 20-символьных полях
    //--- Заголовок и данные второго поля прижимаются к левому краю.
    //--- Значения данных третьего поля прижимаются к правому краю
    //--- Для второго и третьего поля слева добавляется пробел для положительных величин.
       header="Заголовок2";
       value1=10000000;
       value2=-20000000;
       PrintFormat("%-16s%- 20ld% 20lld",header,(int)value1,(long)value2);
       
       /* Пример вывода:
          Заголовок1      -10000000                       20000000
          Заголовок2       10000000                      -20000000
       */
      }
    


  • знак #.

    1. Если используется совместно с форматом o, x или X, то перед выводимым значением добавляется 0, 0x или 0X соответственно.
    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком и данными в 16-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся в десятичном формате
    //--- Значения данных третьего поля выводятся в восьмиричном формате с добавлением 0 перед значением
       header="Заголовок1";
       value1=10000;
       value2=10000;
       PrintFormat("%-16s(DEC) %-16ld(OCT) %-#16lo",header,(uint)value1,(uint)value2);
       
    //--- Вторая строка с заголовком и данными в 16-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся в шестнадцатеричном формате с добавлением 0x перед значением
    //--- Значения данных третьего поля выводятся в шестнадцатеричном формате с добавлением 0X перед значением
       header="Заголовок2";
       value1=10000;
       value2=10000;
       PrintFormat("%-16s(hex) %-#16lx(HEX) %-#16lX",header,(uint)value1,(uint)value2);
       
       /* Пример вывода:
          Заголовок1      (DEC) 10000           (OCT) 023420          
          Заголовок2      (hex) 0x2710          (HEX) 0X2710          
       */
      }
    


    2. Если используется совместно с форматом e, E, a или A, то значение всегда выводится с десятичной точкой.

    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'e'
    //--- Значения данных третьего поля выводятся совместно с форматом 'E'
       header="Заголовок1";
       value1=255;
       value2=1024;
       PrintFormat("%-16s(e) %-22e(E) %-#22E",header,(double)value1,(double)value2);
       
    //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'a'
    //--- Значения данных третьего поля выводятся совместно с форматом 'A'
       header="Заголовок2";
       value1=255;
       value2=1024;
       PrintFormat("%-16s(a) %-#22a(A) %-#22A",header,(double)value1,(double)value2);
       
       /* Пример вывода:
          Заголовок1      (e) 2.550000e+02          (E) 1.024000E+03          
          Заголовок2      (a) 0x1.fe00000000000p+7  (A) 0X1.0000000000000P+10 
       */
      }
    


    3. Если используется совместно с форматом g или G, флаг определяет наличие десятичной точки в выводимом значении и препятствует отсечению ведущих нулей. Формат g выбирает наиболее компактный вид записи из форматов f или e и выводит запись в выбранном формате. Формат G идентичен формату g, но выбор производится между форматами f и E.

    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'f' с точностью по умолчанию
    //--- Значения данных третьего поля выводятся совместно с форматом 'g'
       header="Заголовок1";
       value1=Point();
       value2=DBL_MAX;
       PrintFormat("%-16s(f) %-22f(g) %-#22g",header,(double)value1,(double)value2);
       
    //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'f' с точностью 5 знаков
    //--- Значения данных третьего поля выводятся совместно с форматом 'G'
       header="Заголовок2";
       value1=Point();
       value2=EMPTY_VALUE;
       PrintFormat("%-16s(f) %-#22.5f(G) %-#22G",header,(double)value1,(double)value2);
       
       /* Пример вывода:
          Заголовок1      (f) 0.000010              (g) 1.79769e+308          
          Заголовок2      (f) 0.00001               (G) 1.79769E+308          
       */
      }
    

    Флаг # игнорируется при совместном использовании с форматами c, d, i, u, s.


    Спецификатор ширины (width). Минимальное число выводимых символов отформатированного значения. Работу спецификатора совместно с флагами мы рассмотрели выше. Есть один интересный нюанс: если в качестве значения ширины указать звёздочку (знак *), то на место звёздочки должно подставляться значение, указанное в списке вместе с данными:

    void OnStart()
      {
    //--- Объявим выводимые на печать переменные
       string   header="";  // Заголовок данных
       double   value1=0;   // Первое значение
       double   value2=0;   // Второе значение
       
    //--- Первая строка с заголовком в *-символьном поле (16) и данными в *-символьных полях (22)
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'f' с точностью по умолчанию
    //--- Значения данных третьего поля выводятся совместно с форматом 'g'
       header="Заголовок1";
       value1=Point();
       value2=DBL_MAX;
       PrintFormat("%-*s(f) %-*f(g) %-#*g",16,header,22,(double)value1,22,(double)value2);
       
    //--- Вторая строка с заголовком в *-символьном поле (16) и данными в *-символьных полях (22)
    //--- Заголовок и данные всех полей прижимаются к левому краю.
    //--- Значения данных второго поля выводятся совместно с форматом 'f' с точностью 5 знаков
    //--- Значения данных третьего поля выводятся совместно с форматом 'G'
       header="Заголовок2";
       value1=Point();
       value2=EMPTY_VALUE;
       PrintFormat("%-*s(f) %-#*.5f(G) %-#*G",16,header,22,(double)value1,22,(double)value2);
       
       /* Пример вывода:
          Заголовок1      (f) 0.000010              (g) 1.79769e+308          
          Заголовок2      (f) 0.00001               (G) 1.79769E+308          
       */
      }
    

    В данном примере вывод не отличается от предыдущего, но здесь ширину каждого поля мы указываем числовым параметром в списке значений. Это удобно, если вывод таблицы осуществляется внутри функции, в которую мы можем передать значения ширины для каждой колонки таблицы, и они будут подставлены на место звёздочек в форматной строке.


    Спецификатор точности (.precision). Количество цифр после десятичной точки. Спецификация точности может отсекать часть дробного значения с округлением или без округления.

    Для разных форматных типов (type) спецификация точности применяется по-разному:

    • a, A.  Указывает количество знаков после десятичной точки.
      void OnStart()
        {
      //--- Объявим выводимые на печать переменные
         string   header="";  // Заголовок данных
         double   value1=0;   // Первое значение
         double   value2=0;   // Второе значение
         
      //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'a' с точностью по умолчанию
      //--- Значения данных третьего поля выводятся совместно с форматом 'A' с точностью по умолчанию
         header="Заголовок1";
         value1=Point();
         value2=DBL_MAX;
         PrintFormat("%-16s(a) %-22a(A) %-#22A",header,(double)value1,(double)value2);
         
      //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'a' с точностью 5 знаков
      //--- Значения данных третьего поля выводятся совместно с форматом 'A' с точностью 7 знаков
         header="Заголовок2";
         value1=Point();
         value2=EMPTY_VALUE;
         PrintFormat("%-16s(a) %-#22.5a(A) %-#22.7A",header,(double)value1,(double)value2);
         
         /* Пример вывода:
            Заголовок1      (a) 0x1.4f8b588e368f1p-17 (A ) 0X1.FFFFFFFFFFFFFP+1023
            Заголовок2      (a) 0x1.4f8b6p-17         (A) 0X2.0000000P+1023     
         */
        }
      


    • d, i, u, o, x, X. Указывает минимальное число выводимых цифр. Если количество цифр в соответствующем параметре меньше указанной точности, то выводимое значение дополняется слева нулями. Выводимое значение не обрезается, если количество выводимых цифр больше указанной точности
      void OnStart()
        {
      //--- Объявим выводимые на печать переменные
         string   header="";  // Заголовок данных
         double   value1=0;   // Первое значение
         double   value2=0;   // Второе значение
         
      //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'd' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'i' с точностью 11 знаков
         header="Заголовок1";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(d) %-22.4d(i) %-#22.11i",header,(int)value1,(int)value2);
         
      //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'u' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'o' с точностью 11 знаков
         header="Заголовок2";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(u) %-#22.4u(o) %-#22.11o",header,(double)value1,(double)value2);
         
      //--- Третья строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'x' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'X' с точностью 11 знаков
         header="Заголовок3";
         value1=INT_MAX;
         value2=INT_MAX;
         PrintFormat("%-16s(x) %-#22.4x(X) %-#22.11X",header,(double)value1,(double)value2);
         
         /* Пример вывода:
            Заголовок1      (d) 2147483647            (i) 02147483647           
            Заголовок2      (u) 4290772992            (o) 037760000000          
            Заголовок3      (x) 0xffc00000            (X) 0X000FFC00000         
         */
        }
      


    • e, E, f. Указывает число выводимых цифр после десятичной точки. Последняя выводимая цифра округляется
      void OnStart()
        {
      //--- Объявим выводимые на печать переменные
         string   header="";  // Заголовок данных
         double   value1=0;   // Первое значение
         double   value2=0;   // Второе значение
         
      //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'e' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'E' с точностью 11 знаков
         header="Заголовок1";
         value1=DBL_MAX;
         value2=DBL_MAX;
         PrintFormat("%-16s(e) %-22.4e(E) %-#22.11E",header,(double)value1,(double)value2);
         
      //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'f' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'f' с точностью 11 знаков
         header="Заголовок2";
         value1=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(f) %-#22.4f(f) %-#22.11f",header,(double)value1,(double)value2);
         
         /* Пример вывода:
            Заголовок1      (e) 1.7977e+308           (E) 1.79769313486E+308    
            Заголовок2      (f) 1.2729                (f) 1.27286000000         
         */
        }
      

    • g, G. Указывает максимальное число значимых цифр
      void OnStart()
        {
      //--- Объявим выводимые на печать переменные
         string   header="";  // Заголовок данных
         double   value1=0;   // Первое значение
         double   value2=0;   // Второе значение
         
      //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'g' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'G' с точностью 11 знаков
         header="Заголовок1";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-22.4g(G) %-#22.11G",header,(double)value1,(double)value2);
         
      //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'g' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 'G' с точностью 11 знаков
         header="Заголовок2";
         value1=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         value2=DBL_MAX;
         PrintFormat("%-16s(g) %-#22.4g(G) %-#22.11G",header,(double)value1,(double)value2);
         
         /* Пример вывода:
            Заголовок1      (g) 1.798e+308            (G) 1.2731600000          
            Заголовок2      (g) 1.273                 (G) 1.7976931349E+308     
      
         */
        }
      
      Здесь следует обратить внимание, что максимальное число значимых цифр не означает количество цифр после запятой. Здесь учитываются все цифры числа. При указанной разрядности 4 цифры, в случае со значением Digits(), равным пяти, мы не увидим в значении цены четыре цифры после запятой. В данном примере мы видим всего три цифры после запятой (1.273), так как четвёртой цифрой числа тут является цифра, стоящая перед десятичной точкой.


    • s. Количество выводимых символов строки. Если длина строки превышает значение точности, то строка усекается на выводе
      void OnStart()
        {
      //---
      
      //--- Объявим выводимые на печать переменные
         string   header="";  // Заголовок данных
         double   value1=0;   // Первое значение
         double   value2=0;   // Второе значение
         
      //--- Первая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'g' с точностью 4 знака
      //--- Значения данных третьего поля выводятся совместно с форматом 's' с точностью 11 знаков
         header="Заголовок1";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-22.4g(s) %-#22.11s",header,(double)value1,(string)value2);
         
      //--- Вторая строка с заголовком в 16-символьном поле и данными в 22-символьных полях
      //--- Заголовок и данные всех полей прижимаются к левому краю.
      //--- Значения данных второго поля выводятся совместно с форматом 'g' с точностью 5 знаков
      //--- Значения данных третьего поля выводятся совместно с форматом 's' с точностью 4 знака
         header="Заголовок2";
         value1=DBL_MAX;
         value2=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         PrintFormat("%-16s(g) %-#22.5g(s) %-#22.4s",header,(double)value1,(string)value2);
         
         /* Пример вывода:
            Заголовок1      (g) 1.798e+308            (s) 1.2872                
            Заголовок2      (g) 1.7977e+308           (s) 1.28                  
      
         */
        }
      

        Спецификатор размеров данных (h | l | ll | I32 | I64). Указывает размер целочисленных данных, передаваемых в качестве параметра. Передавая в качестве параметра некое целочисленное число, мы можем указать размер этих данных (int, uint, short, ushort, long, ulong). Ниже представлена таблица совместимости спецификаторов размера с типами данных:

        Размер данных
        Спецификаторы размера
         Спецификаторы типа
          short   h
          d, i, o, x, X
          ushort   h
          u, o, x, X
          int
          l (маленькая L), I32
          d, i, o, x, X
          uint
          l (маленькая L), I32
          u, o, x, X
          long
          ll (две маленькие L), I64
          d, i, o, x, X
          ulong
          I64
          u, o, x, X


        Спецификатор типа данных (type). Единственное обязательное поле для форматированного вывода. 

        Символ
         Тип Формат
        c
        int
        Символ типа short (Unicode)
        C
        int
        Символ типа char (ANSI)
        d
        int
        Знаковое десятичное целое
        i
        int
        Знаковое десятичное целое
        o
        int
        Беззнаковое восьмеричное целое
        u
        int
        Беззнаковое десятичное целое
        x
        int
        Беззнаковое шестнадцатеричное целое с использованием "abcdef"
        X
        int
        Беззнаковое шестнадцатеричное целое с использованием "ABCDEF"
        e
        double
        Вещественное значение в формате [ – ]d.dddd e [sign]ddd, где d – одна десятичная цифра, dddd – одна или больше десятичных цифр, ddd – трехзначное число, определяющее размер экспоненты, sign –     знак плюс или минус
        E
        double
        Идентично формату e, за исключением того, что знак экспоненты вывоится большой буквой (E вместо e)
        f
        double
        Вещественное значение в формате [ – ]dddd.dddd, где dddd – одна или больше десятичных цифр. Количество выводимых знаков перед десятичной точкой зависит от величины значения числа. Количество знаков после десятичной точки зависит от требуемой точности.
        g
        double
        Вещественное значение, выводимое в формате f или e, в зависимости от того какой вывод будет компактнее.
        G
        double
        Вещественное значение, выводимое в формате f или E, в зависимости от того какой вывод будет компактнее.
        a
        double
        Вещественное значение в формате [−]0xh.hhhh p±dd, где h.hhhh – мантисса в виде шестнадцатеричных цифр с использованием "abcdef", dd – одна или более цифр экспоненты. Количество знаков после запятой определяется спецификацией точности
        A
        double
        Вещественное значение в формате [−]0xh.hhhh P±dd, где h.hhhh – мантисса в виде шестнадцатеричных цифр с использованием "ABCDEF", dd – одна или более цифр экспоненты. Количество знаков после запятой определяется спецификацией точности
        s
        string
        Вывод строки


        Тип данных позволяет указать в каком виде мы хотим получить запись в журнале терминала. Например, при использовании типов 'c' или 'C', на выходе получаем один символ. Значение, передаваемое параметрами, указывает код этого символа в таблице Unicode или ANSI, в то время как использование этого же значения с другими спецификаторами типа отобразят само значение параметра в выбранном формате, но не символ:

        void OnStart()
          {
        //--- Объявим выводимые на печать переменные
           string   header="";  // Заголовок данных
           char     value1=0;   // Первое значение
           char     value2=0;   // Второе значение
           
        //--- Первая строка с заголовком в 16-символьном поле и данными в 10-символьных полях
        //--- Заголовок и данные всех полей прижимаются к левому краю.
        //--- Значения данных второго поля выводятся совместно с форматом 'c'
        //--- Значения данных третьего поля выводятся совместно с форматом 'C'
           header="Заголовок1";
           value1=65;
           value2=66;
           PrintFormat("%-16s(c) %-10c(C) %-10C",header,(char)value1,(char)value2);
           
        //--- Вторая строка с заголовком в 16-символьном поле и данными в 10-символьных полях
        //--- Заголовок и данные всех полей прижимаются к левому краю.
        //--- Значения данных второго поля выводятся совместно с форматом 'c'
        //--- Значения данных третьего поля выводятся совместно с форматом 'C'
           header="Заголовок2";
           value1=67;
           value2=68;
           PrintFormat("%-16s(c) %-10c(C) %-10C",header,(char)value1,(char)value2);
           
        //--- Третья строка с заголовком в 16-символьном поле и данными в 10-символьных полях
        //--- Заголовок и данные всех полей прижимаются к левому краю.
        //--- Значения данных второго поля выводятся совместно с форматом 'd'
        //--- Значения данных третьего поля выводятся совместно с форматом 'i'
           header="Заголовок3";
           value1=65;
           value2=66;
           PrintFormat("%-16s(d) %-10d(i) %-10i",header,(int)value1,(int)value2);
           
           /* Пример вывода:
              Заголовок1      (c) A         (C) B         
              Заголовок2      (c) C         (C) D         
              Заголовок3      (d) 65        (i) 66        
           */
          }
        

        Мы рассмотрели вкратце все спецификаторы форматирования выводимого в журнал текста. Рассмотрим, как это выглядит на конкретных примерах вывода свойств торгового счёта.


        Форматированный вывод свойств счёта

        Свойства счёта — целочисленные, вещественные и строковые, мы можем получить функциями AccountInfoInteger(), AccountInfoDouble() и AccountInfoString() соответственно.

        Не всегда требуется выводить полный список всех свойств. Поэтому, для каждого свойства сделаем функцию, распечатывающую описание этого свойства в журнале. А потом можно будет из готовых функций, выводящих в журнал описания свойств, собрать любую функцию, выводящую в журнал требуемые свойства — хоть все, хоть выборочно.

        В функции будем передавать два параметра — ширину поля заголовка и отступ поля заголовка от левого края. Начнём по порядку: целочисленные свойства, затем вещественные, и наконец — строковые.


        Функции для распечатки целочисленных свойств аккаунта.

        Номер счета:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание номера счета                     |
        //+------------------------------------------------------------------+
        void AccountLoginPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Login:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LOGIN));
           /* Пример вывода:
              Login: 68008618
           */
          }
        

        В форматной строке сначала указываем звёздочкой размер отступа строки от левого края. В параметрах строки передаём размер поля отступа (на место звёздочки) и строковое значение — пустую строку (на место символа s).
        И формат "%*s" дополнит пустую строку, переданную в параметрах, пробелами в соответствии со значением отступа, тоже передаваемого в параметрах строки. Таким образом удобно делать любые пустые поля в строке требуемого размера из символов "пробел". И далее в форматной строке мы так же указываем размер поля заголовка звёздочкой, передавая на её место значение переменной w и строку заголовка в переменной header. Последним же параметром у нас будет значение номера счёта из AccountInfoInteger() в виде строки.


        Тип торгового счета:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал тип торгового счета                       |
        //+------------------------------------------------------------------+
        void AccountTradeModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значение типа торгового счёта
           ENUM_ACCOUNT_TRADE_MODE trade_mode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
        //--- "Вырезаем" из строки, полученной из enum, только наименование типа торгового счёта
           string mode=StringSubstr(EnumToString(trade_mode),19);
        //--- Преобразуем символы полученной строки в нижний регистр и заменяем первую букву с маленькой на заглавную
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Trade mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Пример вывода:
              Trade mode: Demo
           */
          }
        


        Размер плеча:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера предоставленного плеча   |
        //+------------------------------------------------------------------+
        void AccountLeveragePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Leverage:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s1:%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LEVERAGE));
           /* Пример вывода:
              Leverage: 1:100
           */
          }
        


        Максимальное количество ордеров:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание максимально допустимого          |
        //| количества действующих отложенных ордеров                        |
        //+------------------------------------------------------------------+
        void AccountLimitOrdersPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Limit orders:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
           /* Пример вывода:
              Limit orders: 200
           */
          }
        


        Режим минимального уровня залоговых средств:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание режима задания минимально        |
        //| допустимого уровня залоговых средств                             |
        //+------------------------------------------------------------------+
        void AccountMarginSOModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значение режима задания минимально допустимого уровня залоговых средств
           ENUM_ACCOUNT_STOPOUT_MODE so_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
        //--- "Вырезаем" из строки, полученной из enum, только наименование режима
           string mode=StringSubstr(EnumToString(so_mode),21);
        //--- Преобразуем символы полученной строки в нижний регистр и заменяем первую букву с маленькой на заглавную
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="StopOut mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Пример вывода:
              StopOut mode: Percent
           */
          }
        


        Разрешение торговли для счета:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание                                  |
        //| разрешенности торговли для текущего счета                        |
        //+------------------------------------------------------------------+
        void AccountTradeAllowedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Trade allowed:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- В зависимости от bool-значения свойства передаём параметром строку "Yes" или "No"
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) ? "Yes" : "No"));
           /* Пример вывода:
              Trade allowed: Yes
           */
          }
        


        Разрешение торговли для эксперта:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание                                  |
        //| разрешенности торговли для эксперта                              |
        //+------------------------------------------------------------------+
        void AccountTradeExpertPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Trade expert:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- В зависимости от bool-значения свойства передаём параметром строку "Yes" или "No"
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) ? "Yes" : "No"));
           /* Пример вывода:
              Trade expert: Yes
           */
          }
        


        Режим расчета маржи:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание режима расчета маржи             |
        //+------------------------------------------------------------------+
        void AccountMarginModePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значение режима расчета маржи
           ENUM_ACCOUNT_MARGIN_MODE  margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
        //--- "Вырезаем" из строки, полученной из enum, только наименование режима
           string mode=StringSubstr(EnumToString(margin_mode),20);
        //--- Преобразуем символы полученной строки в нижний регистр и заменяем первую букву с маленькой на заглавную
           if(mode.Lower())
              mode.SetChar(0,ushort(mode.GetChar(0)-0x20));
        //--- Заменяем в полученной строке все символы подчёркивания на символ пробела
           StringReplace(mode,"_"," ");
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin mode:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,mode);
           /* Пример вывода:
              Margin mode: Retail hedging
           */
          }
        


        Количество знаков после запятой для валюты счета:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание количества                       |
        //| знаков после запятой для валюты счета                            |
        //+------------------------------------------------------------------+
        void AccountCurrencyDigitsPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Currency digits:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,(string)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS));
           /* Пример вывода:
              Currency digits: 2
           */
          }
        


        Признак закрытия по правилу FIFO:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание признака того,                   |
        //| что позиции можно закрывать только по правилу FIFO               |
        //+------------------------------------------------------------------+
        void AccountFIFOClosePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="FIFO close:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- В зависимости от bool-значения свойства передаём параметром строку "Yes" или "No"
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_FIFO_CLOSE) ? "Yes" : "No"));
           /* Пример вывода:
              FIFO close: No
           */
          }
        


        Разрешение встречных позиций по одному символу:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание признака того,                   |
        //| что разрешены встречные позиции по одному символу                |
        //+------------------------------------------------------------------+
        void AccountHedgeAllowedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Hedge allowed:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- В зависимости от bool-значения свойства передаём параметром строку "Yes" или "No"
           PrintFormat("%*s%-*s%-s",indent,"",w,header,((bool)AccountInfoInteger(ACCOUNT_HEDGE_ALLOWED) ? "Yes" : "No"));
           /* Пример вывода:
              Hedge allowed: Yes
           */
          }
        


        Функции для распечатки вещественных свойств аккаунта.

        Баланс счета:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание баланса счета в валюте депозита  |
        //+------------------------------------------------------------------+
        void AccountBalancePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения баланса, количества знаков после запятой для символа и его наименование
           double ballance=AccountInfoDouble(ACCOUNT_BALANCE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Balance:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,ballance,currency);
           /* Пример вывода:
              Balance: 10015.00 USD
           */
          }
        


        Предоставленный кредит:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера                          |
        //| предоставленного кредита в валюте депозита                       |
        //+------------------------------------------------------------------+
        void AccountCreditPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения кредита, количества знаков после запятой для символа и его наименование
           double credit=AccountInfoDouble(ACCOUNT_CREDIT);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Credit:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,credit,currency);
           /* Пример вывода:
              Credit: 0.00 USD
           */
          }
        


        Текущая прибыль на счете:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера                          |
        //| текущей прибыли на счете в валюте депозита                       |
        //+------------------------------------------------------------------+
        void AccountProfitPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения текущей прибыли, количества знаков после запятой для символа и его наименование
           double profit=AccountInfoDouble(ACCOUNT_PROFIT);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Profit:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,profit,currency);
           /* Пример вывода:
              Profit: 0.00 USD
           */
          }
        


        Собственные средства на счете:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание значения                         |
        //| собственных средств на счете в валюте депозита                   |
        //+------------------------------------------------------------------+
        void AccountEquityPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения собственных средств, количества знаков после запятой для символа и его наименование
           double equity=AccountInfoDouble(ACCOUNT_EQUITY);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Equity:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,equity,currency);
           /* Пример вывода:
              Equity: 10015.00 USD
           */
          }
        


        Зарезервированные залоговые средства:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера                          |
        //| зарезервированных залоговых средств на счете в валюте депозита   |
        //+------------------------------------------------------------------+
        void AccountMarginPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения зарезервированных залоговых средств, количества знаков после запятой для символа и его наименование
           double margin=AccountInfoDouble(ACCOUNT_MARGIN);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin,currency);
           /* Пример вывода:
              Margin: 0.00 USD
           */
          }
        


        Доступные свободные средства для открытия позиции:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера свободных средств        |
        //| на счете в валюте депозита, доступных для открытия позиции       |
        //+------------------------------------------------------------------+
        void AccountMarginFreePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения зарезервированных залоговых средств, количества знаков после запятой для символа и его наименование
           double margin_free=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin free:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_free,currency);
           /* Пример вывода:
              Margin free: 10015.00 USD
           */
          }
        


        Уровень залоговых средств на счете в процентах:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание                                  |
        //| уровня залоговых средств на счете в процентах                    |
        //+------------------------------------------------------------------+
        void AccountMarginLevelPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin level:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Значение пишем с digits, равным 2 и указываем, что свойство отображается в процентах
           PrintFormat("%*s%-*s%-.2f %%",indent,"",w,header,AccountInfoDouble(ACCOUNT_MARGIN_LEVEL));
           /* Пример вывода:
              Margin level: 0.00 %
           */
          }
        


        Уровень залоговых средств для наступления Margin Call:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание уровня залоговых средств,        |
        //| при котором требуется пополнение счета (Margin Call)             |
        //+------------------------------------------------------------------+
        void AccountMarginSOCallPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения уровня залоговых средств для MarginCall, количества знаков после запятой для символа и его наименование
           double margin_so_call=AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Если уровень залоговых средств для MarginCall считается в процентах,
        //--- указываем значение currency не в валюте счёта, а в процентах, и digits будет равным 2
           if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT)
             {
              currency="%";
              digits=2;
             }
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin Call:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке полученное выше значение digits
           PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_call,currency);
           /* Пример вывода:
              Margin Call: 50.00 %
           */
          }
        


        Уровень залоговых средств для наступления Stop Out:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание уровня залоговых средств,        |
        //| при достижении которого происходит принудительное закрытие       |
        //| самой убыточной позиции (Stop Out)                               |
        //+------------------------------------------------------------------+
        void AccountMarginStopOutPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения уровня залоговых средств для StopOut, количества знаков после запятой для символа и его наименование
           double margin_so_so=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Если уровень залоговых средств для StopOut считается в процентах,
        //--- указываем значение currency не в валюте счёта, а в процентах, и digits будет равным 2
           if(AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)==ACCOUNT_STOPOUT_MODE_PERCENT)
             {
              currency="%";
              digits=2;
             }
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin Stop Out:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке полученное выше значение digits
           PrintFormat("%*s%-*s%-.*f %s",indent,"",w,header,digits,margin_so_so,currency);
           /* Пример вывода:
              Margin Stop Out: 30.00 %
           */
          }
        


        Резерв средств для обеспечения гарантийной суммы по всем отложенным ордерам:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера средств,                 |
        //| зарезервированных на счёте, для обеспечения                      |
        //| гарантийной суммы по всем отложенным ордерам                     |
        //+------------------------------------------------------------------+
        void AccountMarginInitialPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения размера средств, зарезервированных на счёте, количества знаков после запятой для символа и его наименование
           double margin_initial=AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin initial:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_initial,currency);
           /* Пример вывода:
              Margin initial: 0.00 USD
           */
          }
        


        Резерв средств для обеспечения минимальной суммы по всем открытым позициям:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание размера средств,                 |
        //| зарезервированных на счёте, для обеспечения                      |
        //| минимальной суммы по всем открытым позициям                      |
        //+------------------------------------------------------------------+
        void AccountMarginMaintenancePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения размера средств, зарезервированных на счёте, количества знаков после запятой для символа и его наименование
           double margin_maintenance=AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Margin maintenance:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,margin_maintenance,currency);
           /* Пример вывода:
              Margin maintenance: 0.00 USD
           */
          }
        


        Размер активов:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание текущего размера активов на счёте|
        //+------------------------------------------------------------------+
        void AccountAssetsPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения текущего размера активов на счёте, количества знаков после запятой для символа и его наименование
           double assets=AccountInfoDouble(ACCOUNT_ASSETS);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Assets:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,assets,currency);
           /* Пример вывода:
              Assets: 0.00 USD
           */
          }
        


        Размер обязательств:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание                                  |
        //| текущего размера обязательств на счёте                           |
        //+------------------------------------------------------------------+
        void AccountLiabilitiesPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения текущего размера обязательств на счёте, количества знаков после запятой для символа и его наименование
           double liabilities=AccountInfoDouble(ACCOUNT_LIABILITIES);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Liabilities:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,liabilities,currency);
           /* Пример вывода:
              Liabilities: 0.00 USD
           */
          }
        


        Сумма заблокированных комиссий:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание                                  |
        //| текущей суммы заблокированных комиссий по счёту                  |
        //+------------------------------------------------------------------+
        void AccountComissionBlockedPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Получаем значения текущей суммы заблокированных комиссий по счёту, количества знаков после запятой для символа и его наименование
           double commission_blocked=AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);
           int digits=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
           string currency=AccountInfoString(ACCOUNT_CURRENCY);
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Comission blocked:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
        //--- Для корректного отображения значения передаём на место звёздочки в форматной строке значение digits для символа
           PrintFormat("%*s%-*s%-.*f %-s",indent,"",w,header,digits,commission_blocked,currency);
           /* Пример вывода:
              Comission blocked: 0.00 USD
           */
          }
        


        Функции для распечатки строковых свойств аккаунта.

        Имя клиента:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание имени клиента                    |
        //+------------------------------------------------------------------+
        void AccountNamePrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Name:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_NAME));
           /* Пример вывода:
              Name: Artem
           */
          }
        


        Имя торгового сервера:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание имени торгового сервера          |
        //+------------------------------------------------------------------+
        void AccountServerPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Server:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_SERVER));
           /* Пример вывода:
              Server: MetaQuotes-Demo
           */
          }
        //+------------------------------------------------------------------+
        


        Наименование валюты депозита:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание валюты депозита                  |
        //+------------------------------------------------------------------+
        void AccountCurrencyPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Currency:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_CURRENCY));
           /* Пример вывода:
              Currency: USD
           */
          }
        


        Имя компании, обслуживающей счет:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал описание имени компании,                  |
        //| обслуживающей счет                                               |
        //+------------------------------------------------------------------+
        void AccountCompanyPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Company:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение свойства с заголовком с нужной шириной и отступом
           PrintFormat("%*s%-*s%-s",indent,"",w,header,AccountInfoString(ACCOUNT_COMPANY));
           /* Пример вывода:
              Company: MetaQuotes Software Corp.
           */
          }
        

        Все представленные выше функции практически идентичны друг другу. У каждой есть возможность задать величины отступа строки от левого края и ширины поля заголовка. Нулевые значения по умолчанию, передаваемые в функции, означают, что отступа нет, а ширина поля равна размеру строки заголовка + 1 символ. Таким образом, эти функции можно использовать как есть для вывода требуемых свойств аккаунта в журнал. Но когда нужно будет создать функцию для вывода группы свойств — вот тогда и потребуются отступ и ширина поля заголовка — для красивого и удобного для чтения вывода значений в журнал.

        Создадим пример такой функции, выводящий все свойства аккаунта в журнал.

        Функция, распечатывающая в журнал все данные аккаунта:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал данные аккаунта                           |
        //+------------------------------------------------------------------+
        void AccountInfoPrint(const uint header_width=0,const uint indent=0)
          {
        //--- Выводим в журнал описания целочисленных свойств в порядке их расположения в 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);
        //--- Выводим в журнал описания вещественных свойств в порядке их расположения в 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);
        //--- Выводим в журнал описания строковых свойств в порядке их расположения в ENUM_ACCOUNT_INFO_STRING
           Print("AccountInfoString properties:");
           AccountNamePrint(header_width,indent);
           AccountServerPrint(header_width,indent);
           AccountCurrencyPrint(header_width,indent);
           AccountCompanyPrint(header_width,indent);
          }
        

        Функция вызывает подряд все функции, распечатывающие данные свойств аккаунта, в порядке следования этих свойств в перечислениях ENUM_ACCOUNT_INFO_INTEGER, ENUM_ACCOUNT_INFO_DOUBLE и ENUM_ACCOUNT_INFO_STRING.

        Результат вызова функции из скрипта с шириной поля заголовка 20 символов и отступом 2 символа:

        void OnStart()
          {
        //--- Распечатываем в журнале свойства торгового счёта
           AccountInfoPrint(20,2);
           /* Пример вывода:
              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.
           */
          }
        


        Время с миллисекундами из свойств тика

        Структура  MqlTick  предназначена для быстрого получения наиболее востребованной информации о текущих ценах.

        Переменная типа MqlTick позволяет за один вызов функции SymbolInfoTick() получить значения Ask, Bid, Last и Volume. Кроме того, в структуре содержится время тика в миллисекундах. Значение времени отдаётся в переменной с типом long. Т.е., при распечатке этих данных в журнале, мы просто получим некое число — количество миллисекунд, прошедшее с даты 01.01.1970. Чтобы вывести эти данные в удобном для восприятия формате времени, необходимо преобразовать это число в дату и добавить к полученной дате значение миллисекунд.

        Для получения даты с секундами нужно количество миллисекунд разделить на 1000, а для получения миллисекунд времени нужно взять остаток от деления на 1000 количества миллисекунд даты.

        В общем случае это будет выглядеть так:

        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);
             }
           /* Пример вывода:
              time_str=2023.07.10 18:49:36.463
           */
          }  
        


        Напишем функцию, получающую время в миллисекундах, и выводящую в журнал время в формате Date Time.Msc:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал время в формате Date Time.Msc             |
        //+------------------------------------------------------------------+
        void TimeMSCPrint(const long time_msc,const uint header_width=0,const uint indent=0)
          {
        //--- Определяем текст заголовка и ширину поля заголовка
        //--- Если ширина заголовка передана в функцию равной нулю, то шириной будет размер строки заголовка + 1
           string header="Time msc:";
           uint w=(header_width==0 ? header.Length()+1 : header_width);
        //--- Распечатываем в журнале значение даты и времени с заголовком с нужной шириной и отступом, миллисекунды с точностью 3 знака
           PrintFormat("%*s%-*s%-s.%.3lu",indent,"",w,header,string((datetime)time_msc / 1000),time_msc % 1000);
           /* Пример вывода:
              Time msc: 2023.07.10 19:49:05.233
           */
          }
        


        Для непосредственного получения даты и времени в миллисекундах и вывода его в журнал, можно использовать такую функцию:

        //+------------------------------------------------------------------+
        //| Распечатывает в журнал время в формате Date Time.Msc по символу  |
        //+------------------------------------------------------------------+
        void TimeMSCPrint(const string symbol,const uint header_width=0,const uint indent=0)
          {
        //--- Получаем время из тика
           MqlTick tick;
           if(!SymbolInfoTick(symbol,tick))
             {
              Print(__FUNCTION__,": SymbolInfoTick error: ",(string)GetLastError());
              return;
             }
        //--- Распечатываем время в миллисекундах при помощи первого варианта функции
           TimeMSCPrint(tick.time_msc,header_width,indent);
           /* Пример вывода:
              Time msc: 2023.07.10 20:07:08.202
           */
          }
        


        Заключение

        В этом обзоре мы рассмотрели возможности PrintFormat() для вывода на печать форматированной строки и создали примеры функций для распечатки свойств счёта, которые можно использовать "как есть" в своих программах. Но есть ещё один способ создания форматированного вывода — функция StringFormat(), которая в отличие от PrintFormat(), печатающей в журнал строку в нужном формате, возвращает форматированную строку в заданном формате. Считаю её более удобной для вывода форматированного текста, так как она создаёт из форматных строк нужную строку, которую далее можно использовать в разных местах программы, а не просто выводить в журнал. В следующей статье поговорим о StringFormat() и рассмотрим её возможности.


        Последние комментарии | Перейти к обсуждению на форуме трейдеров (27)
        lynxntech
        lynxntech | 12 авг. 2023 в 12:42
        Artyom Trishkin #:

        Спасибо

        объем информации огромный для вывода текстов,

        будье готовы к большому кол-ву вопросов в использовании

        как ни пытался, так и не понял как работает printformat

        Alexey Viktorov
        Alexey Viktorov | 12 авг. 2023 в 12:48
        lynxntech #:

        объем информации огромный для вывода текстов,

        будье готовы к большому кол-ву вопросов в использовании

        как ни пытался, так и не понял как работает printformat

        Не будет так много как вы думаете. Таких как Федосеев достаточно много

        lynxntech
        lynxntech | 12 авг. 2023 в 14:28
        Alexey Viktorov #:

        Не будет так много как вы думаете. Таких как Федосеев достаточно много


        именно про это и сказал тут, большим дураком надо быть, что-бы охватить этот большой объем для просто личной информации

        в очередной раз MQ виню за просто бездарное использование.

        --

        знаю что это пошло от C++

        какое это имеет значение в торговле?, такую срань добавить

        Artyom Trishkin
        Artyom Trishkin | 12 авг. 2023 в 14:51
        lynxntech #:

        именно про это и сказал тут, большим дураком надо быть, что-бы охватить этот большой объем для просто личной информации

        в очередной раз MQ виню за просто бездарное использование.

        --

        знаю что это пошло от C++

        какое это имеет значение в торговле?, такую срань добавить

        Это имеет значение для удобного структурированного вывода информации.

        Если Вам не нужно, просто сваливайте информацию в большую кучу и разбирайтесь потом часами.

        А кому-то удобно видеть всё аккуратно "разложенным по полочкам".

        А кому-то нужно иметь "резиновый" график. А какое это имеет отношение к торговле?

        В общем, спор остроконечников с тупоконечниками.

        lynxntech
        lynxntech | 12 авг. 2023 в 15:02
        Artyom Trishkin #:

        Это имеет значение для удобного структурированного вывода информации.

        Если Вам не нужно, просто сваливайте информацию в большую кучу и разбирайтесь потом часами.

        А кому-то удобно видеть всё аккуратно "разложенным по полочкам".

        А кому-то нужно иметь "резиновый" график. А какое это имеет отношение к торговле?

        В общем, спор остроконечников с тупоконечниками.

        Артем, то что вы умеете, хорошо

        когда заходишь в Справку, а там вместо 20 страниц полезных, 50

        Разработка системы репликации - Моделирование рынка (Часть 03):  Внесение корректировок (I) Разработка системы репликации - Моделирование рынка (Часть 03): Внесение корректировок (I)
        Начнем с прояснения нынешней ситуации, потому что мы начали не самым лучшим образом. Если не сделать этого сейчас, то вскоре мы окажемся в беде.
        Нейросети — это просто (Часть 48): Методы снижения переоценки значений Q-функции Нейросети — это просто (Часть 48): Методы снижения переоценки значений Q-функции
        В предыдущей статье мы познакомились с методом DDPG, который позволяет обучать модели в непрерывном пространстве действий. Однако, как и другие методы Q-обучения, DDPG склонен к переоценки значений Q-функции. Эта проблема часто приводит к обучению агента с неоптимальной стратегией. В данной статье мы рассмотрим некоторые подходы преодоления упомянутой проблемы.
        Нейросети — это просто (Часть 49): Мягкий Актор-Критик (Soft Actor-Critic) Нейросети — это просто (Часть 49): Мягкий Актор-Критик (Soft Actor-Critic)
        Мы продолжаем рассмотрение алгоритмов обучения с подкреплением в решении задач непрерывного пространства действий. И в данной статье предлагаю познакомиться с алгоритмом Soft Аctor-Critic (SAC). Основное преимущество SAC заключается в способности находить оптимальные политики, которые не только максимизируют ожидаемую награду, но и имеют максимальную энтропию (разнообразие) действий.
        Теория категорий в MQL5 (Часть 8): Моноиды Теория категорий в MQL5 (Часть 8): Моноиды
        Статья продолжает серию о реализации теории категорий в MQL5. Здесь мы вводим моноиды как домен (множество), который отличает теорию категорий от других методов классификации данных за счет включения правил и элемента равнозначности.