English Русский 中文 Español 日本語 Português
preview
Strukturen in MQL5 und Methoden zum Drucken deren Daten

Strukturen in MQL5 und Methoden zum Drucken deren Daten

MetaTrader 5Beispiele | 22 November 2023, 09:40
238 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Einführung

Die Struktur ist ein praktisches Werkzeug zum Speichern, Aufzeichnen und Abrufen logisch zusammenhängender Daten, die zu einer beliebigen Definition gehören, aus einer einzigen Variablen.

MQL5 verfügt über 12 vordefinierte Strukturen zur Speicherung und Übermittlung von Serviceinformationen:

Die Strukturen MqlParam und MqlTradeRequest übermitteln technische Informationen zur Erstellung von Indikatoren und zum Senden von Handelsaufträgen an den Server. Wir füllen die erforderlichen Felder der Strukturen entsprechend dem gewünschten Ergebnis der Datenübermittlung in der ausgefüllten Struktur aus. Mit anderen Worten, diese Strukturen müssen nicht unbedingt die Daten ausgeben, die den Feldern dieser Strukturen von einem Programmierer zugewiesen wurden.
Die übrigen Strukturen liefern jedoch Abfrageergebnisse, und jedes Feld wird entweder vom Terminal-Subsystem oder vom Handelsserver ausgefüllt. Das Abrufen von Daten aus diesen Strukturen, das Analysieren von programmatisch gefüllten Feldern von Strukturen oder das Ausdrucken in ein Protokoll für eine anschließende manuelle Analyse ist sehr praktisch und notwendig, um sowohl programmatische Entscheidungen zu treffen als auch den Ort eines logischen Fehlers zu verstehen und zu finden.

Um alle Felder einer Struktur auszudrucken, gibt es die Standardfunktion ArrayPrint(), die die im Array enthaltenen Daten mit dem Typ der behandelten Struktur in einem praktischen Tabellenformat anzeigt. Aber manchmal müssen wir die Daten aus der Struktur in einem anderen Format ausgeben, das vielleicht bequemer ist als eine tabellarische Darstellung. So kann es beispielsweise erforderlich sein, alle Felder der Struktur in einer Zeile anzuzeigen - mit Überschriften und entsprechenden Daten. Dies kann sich bei der Analyse großer Datenmengen als vorteilhaft erweisen. Gleichzeitig benötigen wir manchmal eine detailliertere Ansicht - mit einer Beschreibung der Strukturfelder und einer anderen Darstellung der entsprechenden Daten.

In diesem Artikel werden wir uns mit den Standardwerkzeugen für die Anzeige von Strukturdaten befassen und nutzerdefinierte Funktionen für verschiedene Darstellungen von Strukturdaten im Journal-Log erstellen.


Die Struktur MqlDateTime

Die Datenstruktur enthält acht Felder vom Typ int.

struct MqlDateTime
  {
   int year;           // year
   int mon;            // month
   int day;            // day
   int hour;           // hour
   int min;            // minutes
   int sec;            // seconds
   int day_of_week;    // day of the week (0-Sunday, 1-Monday, ... ,6-Saturday)
   int day_of_year;    // number of a day in the year (1st of January has number 0)
  };

Die Standardfunktionen TimeCurrent(), TimeGMT(), TimeLocal(), TimeTradeServer() und TimeToStruct() werden zum Ausfüllen der Strukturfelder verwendet.

Die ersten vier Funktionen geben nicht nur das aktuelle Datum, das GMT-Datum, die lokale Computerzeit und das Datum des Handelsservers zurück, sondern haben auch jeweils eine Überladung. In den Formalparametern der Funktion können wir ihr eine Datumsstruktur per Referenz übergeben. Nach Ausführung der Funktion werden die an die Funktion übergebenen Strukturfelder mit den von der Funktion zurückgegebenen Datumsdaten gefüllt.

Die Funktion TimeToStruct() wurde speziell entwickelt, um eine Struktur vom Typ datetime (Anzahl der Sekunden seit dem 01.01.1970) der Variablen vom Typ MqlDateTime zuzuweisen.

bool  TimeToStruct(
   datetime      dt,            // date and time
   MqlDateTime&  dt_struct      // structure for accepting values 
   );

Bei Erfolg wird true zurückgegeben, andernfalls false. Nach der Operation sind der Datumsstruktur die Zeitdaten zugewiesen worden, der ersten Parameter ist eine Variable mit dem Typ datetime.

Unsere Datumsstruktur ist vollständig, aber wie können wir sie ausdrucken? Es gibt eine Standardfunktion TimeToString(), die einen Wert, der die Zeit in Sekunden seit dem 01.01.1970 enthält, in eine Zeichenkette im Format „yyyy.mm.dd hh:min:sec“ umwandelt.

Die Funktion funktioniert jedoch nicht mit der MqlDateTime-Struktur, sondern mit einem Datetime-Datum. Sollten wir die Struktur also wieder in einen Zeitwert umwandeln? Nein, natürlich nicht. Jede der Funktionen ist für ihre eigenen Zwecke bestimmt. Wir können jede Komponente des Datums und der Uhrzeit separat aus der Datumsstruktur entnehmen - ein Jahr, einen Monat, eine Stunde, eine Minute, einen Wochentag usw... Aber wie können wir alle Daten der Struktur anzeigen?
Die Funktion ArrayPrint(), die ein Array eines einfachen Typs oder einer einfachen Struktur protokolliert, ist für diese Aufgabe geeignet. Sie zeigt Daten in Form einer Tabelle an, wobei die Spalten die Felder der Struktur und die Zeilen die Array-Zellen darstellen. Mit anderen Worten: Um die Struktur eines einzigen Datums anzuzeigen, benötigen wir ein Array von 1. Für eine Handelswoche beträgt die Array-Größe in der Regel 5 Handelstage, vorausgesetzt, die Daten stammen aus dem D1-Chart.


Druckmethoden für MqlDateTime

Ein solches Skript gibt eine Datumsstruktur aus, die mit ArrayPrint() aus der aktuellen Zeit im Journal ermittelt wurde:

void OnStart()
  {
//--- Declare a date structure variable
   MqlDateTime  time;
//--- Get the current time and at the same time fill in the date structure
   TimeCurrent(time);
//--- Declare an array with the MqlDateTime type and write the data of the filled structure into it

   MqlDateTime array[1];
   array[0]=time;
//--- Display the header and time using the standard ArrayPrint()
   Print("Time current (ArrayPrint):");
   ArrayPrint(array);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }

Die Funktion, die eine Datumsstruktur aufnimmt und im Journal ausgibt, sieht dementsprechend wie folgt aus:

//+------------------------------------------------------------------+
//| Take a date structure and display its data to the journal.       |
//| Use ArrayPrint() for display                                     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(const MqlDateTime& time_struct)
  {
//--- Declare an array with the MqlDateTime type and write the data of the obtained structure into it
   MqlDateTime array[1];
   array[0]=time_struct;
//--- Print the array
   ArrayPrint(array);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }

Die Funktion ermöglicht den Ausdruck eines in der Variablen time_struct übergebenen Datums im Journal.

Das Skript, das eine einzelne Datumsstruktur mit der oben vorgestellten Funktion protokolliert:

void OnStart()
  {
//--- Declare a date structure variable
   MqlDateTime  time;
//--- Get the current time and at the same time fill in the date structure
   TimeCurrent(time);
//--- Display the header and time using the standard ArrayPrint()
   Print("Time current (ArrayPrint):");
   MqlDateTimePrint(time);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }


Wenn wir ein Array mit Daten ausdrucken müssen (was ja das Hauptziel von ArrayPrint() ist), dann müssen wir das Datenarray an die Funktion datetime übergeben, das MqlDateTime-Array ausfüllen und ausdrucken.

Die Funktion, die das Array datetime übernimmt und das MqlDateTime-Array ausgibt:

//+------------------------------------------------------------------+
//| Accept the datetime array, convert it into MqlDateTime and       |
//| display converted data into the journal.                         |
//| Use ArrayPrint() for display                                     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(const datetime& array_time[])
  {
//--- Declare a dynamic array of the MqlDateTime type
   MqlDateTime array_struct[];
//--- Get the size of the array passed to the function
   int total=(int)array_time.Size();
//--- If an empty array is passed, report on that and leave the function
   if(total==0)
     {
      PrintFormat("%s: Error. Empty array.",__FUNCTION__);
      return;
     }
//--- Change the size of the MqlDateTime array to match the size of the datetime array
   ResetLastError();
   if(ArrayResize(array_struct,total)!=total)
     {
      PrintFormat("%s: ArrayResize() failed. Error %s",__FUNCTION__,(string)GetLastError());
      return;
     }
//--- Convert dates from the datetime array into the date structure in the MqlDateTime array
   for(int i=0;i<total;i++)
     {
      ResetLastError();
      if(!TimeToStruct(array_time[i],array_struct[i]))
         PrintFormat("%s: [%s] TimeToStruct() failed. Error %s",__FUNCTION__,(string)i,(string)GetLastError());
     }
//--- Print the filled MqlDateTime array
   ArrayPrint(array_struct);
   /* Sample output:
      Time data of the last 10 bars GBPUSD H1 (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17      7     0     0             1           197
      [1]   2023     7    17      8     0     0             1           197
      [2]   2023     7    17      9     0     0             1           197
      [3]   2023     7    17     10     0     0             1           197
      [4]   2023     7    17     11     0     0             1           197
      [5]   2023     7    17     12     0     0             1           197
      [6]   2023     7    17     13     0     0             1           197
      [7]   2023     7    17     14     0     0             1           197
      [8]   2023     7    17     15     0     0             1           197
      [9]   2023     7    17     16     0     0             1           197
   */
  }


Dementsprechend sieht das Skript, das die obige Funktion verwendet, um das Array datetime im Journal auszudrucken, wie folgt aus:

void OnStart()
  {
//--- Declare a time array
   datetime array[];
//--- Copy the time of the last 10 bars to the array
   ResetLastError();
   if(CopyTime(Symbol(),Period(),0,10,array)<0)
     {
      PrintFormat("CopyTime() failed. Error %s",(string)GetLastError());
      return;
     }
//--- Display the header and the time data array of the last 10 bars using the standard ArrayPrint()
   PrintFormat("Time data of the last 10 bars %s %s (ArrayPrint):",Symbol(),StringSubstr(EnumToString(Period()),7));
   MqlDateTimePrint(array);
   /* Sample output:
      Time data of the last 10 bars GBPUSD H1 (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17      7     0     0             1           197
      [1]   2023     7    17      8     0     0             1           197
      [2]   2023     7    17      9     0     0             1           197
      [3]   2023     7    17     10     0     0             1           197
      [4]   2023     7    17     11     0     0             1           197
      [5]   2023     7    17     12     0     0             1           197
      [6]   2023     7    17     13     0     0             1           197
      [7]   2023     7    17     14     0     0             1           197
      [8]   2023     7    17     15     0     0             1           197
      [9]   2023     7    17     16     0     0             1           197
   */
  }


Funktionen für die Arbeit mit MqlDateTime-Strukturdaten.

Alles, was oben getestet wurde, ist bequem, praktisch und übersichtlich. Manchmal sind jedoch umfassendere Informationen erforderlich, und zwar vorzugsweise in derselben knappen Darstellung. Oder aber wir brauchen eine detailliertere Beschreibung, indem wir die Kürze und Trockenheit der Datenpräsentation verringern. Zum Beispiel kann eine Tageszahl allein schon verwirrend sein. Wenn aber „Do.“ geschrieben wird, dann verstehen wir sofort, dass es sich um den Donnerstag handelt. Das Gleiche gilt für eine Monatsnummer - manchmal ist es besser, „07 (Juli)“ zu sehen, als sich daran zu erinnern, welcher Monat an siebter Stelle steht... Das mag natürlich übertrieben sein, aber solche kleinen Verbesserungen sind doch sehr praktisch. Diese kleinen Annehmlichkeiten summieren sich zu einem spürbaren Zeitgewinn bei der Analyse großer Mengen von Einträgen in den Programmprotokollen.

Um solche Annehmlichkeiten hinzuzufügen, müssen wir eine eigene Funktion schreiben, die eine Beschreibung des Datums im MqlDateTime-Format zurückgibt.

Die Funktion wird:

  1. Daten in einem Kurzformat anzeigen (Wochentag, Monat, Tag, Jahr, Uhrzeit);
  2. Daten in einer Tabellenansicht anzeigen (Datenkopfwert);

Bevor wir mit der Erstellung von Funktionen zur Rückgabe von Beschreibungen von Strukturfeldern beginnen, werden wir Hilfsfunktionen erstellen, die die Namen von Wochentagen und Monaten zurückgeben.

Zusatzfunktionen

Um den Namen eines Wochentags zu erhalten, schreiben wir eine einfache Funktion, die den Text des Wochentags in Abhängigkeit vom Wert im Strukturfeld zurückgibt, in dem der Wochentag im numerischen Format gespeichert ist:

//+------------------------------------------------------------------+
//| Return the name of a week day                                    |
//+------------------------------------------------------------------+
string DayWeek(MqlDateTime &date_time)
  {
//--- Define a week day name
   string dw=EnumToString((ENUM_DAY_OF_WEEK)date_time.day_of_week);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital
   if(dw.Lower())
      dw.SetChar(0,ushort(dw.GetChar(0)-0x20));
//--- Return a resulting string
   return dw;
   /* Sample output:
      Wednesday
   */
  }

Da MQL5 eine Liste mit Wochentagsnamen hat, verwenden wir hier die Zeichen-Darstellung des Enumerationswertes. Um sicherzustellen, dass der Text korrekt erscheint, werden alle Zeichen in der Zeile in Kleinbuchstaben umgewandelt, mit Ausnahme des ersten Buchstabens des Wortes.

Um den Namen eines Monats zu erhalten, schreiben wir eine einfache Funktion, die den Text eines Monats in Abhängigkeit vom Wert im Strukturfeld zurückgibt, das den Monat im numerischen Format speichert:

//+------------------------------------------------------------------+
//| Return a month name                                              |
//+------------------------------------------------------------------+
string Month(MqlDateTime &date_time)
  {
//--- Define a month name
   switch(date_time.mon)
     {
      case  1  :  return "January";
      case  2  :  return "February";
      case  3  :  return "March";
      case  4  :  return "April";
      case  5  :  return "May";
      case  6  :  return "June";
      case  7  :  return "July";
      case  8  :  return "August";
      case  9  :  return "September";
      case 10  :  return "October";
      case 11  :  return "November";
      case 12  :  return "December";
      default  :  return "Undefined";
     }
   /* Sample output:
      July
   */
  }

MQL5 hat keine Liste mit den Monatsnamen, sodass wir hier den Switch-Operator verwenden müssen, um den Text des Monatsnamens auszuwählen und zurückzugeben, abhängig von dem digitalen Wert, der in das Strukturfeld geschrieben wurde.

Diese Funktionen werden uns bei der Anzeige von Beschreibungen der Wochentage und Monate nützlich sein. Außerdem können sie in Zukunft für unsere weiteren Projekte nützlich sein.

Die Funktionen, die die Beschreibungen der Felder der Struktur MqlDateTime zurückgeben, müssen das Format vom Artikel „StringFormat() Beurteilung und fertige Beispiele“ verwenden. Jede Zeile, die von der Funktion zurückgegeben wird, hat eine Kopfzeile und Daten. Die Kopfzeile kann vom linken Rand aus eingerückt werden und kann eine Breite für die tabellarische Ansicht des zurückgegebenen Datensatzes erhalten. Wir werden die Werte für Einrückung und Breite als Parameter an die Funktionen übergeben. Die Standardwerte für diese Optionen sind Null, d. h. keine Zuweisung, und eine Breite, die der Länge des Kopfzeilentextes + 1 entspricht.


Das Jahr in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return the year as a string from MqlDateTime                     |
//+------------------------------------------------------------------+
string MqlDateTimeYear(MqlDateTime &date_time,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="Year:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.year);
   /* Sample output:
      Year: 2023
   */
  }


Der Monat in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return the month as a string from MqlDateTime                    |
//+------------------------------------------------------------------+
string MqlDateTimeMonth(MqlDateTime &date_time,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="Month:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get a month name
   string mn=Month(date_time);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu (%s)",indent,"",w,header,date_time.mon,mn);
   /* Sample output:
      Month: 07 (July)
   */
  }


Der Tag in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return the day as a string from the MqlDateTime structure        |
//+------------------------------------------------------------------+
string MqlDateTimeDay(MqlDateTime &date_time,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="Day:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.day);
   /* Sample output:
      Day: 19
   */
  }



Stunden in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return hours as a string from the MqlDateTime structure          |
//+------------------------------------------------------------------+
string MqlDateTimeHour(MqlDateTime &date_time,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="Hour:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.hour);
   /* Sample output:
      Hour: 08
   */
  }


Minuten in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return minutes as a string from MqlDateTime                      |
//+------------------------------------------------------------------+
string MqlDateTimeMin(MqlDateTime &date_time,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="Minutes:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.min);
   /* Sample output:
      Minutes: 41
   */
  }


Sekunden in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return seconds as a string from MqlDateTime                      |
//+------------------------------------------------------------------+
string MqlDateTimeSec(MqlDateTime &date_time,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="Seconds:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.sec);
   /* Sample output:
      Seconds: 23
   */
  }


Der Wochentag in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//| Return a week day as a string from the MqlDateTime structure     |
//+------------------------------------------------------------------+
string MqlDateTimeDayWeek(MqlDateTime &date_time,const uint header_width=0,const uint indent=0,bool descr=true)
  {
//--- 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="Day of week:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get a week day name
   string dw=DayWeek(date_time);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s (%-lu)",indent,"",w,header,dw,date_time.day_of_week);
   /* Sample output:
      Day of week: Wednesday (3)
   */
  }


Die Nummer eines Tages in einem Jahr in der Struktur MqlDateTime:

//+------------------------------------------------------------------+
//|Return a number of a day in a year from MqlDateTime               |
//+------------------------------------------------------------------+
string MqlDateTimeDayYear(MqlDateTime &date_time,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="Day of year:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.day_of_year);
   /* Sample output:
      Day of year: 199
   */
  }


Anwendungsbeispiele:

Um einen kurzen Datensatz der Datumszeit aus der MqlDateTime-Struktur anzuzeigen, schreiben wir eine Funktion, die das Datum im Format „DW, Monat DD, YYYY, HH:MM:SS“ zurückgibt:

//+------------------------------------------------------------------+
//| Return the date as a string from the MqlDateTime structure       |
//| in the DW, Month DD, YYYY, HH:MM:SS format                       |
//+------------------------------------------------------------------+
string DateTime(MqlDateTime &date_time)
  {
//--- Get the month and the first three characters of a week day
   string mn=Month(date_time);
   string dw=StringSubstr(DayWeek(date_time),0,3);
//--- Return a string in the DW, Month DD, YYYY, HH:MM:SS format
   return StringFormat("%s, %s %02lu, %lu, %02lu:%02lu:%02lu",dw,mn,date_time.day,date_time.year,date_time.hour,date_time.min,date_time.sec);
   /* Sample output:
      Wed, July 19, 2023, 08:41:23
   */
  }

Dies ist eine einzeilige Zusammenfassung aller Strukturdaten mit Ausnahme der Tageszahl des Jahres. Die Funktion ist z.B. praktisch, um eine bestimmte Anzahl von Balken im Journal anzuzeigen:

void OnStart()
  {
   datetime array[];
   MqlDateTime adt[];
   if(CopyTime(Symbol(),PERIOD_CURRENT,0,10,array)==10)
     {
      int total=(int)array.Size();
      if(ArrayResize(adt,total)==total)
        {
         for(int i=0;i<total;i++)
           {
            ResetLastError();
            if(!TimeToStruct(array[i],adt[i]))
               Print("TimeToStruct failed. Error: ",GetLastError());
            PrintFormat("%s %s [%02u] %s",Symbol(),StringSubstr(EnumToString(Period()),7),i,DateTime(adt[i]));
           }
        }
     }
   /* Sample output:
      GBPUSD H1 [00] Wed, July 19, 2023, 02:00:00
      GBPUSD H1 [01] Wed, July 19, 2023, 03:00:00
      GBPUSD H1 [02] Wed, July 19, 2023, 04:00:00
      GBPUSD H1 [03] Wed, July 19, 2023, 05:00:00
      GBPUSD H1 [04] Wed, July 19, 2023, 06:00:00
      GBPUSD H1 [05] Wed, July 19, 2023, 07:00:00
      GBPUSD H1 [06] Wed, July 19, 2023, 08:00:00
      GBPUSD H1 [07] Wed, July 19, 2023, 09:00:00
      GBPUSD H1 [08] Wed, July 19, 2023, 10:00:00
      GBPUSD H1 [09] Wed, July 19, 2023, 11:00:00
   */
  }


Implementieren wir die folgende Funktion, um alle Felder der Struktur in kurzen und tabellarischen Formaten zu protokollieren:

//+------------------------------------------------------------------+
//| Logs descriptions of all fields of the MqlDateTime structure     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(MqlDateTime &date_time,const bool short_entry=true,const uint header_width=0,const uint indent=0)
  {
//--- If it is a short entry, log the date and time in the DW, Month DD, YYYY, HH:MM:SS format
   if(short_entry)
      Print(DateTime(date_time));
   /* Sample output:
      Wed, July 19, 2023, 08:41:23
   */
//--- Otherwise
   else
     {
      //--- create a string describing all the data of the structure with indents and a given width of the header field 
      string res=StringFormat("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
                              MqlDateTimeYear(date_time,header_width,indent),
                              MqlDateTimeMonth(date_time,header_width,indent),
                              MqlDateTimeDay(date_time,header_width,indent),
                              MqlDateTimeHour(date_time,header_width,indent),
                              MqlDateTimeMin(date_time,header_width,indent),
                              MqlDateTimeSec(date_time,header_width,indent),
                              MqlDateTimeDayWeek(date_time,header_width,indent),
                              MqlDateTimeDayYear(date_time,header_width,indent)
                             );
      //--- Display the obtained string in the journal
      Print(res);
     }
   /* Sample output:
      Year: 2023
      Month: 07 (July)
      Day: 19
      Hour: 09
      Minutes: 32
      Seconds: 25
      Day of week: Wednesday (3)
      Day of year: 199
   */
  }

Ein Skript mit einem Beispiel für die Verwendung der Funktion. Es zeig zunächst einen kurzen Eintrag im Journal an, gefolgt von der tabellarischen Form mit eingerückten Feldüberschriften und Feldbreiten von 2 bzw. 14 Zeichen:

void OnStart()
  {
   MqlDateTime dt;
   TimeCurrent(dt);
   MqlDateTimePrint(dt,true);
   MqlDateTimePrint(dt,false,14,2);
   /* Sample output:
      Wed, July 19, 2023, 09:33:56
        Year:         2023
        Month:        07 (July)
        Day:          19
        Hour:         09
        Minutes:      33
        Seconds:      56
        Day of week:  Wednesday (3)
        Day of year:  199
   */
  }

Alle oben vorgestellten Funktionen für die Arbeit mit Feldern der MqlDateTime-Struktur und mit Hilfsfeldern können in Ihren Programmen „so wie sie sind“ verwendet oder nach Ihren Vorstellungen und Bedürfnissen verändert werden.


Die Struktur MqlTick

Struktur zur Speicherung der letzten Preise nach Symbolen. Die Struktur ist so konzipiert, dass die am meisten benötigten Daten über die aktuellen Preise zeitnah zur Verfügung stehen.

struct MqlTick
  {
   datetime     time;          // Last price update time
   double       bid;           // Current Bid price
   double       ask;           // Current Ask price
   double       last;          // Current price of the last trade (Last)
   ulong        volume;        // Volume for the current Last price
   long         time_msc;      // Last price update time in milliseconds
   uint         flags;         // Tick flags
   double       volume_real;   // Volume for the current Last price
  };

Eine Variable vom Typ MqlTick ermöglicht es, Ask-, Bid-, Last- und Volume-Werte sowie die Zeit in Millisekunden mit einem Aufruf der Funktion SymbolInfoTick() abzufragen.

Die Parameter jedes Ticks werden unabhängig davon ausgefüllt, ob es Änderungen gegenüber dem vorherigen Tick gibt. Auf diese Weise ist es möglich, einen korrekten Preis für einen beliebigen Zeitpunkt in der Vergangenheit zu ermitteln, ohne dass man in der Tick-Historie nach früheren Werten suchen muss. Selbst wenn sich beispielsweise nur der Bid während einer Tickankunft ändert, enthält die Struktur noch andere Parameter, darunter den vorherigen Ask, das Volumen usw.

Analyse der Ticks, um festzustellen, welche Daten sich geändert haben:

  • TICK_FLAG_BID — der Tick hat den Geldkurs verändert
  • TICK_FLAG_ASK — der Tick hat den Briefkurs verändert
  • TICK_FLAG_LAST — der Tick hat den Preis des letzten Geschäfts geändert
  • TICK_FLAG_VOLUME — der Tick hat das Volumen verändert
  • TICK_FLAG_BUY — der Tick ist das Ergebnis eines Kaufgeschäfts
  • TICK_FLAG_SELL — der Tick ist das Ergebnis eines Verkaufsgeschäfts

    Druckmethoden für MqlTick

    Die Funktion ArrayPrint() ist geeignet, die Struktur im Journal auf die gleiche Weise wie bei MqlDateTime darzustellen:

    void OnStart()
      {
    //--- Declare a variable with the MqlTick type
       MqlTick  tick;
    //--- If failed to get the last tick, display the error message and exit the method
       if(!SymbolInfoTick(Symbol(),tick))
         {
          Print("SymbolInfoTick failed, error: ",(string)GetLastError());
          return;
         }
    //--- Display the tick using standard ArrayPrint()
    //--- To do this, declare an array of dimension 1 with type MqlTick,
    //--- enter the value of the 'tick' variable into it and print it
       MqlTick array[1];
       array[0]=tick;
       Print("Last tick (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Last tick (ArrayPrint):
                           [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
          [0] 2023.07.19 17:02:49 1.28992 1.28996 0.0000        0 1689786169589       6       0.00000
       */
      }
    
    

    Es ist logisch, dass man zum Drucken eines Arrays das Array mit einem Bereich von Ticks füllen kann:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If failed to get the last 10 ticks, display the error message and exit the method
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 10 tick (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Last 10 tick (ArrayPrint):
                           [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
          [0] 2023.07.19 17:24:38 1.28804 1.28808 0.0000        0 1689787478461       6       0.00000
          [1] 2023.07.19 17:24:38 1.28806 1.28810 0.0000        0 1689787478602       6       0.00000
          [2] 2023.07.19 17:24:38 1.28804 1.28808 0.0000        0 1689787478932       6       0.00000
          [3] 2023.07.19 17:24:39 1.28806 1.28810 0.0000        0 1689787479210       6       0.00000
          [4] 2023.07.19 17:24:39 1.28807 1.28811 0.0000        0 1689787479765       6       0.00000
          [5] 2023.07.19 17:24:39 1.28808 1.28812 0.0000        0 1689787479801       6       0.00000
          [6] 2023.07.19 17:24:40 1.28809 1.28813 0.0000        0 1689787480240       6       0.00000
          [7] 2023.07.19 17:24:40 1.28807 1.28811 0.0000        0 1689787480288       6       0.00000
          [8] 2023.07.19 17:24:40 1.28809 1.28813 0.0000        0 1689787480369       6       0.00000
          [9] 2023.07.19 17:24:40 1.28810 1.28814 0.0000        0 1689787480399       6       0.00000
       */
      }
    
    

    Auch hier brauchen wir eine aussagekräftigere Darstellung der Werte. Zum Beispiel die Zeit in Millisekunden und Flags. Es ist wahrscheinlich bequemer, sie auf die übliche Weise zu sehen - die Zeit im Zeitformat und die Flags im Format von Enumerationswerte.


    Funktionen für die Arbeit mit MqlTick-Strukturdaten.

    Implementieren wir die Funktionen für die Arbeit mit MqlTick-Strukturdaten. Genau wie alle bereits erstellten Funktionen für die Arbeit mit der MqlDateTime-Struktur geben auch die Funktionen für die Arbeit mit MqlTick einen formatierten String zurück. Das Zeilenformat umfasst den linken Rand des Textes und die Breite des Header-Feldes. Standardmäßig sind die Werte für Auffüllung und Randbreite gleich Null, d. h. es gibt keine Zuweisungen und die Randbreite ist gleich der Länge des Kopfzeilentextes + 1.


    Zusatzfunktionen

    Wir haben diese Funktion bereits erstellt, um die Zeit in Millisekunden als String zurückzugeben. Hier ist es nützlich, um die Tickzeit in Millisekunden zurückzugeben. Wenden wir es an:

    //+------------------------------------------------------------------+
    //| Accept a date in ms, return time in Date Time.Msc format         |
    //+------------------------------------------------------------------+
    string TimeMSC(const long time_msc)
      {
       return StringFormat("%s.%.3hu",string((datetime)time_msc / 1000),time_msc % 1000);
       /* Sample output:
          2023.07.13 09:31:58.177
       */
      }
    
    


    Zeit in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the time of the last price update as a string             |
    //+------------------------------------------------------------------+
    string MqlTickTime(const MqlTick &tick,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:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)tick.time);
       /* Sample output:
          Time: 2023.07.19 20:58:00
       */
      }
    
    


    Geldkurs (Bid) in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the Bid price as a string                                 |
    //+------------------------------------------------------------------+
    string MqlTickBid(const string symbol,const MqlTick &tick,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="Bid:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.bid);
       /* Sample output:
          Bid: 1.29237
       */
      }
    
    


    Briefkurs (Ask) in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the Ask price as a string                                 |
    //+------------------------------------------------------------------+
    string MqlTickAsk(const string symbol,const MqlTick &tick,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="Ask:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.ask);
       /* Sample output:
          Ask: 1.29231
       */
      }
    
    


    Letzter Handelskurs in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the Last price as a string                                |
    //+------------------------------------------------------------------+
    string MqlTickLast(const string symbol,const MqlTick &tick,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="Last:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.last);
       /* Sample output:
          Last: 0.00000
       */
      }
    
    


    Letztes Preisvolumen in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the volume for the Last price as a string                 |
    //+------------------------------------------------------------------+
    string MqlTickVolume(const MqlTick &tick,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="Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-I64u",indent,"",w,header,tick.volume);
       /* Sample output:
          Volume: 0
       */
      }
    
    


    Zeit in Millisekunden in der Struktur MqlTick:

    //+------------------------------------------------------------------+
    //| Return the time in milliseconds as a string                      |
    //+------------------------------------------------------------------+
    string MqlTickTimeMSC(const MqlTick &tick,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);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,TimeMSC(tick.time_msc));
       /* Sample output:
          Time msc: 2023.07.19 21:21:09.732
       */
      }
    
    


    Tick-Flags in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return tick flags as a string                                    |
    //+------------------------------------------------------------------+
    string MqlTickFlags(const MqlTick &tick,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="Flags:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Define a variable to describe tick flags
       string flags="";
    //--- Parse tick flags into components
       if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID)
          flags+=(flags.Length()>0 ? "|" : "")+"BID";
       if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK)
          flags+=(flags.Length()>0 ? "|" : "")+"ASK";
       if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST)
          flags+=(flags.Length()>0 ? "|" : "")+"LAST";
       if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME)
          flags+=(flags.Length()>0 ? "|" : "")+"VOLUME";
       if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY)
          flags+=(flags.Length()>0 ? "|" : "")+"BUY";
       if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL)
          flags+=(flags.Length()>0 ? "|" : "")+"SELL";
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,flags);
       /* Sample output:
          Flags: BID|ASK
       */
      }
    
    


    Letztes Preisvolumen mit erhöhter Genauigkeit in der MqlTick-Struktur:

    //+------------------------------------------------------------------+
    //| Return the volume for the Last price as a string                 |
    //+------------------------------------------------------------------+
    string MqlTickVolumeReal(const MqlTick &tick,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="Volume Real:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.2f",indent,"",w,header,tick.volume_real);
       /* Sample output:
          Volume Real: 0.00
       */
      }
    
    


    Beispiele für die Verwendung

    Schreiben wir die Funktion zur Anzeige von Tickdaten im Journal. Wir übergeben den Namen des Symbols an die Funktion, um zu wissen, mit welcher Genauigkeit die Kurswerte im Journal angezeigt werden sollen. Da die Felder Volume und Volume Real die Volumina des Last-Preises enthalten, macht es keinen Sinn, die Volumina anzuzeigen, wenn Last Null ist (nicht umgerechnet) - sie sind ebenfalls Null. Um den Index eines Ticks aus einem Array von Ticks angeben und drucken zu können, übergeben wir diesen Index in den Eingabeparametern der Funktion. Standardmäßig ist sein Wert -1, und bei diesem Wert wird der Index nicht gedruckt.

    //+------------------------------------------------------------------+
    //| Logs descriptions of all fields of the MqlTick structure         |
    //| If Last==0, Last, Volume and Volume Real fields are not displayed|
    //+------------------------------------------------------------------+
    void MqlTickPrint(const string symbol,const MqlTick &tick,const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE)
      {
    //--- Declare the variable for storing the result
       string res="";
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
       string num=(index==WRONG_VALUE ? "" : StringFormat("[%ld] ",index));
    //--- If it is a short entry, log the tick data in the Symbol TimeMSC, Bid, Ask, Last, Vol/VolR, Flags format
       if(short_entry)
         {
          //--- If Last is not zero, display Last, Volume and Volume Real, otherwise they are all zero and there is no point in displaying them
          string last=(tick.last!=0 ? StringFormat(", Last: %.*f, Vol: %I64u/%.2f",dg,tick.last,tick.volume,tick.volume_real) : "");
          res=StringFormat("%sTick %s Time: %s, Bid: %.*f, Ask: %.*f%s, %s",num,symbol,TimeMSC(tick.time_msc),dg,tick.bid,dg,tick.ask,last,MqlTickFlags(tick));
          Print(res);
         }
       /* Sample output (if Last is not zero):
          Tick GBPUSD Time: 2023.07.20 13:57:31.376, Bid: 1.28947, Ask: 1.28951, Last: 1.28947, Vol: 33/33.45, Flags: BID|ASK
          Sample output (if Last is zero):
          Tick GBPUSD Time: 2023.07.20 13:59:33.274, Bid: 1.28956, Ask: 1.28960, Flags: BID|ASK
       */
    //--- Otherwise
       else
         {
          //--- create a string describing all the data of the structure with indents and a given width of the header field 
          res=StringFormat("%s\n%s\n%s%s%s\n%s\n%s%s",
                           MqlTickTime(tick,header_width,indent),
                           MqlTickBid(symbol,tick,header_width,indent),
                           MqlTickAsk(symbol,tick,header_width,indent),
                           (tick.last!=0 ? "\n"+MqlTickLast(symbol,tick,header_width,indent) : ""),
                           (tick.last!=0 ? "\n"+MqlTickVolume(tick,header_width,indent) : ""),
                           MqlTickTimeMSC(tick,header_width,indent),
                           MqlTickFlags(tick,header_width,indent),
                           (tick.last!=0 ? "\n"+MqlTickVolumeReal(tick,header_width,indent) : "")
                          );
          //--- Display the obtained string in the journal
          Print(res);
         }
       /* Sample output (if Last is not zero):
          Time:         2023.07.20 14:42:33
          Bid:          1.28958
          Ask:          1.28962
          Last:         1.28947
          Volume:       33
          Time msc:     2023.07.20 14:42:33.401
          Flags:        BID|ASK
          Volume Real:  33.45
          
          Sample output (if Last is zero):
          Time:         2023.07.20 14:42:33
          Bid:          1.28958
          Ask:          1.28962
          Time msc:     2023.07.20 14:42:33.401
          Flags:        BID|ASK
       */
      }
    
    

    Ein Skript, das die letzten 10 Ticks in Kurzform in das Journal druckt und dabei die Tick-Indizes aus dem Array angibt:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If failed to get the last 10 ticks, display the error message and exit the method
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 10 tick (MqlTickPrint):");
       for(int i=0;i<(int)array.Size();i++)
          MqlTickPrint(Symbol(),array[i],true,0,0,i);
    
       /* Sample output:
          Last 10 tick (MqlTickPrint):
          [0] Tick GBPUSD Time: 2023.07.20 15:36:29.941, Bid: 1.28686, Ask: 1.28690, Flags: BID|ASK
          [1] Tick GBPUSD Time: 2023.07.20 15:36:29.970, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK
          [2] Tick GBPUSD Time: 2023.07.20 15:36:30.061, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK
          [3] Tick GBPUSD Time: 2023.07.20 15:36:30.212, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK
          [4] Tick GBPUSD Time: 2023.07.20 15:36:30.259, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK
          [5] Tick GBPUSD Time: 2023.07.20 15:36:30.467, Bid: 1.28682, Ask: 1.28686, Flags: BID|ASK
          [6] Tick GBPUSD Time: 2023.07.20 15:36:30.522, Bid: 1.28681, Ask: 1.28685, Flags: BID|ASK
          [7] Tick GBPUSD Time: 2023.07.20 15:36:30.572, Bid: 1.28673, Ask: 1.28677, Flags: BID|ASK
          [8] Tick GBPUSD Time: 2023.07.20 15:36:30.574, Bid: 1.28672, Ask: 1.28676, Flags: BID|ASK
          [9] Tick GBPUSD Time: 2023.07.20 15:36:30.669, Bid: 1.28674, Ask: 1.28678, Flags: BID|ASK
       */
      }
    
    

    Ein Skript, das die letzten 4 Ticks aus einem Array im Protokoll mit einem linken Einzug von 2 Zeichen und einer Kopffeldbreite von 14 Zeichen ausgibt:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If the last 4 ticks are not received in the array, display an error message and leave
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,4)!=4)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 4 tick (MqlTickPrint):");
       for(int i=0;i<(int)array.Size();i++)
         {
          PrintFormat("Tick[%lu] %s:",i,Symbol());
          MqlTickPrint(Symbol(),array[i],false,14,2);
         }
    
       /* Sample output:
          Last 4 tick (MqlTickPrint):
          Tick[0] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28776
            Ask:          1.28780
            Time msc:     2023.07.20 17:04:51.203
            Flags:        BID|ASK
          Tick[1] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28772
            Ask:          1.28776
            Time msc:     2023.07.20 17:04:51.331
            Flags:        BID|ASK
          Tick[2] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28771
            Ask:          1.28775
            Time msc:     2023.07.20 17:04:51.378
            Flags:        BID|ASK
          Tick[3] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28772
            Ask:          1.28776
            Time msc:     2023.07.20 17:04:51.680
            Flags:        BID|ASK
       */
      }
    
    


    Die Struktur MqlRates

    Struktur zur Speicherung von Informationen über Preise, Volumen und Spread.

    struct MqlRates
      {
       datetime time;         // period start time
       double   open;         // open price
       double   high;         // high price for the period
       double   low;          // low price for the period
       double   close;        // close price
       long     tick_volume;  // tick volume
       int      spread;       // spread
       long     real_volume;  // exchange volume
      };
    

    Druckmethoden für MqlRates

    MqlRates — Struktur zur Speicherung von Daten über einen einzelnen Balken historischer Daten. Die Struktur kann mit der Funktion CopyRates() gefüllt werden. Um die Daten des aktuellen Balkens zu erhalten, können wir die erste Form des Funktionsaufrufs verwenden, wobei wir den Index 0 und die Anzahl der kopierten Balken gleich 1 angeben. In jedem Fall füllt diese Funktion ein Array mit dem Typ MqlRates. Daraus ergibt sich die Schlussfolgerung, dass es praktisch ist, dieses Array mit ArrayPrint() in das Journal zu drucken:

    void OnStart()
      {
    //---
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,1,array)!=1)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
       Print("Current bar ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Current bar GBPUSD H1 (ArrayPrint):
                           [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
          [0] 2023.07.21 04:00:00 1.28763 1.28765 1.28663 1.28748          2083        7             0
       */
      }
    
    

    Um die letzten zehn Balken zu kopieren, müssen wir also nur die Anzahl der zu kopierenden Daten mit 10 angeben:

    void OnStart()
      {
    //---
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
       Print("Data of the last 10 bars: ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Data of the last 10 bars: GBPUSD H1 (ArrayPrint):
                           [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
          [0] 2023.07.20 20:00:00 1.28530 1.28676 1.28512 1.28641          2699        4             0
          [1] 2023.07.20 21:00:00 1.28641 1.28652 1.28557 1.28587          1726        3             0
          [2] 2023.07.20 22:00:00 1.28587 1.28681 1.28572 1.28648          2432        3             0
          [3] 2023.07.20 23:00:00 1.28648 1.28683 1.28632 1.28665           768        4             0
          [4] 2023.07.21 00:00:00 1.28663 1.28685 1.28613 1.28682           396        1             0
          [5] 2023.07.21 01:00:00 1.28684 1.28732 1.28680 1.28714           543        8             0
          [6] 2023.07.21 02:00:00 1.28714 1.28740 1.28690 1.28721           814        2             0
          [7] 2023.07.21 03:00:00 1.28721 1.28774 1.28685 1.28761          2058        5             0
          [8] 2023.07.21 04:00:00 1.28763 1.28791 1.28663 1.28774          3480        7             0
          [9] 2023.07.21 05:00:00 1.28774 1.28776 1.28769 1.28774            18        7             0
       */
      }
    
    

    Hier ist alles gleich — es gibt eine lange Liste von Daten im Journal. Wenn der Tabellenkopf hinter dem oberen Rand des Journals verborgen ist, ist nicht klar, worauf sich die dargestellten Zahlen beziehen.

    Schreiben wir unsere eigenen Funktionen, um Beschreibungen der Strukturfelder zurückzugeben und diese Daten im Terminaljournal zu drucken.


    Funktionen für die Arbeit mit MqlRates-Strukturdaten.

    Unsere nutzerdefinierten Funktionen geben eine Textbeschreibung für jedes Feld in der Struktur zurück. Jede Beschreibung besteht aus einer Überschrift und den eigentlichen Daten. Für die von der Funktion zurückgegebene Zeichenkette können wir den Einzug vom linken Rand und die Breite des Kopffelds festlegen.


    Zeit:

    Zeit — Startzeit des Zeitraums. Mit anderen Worten, die Öffnungszeit des Balkens auf dem Symbol und der Zeitrahmen des Charts, aus der die in die Struktur geschriebenen Daten angefordert wurden.

    //+------------------------------------------------------------------+
    //| Return the bar opening time as a string                          |
    //+------------------------------------------------------------------+
    string MqlRatesTime(const MqlRates &rates,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:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)rates.time);
       /* Sample output:
          Time: 2023.07.21 06:00:00
       */
      }
    
    


    Open:

    Der Eröffnungskurs des Balkens für das Symbol und der Zeitrahmen des Charts, aus der die in die Struktur geschriebenen Daten angefordert wurden.

    //+------------------------------------------------------------------+
    //| Return the bar open price as a string                            |
    //+------------------------------------------------------------------+
    string MqlRatesOpen(const string symbol,const MqlRates &rates,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="Open:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.open);
       /* Sample output:
          Open: 1.28812
       */
      }
    
    


    High:

    Höchstpreis - der höchste Preis des Balkens auf dem Symbol und der Zeitrahmen des Charts, von dem die in die Struktur geschriebenen Daten angefordert wurden.

    //+------------------------------------------------------------------+
    //| Return the High bar price as a string                            |
    //+------------------------------------------------------------------+
    string MqlRatesHigh(const string symbol,const MqlRates &rates,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="High:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.high);
       /* Sample output:
          High: 1.28859
       */
      }
    
    


    Low:

    Niedriger Preis - der niedrigste Preis des Balkens auf dem Symbol und der Chart-Periode, von dem die in die Struktur geschriebenen Daten angefordert wurden.

    //+------------------------------------------------------------------+
    //| Return the bar Low price as a string                             |
    //+------------------------------------------------------------------+
    string MqlRatesLow(const string symbol,const MqlRates &rates,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="Low:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.low);
       /* Sample output:
          Low: 1.28757
       */
      }
    
    


    Close:

    Schlusskurs — der Schlusskurs des Balkens für das Symbol und die Chart-Periode, von dem die in die Struktur geschriebenen Daten angefordert wurden.
    Für den aktuellen Balken ist der Schlusskurs gleich dem aktuellen Geld- oder Briefkurs, je nachdem, auf welchem Kurs das Chart basiert.

    //+------------------------------------------------------------------+
    //| Return the bar close price as a string                           |
    //+------------------------------------------------------------------+
    string MqlRatesClose(const string symbol,const MqlRates &rates,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="Close:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.close);
       /* Sample output:
          Close: 1.28770
       */
      }
    
    


    TickVolume:

    Das Tick Volumen des Balkens.

    //+------------------------------------------------------------------+
    //| Return the tick volume of a bar as a string                      |
    //+------------------------------------------------------------------+
    string MqlRatesTickVolume(const MqlRates &rates,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="Tick Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.tick_volume);
       /* Sample output:
          Tick Volume: 963
       */
      }
    
    


    Spread:

    Spreizung des Balkens.

    //+------------------------------------------------------------------+
    //| Return the bar spread as a string                                |
    //+------------------------------------------------------------------+
    string MqlRatesSpread(const MqlRates &rates,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="Spread:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-ld",indent,"",w,header,rates.spread);
       /* Sample output:
          Spread: 4
       */
      }
    
    


    RealVolume:

    Das Volumen innerhalb des Balkens.

    //+------------------------------------------------------------------+
    //| Return the bar exchange volume as a string                       |
    //+------------------------------------------------------------------+
    string MqlRatesRealVolume(const MqlRates &rates,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="Real Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.real_volume);
       /* Sample output:
          Real Volume: 0
       */
      }
    
    


    Beispiele für die Verwendung

    Erstellen wir das folgende Skript, um die Daten der letzten 10 Balken im Journal zu drucken:

    void OnStart()
      {
    //--- Copy the last 10 data bars to the MqlRates array
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
    
    //--- Set the indexing of the array like a timeseries
       ArraySetAsSeries(array,true);
    //--- Print short entries in the journal in a loop through the array with the received bar data
       for(int i=0;i<(int)array.Size();i++)
          MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],true,0,0,i);
       
       /* Sample output:
          GBPUSD H1[0]: 2023.07.21 14:00:00, O: 1.28451, H: 1.28541, L: 1.28451, C: 1.28501, S:  4, V:   821, RV: 0
          GBPUSD H1[1]: 2023.07.21 13:00:00, O: 1.28678, H: 1.28685, L: 1.28418, C: 1.28452, S:  1, V:  3602, RV: 0
          GBPUSD H1[2]: 2023.07.21 12:00:00, O: 1.28581, H: 1.28696, L: 1.28557, C: 1.28678, S:  1, V:  4807, RV: 0
          GBPUSD H1[3]: 2023.07.21 11:00:00, O: 1.28695, H: 1.28745, L: 1.28401, C: 1.28581, S:  1, V:  7440, RV: 0
          GBPUSD H1[4]: 2023.07.21 10:00:00, O: 1.28933, H: 1.28960, L: 1.28651, C: 1.28696, S:  1, V:  8883, RV: 0
          GBPUSD H1[5]: 2023.07.21 09:00:00, O: 1.28788, H: 1.29040, L: 1.28753, C: 1.28934, S:  1, V:  5474, RV: 0
          GBPUSD H1[6]: 2023.07.21 08:00:00, O: 1.28794, H: 1.28848, L: 1.28713, C: 1.28787, S:  1, V:  1885, RV: 0
          GBPUSD H1[7]: 2023.07.21 07:00:00, O: 1.28762, H: 1.28808, L: 1.28744, C: 1.28794, S:  4, V:   878, RV: 0
          GBPUSD H1[8]: 2023.07.21 06:00:00, O: 1.28812, H: 1.28859, L: 1.28743, C: 1.28760, S:  3, V:  1112, RV: 0
          GBPUSD H1[9]: 2023.07.21 05:00:00, O: 1.28774, H: 1.28820, L: 1.28747, C: 1.28812, S:  7, V:  1671, RV: 0
       */
      }
    
    

    Nachdem wir die erforderliche Datenmenge in das Array kopiert haben, indexieren wir es wie eine Zeitreihe, sodass die Daten wie Chart-Balken im Terminal angezeigt werden. Daten mit einem Null-Index entsprechen dem aktuellen Balken.

    Dieses Skript druckt die letzten 4 Balken in das Journal in tabellarischer Form aus, wobei das Kopfzeilenfeld um zwei Zeichen nach links eingerückt ist und die Breite des Titelfeldes 14 Zeichen beträgt:

    void OnStart()
      {
    //--- Copy the last 4 data bars to the MqlRates array
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,4,array)!=4)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
    
    //--- Set the indexing of the array like a timeseries
       ArraySetAsSeries(array,true);
    //--- Print short entries in the journal in a loop through the array with the received bar data
       for(int i=0;i<(int)array.Size();i++)
          MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],false,14,2,i);
       
       /* Sample output:
          GBPUSD H1[0]:
            Time:         2023.07.21 14:00:00
            Open:         1.28451
            High:         1.28541
            Low:          1.28451
            Close:        1.28491
            Tick Volume:  1098
            Spread:       4
            Real Volume:  0
          GBPUSD H1[1]:
            Time:         2023.07.21 13:00:00
            Open:         1.28678
            High:         1.28685
            Low:          1.28418
            Close:        1.28452
            Tick Volume:  3602
            Spread:       1
            Real Volume:  0
          GBPUSD H1[2]:
            Time:         2023.07.21 12:00:00
            Open:         1.28581
            High:         1.28696
            Low:          1.28557
            Close:        1.28678
            Tick Volume:  4807
            Spread:       1
            Real Volume:  0
          GBPUSD H1[3]:
            Time:         2023.07.21 11:00:00
            Open:         1.28695
            High:         1.28745
            Low:          1.28401
            Close:        1.28581
            Tick Volume:  7440
            Spread:       1
            Real Volume:  0
       */
      }
    
    


    Die Struktur MqlBookInfo

    Eine Struktur, die die Daten zur Markttiefe liefert.

    struct MqlBookInfo
      {
       ENUM_BOOK_TYPE   type;            // order type from ENUM_BOOK_TYPE enumeration
       double           price;           // price
       long             volume;          // volume
       double           volume_real;     // volume with increased accuracy
      };
    

    Um die Struktur zu verwenden, genügt es, eine Variable dieses Typs zu deklarieren. Die Markttiefe ist nicht für alle Finanzinstrumente verfügbar. Bevor wir die Daten der Markttiefe erhalten, sollten wir sie mit MarketBookAdd() abonnieren. Nach der Beendigung müssen wir uns von der Markttiefe abmelden: MarketBookRelease(). Das EA-Programm sollte die Funktion OnBookEvent() enthalten, um eingehende Benachrichtigungen zu verarbeiten.


    Druckmethoden für MqlBookInfo

    Jeder Empfang der Markttiefe beinhaltet den Empfang einer Liste von Aufträgen in diesem Markt. Dies ist ein Datenfeld. Daher können wir mit ArrayPrint() einen Schnappschuss der Markttiefe drucken:

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print the header in the journal and the market depth snapshot from the array below
       Print("MarketBookInfo by ",Symbol(),":");
       ArrayPrint(array);
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       /* Sample output:
          MarketBookInfo by GBPUSD:
              [type] [price] [volume] [volume_real]
          [0]      1 1.28280      100     100.00000
          [1]      1 1.28276       50      50.00000
          [2]      1 1.28275       20      20.00000
          [3]      1 1.28273       10      10.00000
          [4]      2 1.28268       10      10.00000
          [5]      2 1.28266       20      20.00000
          [6]      2 1.28265       50      50.00000
          [7]      2 1.28260      100     100.00000
       */
      }
    
    

    Wie Sie sehen können, werden die Arten von Anfragen hier in numerischen Werten ausgedrückt, was für die Wahrnehmung ungünstig ist. Schreiben wir Funktionen, um Beschreibungen der Tiefe von Marktfeldern in der bereits für die anderen oben besprochenen Strukturen akzeptierten Weise zurückzugeben.


    Funktionen für die Arbeit mit MqlBookInfo-Strukturdaten.

    Alle Funktionen, die eine String-Repräsentation der Felder der MqlBookInfo-Struktur zurückgeben, sind im gleichen Stil wie die oben beschriebenen Funktionen zur Beschreibung der Felder der entsprechenden Strukturen. Wenden wir uns dieser Methoden zu.


    Die Auftragsart in der MqlBookInfo-Markttiefenstruktur:

    //+------------------------------------------------------------------+
    //| Return the order type in the market depth as a string            |
    //+------------------------------------------------------------------+
    string MqlBookInfoType(const MqlBookInfo &book,const uint header_width=0,const uint indent=0)
      {
    //--- Get the value of the order type
       ENUM_BOOK_TYPE book_type=book.type;
    //--- "Cut out" the type from the string obtained from enum
       string type=StringSubstr(EnumToString(book_type),10);
    //--- Convert all obtained symbols to lower case and replace the first letter from small to capital
       if(type.Lower())
          type.SetChar(0,ushort(type.GetChar(0)-0x20));
    //--- Replace all underscore characters with space in the resulting line
       StringReplace(type,"_"," ");
    //--- 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="Type:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,type);
       /* Sample output:
          Type: Sell
       */
      }
    
    


    Der Auftragspreis in der MqlBookInfo-Markttiefenstruktur:

    //+------------------------------------------------------------------+
    //| Return the order price in the market depth as a string           |
    //+------------------------------------------------------------------+
    string MqlBookInfoPrice(const string symbol,const MqlBookInfo &book,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="Price:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,book.price);
       /* Sample output:
          Price: 1.28498
       */
      }
    
    


    Das Auftragsvolumen in der MqlBookInfo-Markttiefenstruktur:

    //+------------------------------------------------------------------+
    //| Return the order volume in the market depth as a string          |
    //+------------------------------------------------------------------+
    string MqlBookInfoVolume(const MqlBookInfo &book,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="Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,book.volume);
       /* Sample output:
          Volume: 100
       */
      }
    
    


    Das Volumen mit erhöhter Genauigkeit:

    //+------------------------------------------------------------------+
    //| Return the order volume with increased accuracy as a string      |
    //+------------------------------------------------------------------+
    string MqlBookInfoVolumeReal(const MqlBookInfo &book,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="Volume Real:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.2f",indent,"",w,header,book.volume_real);
       /* Sample output:
          Volume Real: 100.00
       */
      }
    
    


    Anwendungsbeispiele:

    Nun wollen wir eine Funktion schreiben, die alle Daten in der MqlBookInfo-Struktur in das Journal ausgibt. Es wird möglich sein, sie in zwei Modi zu drucken: in einer Zeile und in Tabellenform:

    //+------------------------------------------------------------------+
    //| Logs a description of all fields of the MqlRates structure       |
    //+------------------------------------------------------------------+
    void MqlBookInfoPrint(const string symbol,const MqlBookInfo &book,
                          const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE)
      {
    //--- Declare the variable for storing the result
       string res="";
    //--- Get the number of decimal places and the string index value
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
       string num=(index==WRONG_VALUE ? "" : StringFormat("[%02ld]",index));
       
    //--- "Cut out" the type from the order type name string obtained from enum
       string type=StringSubstr(EnumToString(book.type),10);
    //--- Convert all obtained symbols to lower case and replace the first letter from small to capital
       if(type.Lower())
          type.SetChar(0,ushort(type.GetChar(0)-0x20));
    //--- Replace all underscore characters with space in the resulting line
       StringReplace(type,"_"," ");
       
    //--- If it is a short entry, log the market depth data in the [index] Type Price V VR format
       if(short_entry)
         {
          res=StringFormat("%-8s%-11s%- *.*f Volume%- 5lld Real%- 8.2f",
                           num,type,dg+4,dg,book.price,book.volume,book.volume_real);
          Print(res);
         }
       /* Sample output:
          [00]    Sell        1.28598  Volume 100  Real 100.00 
       */
    //--- Otherwise
       else
         {
          //--- create a string describing all the data of the structure with indents and a given width of the header field 
          res=StringFormat("Market Book by %s %s:\n%s\n%s\n%s\n%s",symbol,num,
                           MqlBookInfoType(book,header_width,indent),
                           MqlBookInfoPrice(symbol,book,header_width,indent),
                           MqlBookInfoVolume(book,header_width,indent),
                           MqlBookInfoVolumeReal(book,header_width,indent)
                          );
          //--- Display the obtained string in the journal
          Print(res);
         }
       /* Sample output
          BoolInfo by GBPUSD [00]:
            Type:         Sell
            Price:        1.28588
            Volume:       100
            Volume Real:  100.00
       */
      }
    
    

    Der Hauptmodus hier sollte die Ausgabe an das Journal in einer Zeile sein, da die Markttiefe nicht eine einzelne Order ist, und wir eine Liste dieser Orders im Array erhalten. Dementsprechend können wir dieses Array mit der folgenden Funktion in das Journal drucken:

    //+----------------------------------------------------------------------+
    //| Display the market depth entries in the journal in the short format  |
    //+----------------------------------------------------------------------+
    void MqlBookInfoPrintShort(const string symbol,const MqlBookInfo &book_array[])
      {
       PrintFormat("Market Book by %s:",symbol);
       for(int i=0;i<(int)book_array.Size();i++)
          MqlBookInfoPrint(symbol,book_array[i],true,0,0,i);
      }
    
    

    Die Funktion empfängt ein Array von Aufträgen für die Markttiefe und druckt in einer Schleife durch das Array alle Daten der Markttiefe in das Journal unter Verwendung der Kurzausgabe.

    Ein Skript, das die Verwendung dieser Funktion und das Ergebnis demonstriert:

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print in the journal a snapshot of the market depth from the array in the form of strings
       MqlBookInfoPrintShort(Symbol(),array);
    
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       
       /* Sample output:
          Market Book by GBPUSD:
          [00]    Sell        1.28674  Volume 100  Real 100.00 
          [01]    Sell        1.28668  Volume 50   Real 50.00  
          [02]    Sell        1.28666  Volume 20   Real 20.00  
          [03]    Sell        1.28664  Volume 10   Real 10.00  
          [04]    Buy         1.28657  Volume 10   Real 10.00  
          [05]    Buy         1.28654  Volume 20   Real 20.00  
          [06]    Buy         1.28653  Volume 50   Real 50.00  
          [07]    Buy         1.28646  Volume 100  Real 100.00 
       */
      }
    
    

    Aber manchmal müssen wir dieselben Daten auch in Tabellenform anzeigen. Dazu können wir die folgende Funktion verwenden:

    //+------------------------------------------------------------------------+
    //| Display the market depth entries in the journal in the tabular format  |
    //+------------------------------------------------------------------------+
    void MqlBookInfoPrintTable(const string symbol,const MqlBookInfo &book_array[],const uint header_width=0,const uint indent=0)
      {
       for(int i=0;i<(int)book_array.Size();i++)
          MqlBookInfoPrint(symbol,book_array[i],false,header_width,indent,i);
      }
    
    

    Ein Skript, das die Verwendung dieser Funktion und das Ergebnis demonstriert:

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print in the journal a snapshot of the market depth from the array in the form of strings
       MqlBookInfoPrintTable(Symbol(),array,14,2);
    
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       
       /* Sample output:
          Market Book by GBPUSD [00]:
            Type:         Sell
            Price:        1.28627
            Volume:       100
            Volume Real:  100.00
          Market Book by GBPUSD [01]:
            Type:         Sell
            Price:        1.28620
            Volume:       50
            Volume Real:  50.00
          Market Book by GBPUSD [02]:
            Type:         Sell
            Price:        1.28618
            Volume:       20
            Volume Real:  20.00
          Market Book by GBPUSD [03]:
            Type:         Sell
            Price:        1.28615
            Volume:       10
            Volume Real:  10.00
          Market Book by GBPUSD [04]:
            Type:         Buy
            Price:        1.28610
            Volume:       10
            Volume Real:  10.00
          Market Book by GBPUSD [05]:
            Type:         Buy
            Price:        1.28606
            Volume:       20
            Volume Real:  20.00
          Market Book by GBPUSD [06]:
            Type:         Buy
            Price:        1.28605
            Volume:       50
            Volume Real:  50.00
          Market Book by GBPUSD [07]:
            Type:         Buy
            Price:        1.28599
            Volume:       100
            Volume Real:  100.00
       */
      }
    
    


    Schlussfolgerung

    Wir haben den Druck der Felder der vier Strukturen berücksichtigt: MqlDateTime, MqlTick, MqlRates und MqlBookInfo. Die erstellten Funktionen geben eine Beschreibung der Felder jeder Struktur im „Header-Data“-Format als String zurück, der gedruckt oder in einer anderen Funktion verwendet werden kann. Alle Funktionen sind eigenständig, sofort einsatzbereit und können in nutzerdefinierten Programmen „so wie sie sind“ verwendet werden. Der nächste Schritt ist die Beschreibung und Darstellung der Handelsstrukturen.


    Übersetzt aus dem Russischen von MetaQuotes Ltd.
    Originalartikel: https://www.mql5.com/ru/articles/12900

    PrintFormat() studieren und vorgefertigte Beispiele anwenden PrintFormat() studieren und vorgefertigte Beispiele anwenden
    Der Artikel ist sowohl für Anfänger als auch für erfahrene Entwickler nützlich. Wir werden uns die Funktion PrintFormat() ansehen, Beispiele für die Formatierung von Zeichenketten analysieren und Vorlagen für die Anzeige verschiedener Informationen im Terminalprotokoll schreiben.
    Entwicklung eines Replay-Systems — Marktsimulation (Teil 12): Die Geburt des SIMULATORS (II) Entwicklung eines Replay-Systems — Marktsimulation (Teil 12): Die Geburt des SIMULATORS (II)
    Die Entwicklung eines Simulators kann viel interessanter sein, als es scheint. Heute gehen wir ein paar Schritte weiter in diese Richtung, denn die Dinge werden immer interessanter.
    Neuronale Netze leicht gemacht (Teil 49): Soft Actor-Critic Neuronale Netze leicht gemacht (Teil 49): Soft Actor-Critic
    Wir setzen unsere Diskussion über Algorithmen des Verstärkungslernens zur Lösung von Problemen im kontinuierlichen Aktionsraum fort. In diesem Artikel werde ich den Soft Actor-Critic (SAC) Algorithmus vorstellen. Der Hauptvorteil von SAC ist die Fähigkeit, optimale Strategien zu finden, die nicht nur die erwartete Belohnung maximieren, sondern auch eine maximale Entropie (Vielfalt) von Aktionen aufweisen.
    Entwicklung eines Replay-Systems — Marktsimulation (Teil 11): Die Geburt des SIMULATORS (I) Entwicklung eines Replay-Systems — Marktsimulation (Teil 11): Die Geburt des SIMULATORS (I)
    Um die Daten, die die Balken bilden, nutzen zu können, müssen wir auf das Replay verzichten und einen Simulator entwickeln. Wir werden 1-Minuten-Balken verwenden, weil sie den geringsten Schwierigkeitsgrad aufweisen.