English Русский Español 日本語 Português
preview
MQL5 beherrschen, vom Anfänger zum Profi (Teil II): Grundlegende Datentypen und die Verwendung von Variablen

MQL5 beherrschen, vom Anfänger zum Profi (Teil II): Grundlegende Datentypen und die Verwendung von Variablen

MetaTrader 5Beispiele | 10 Juni 2024, 11:06
193 0
Oleh Fedorov
Oleh Fedorov

Einführung

In meinem vorherigen Artikel haben wir uns die wichtigsten Programme angesehen, die von MQL5-Programmierern verwendet werden (und sind zu dem Schluss gekommen, dass die MetaEditor-IDE gut für die Bedürfnisse von Anfängern geeignet ist). Außerdem haben wir einen kurzen Blick auf das Konzept einer Funktion geworfen und ein einfaches Skript erstellt, das eine Meldung im Systemprotokoll ausgibt. Diese Meldungen können am unteren Rand des Terminalfensters auf der Registerkarte Experten angezeigt werden.

Ich möchte Sie daran erinnern, dass eine Funktion eine Beschreibung der Handlung ist.

Wir haben nur vordefinierte Funktionen verwendet: OnStart und Print. Die erste Funktion haben wir mit dem Inhalt gefüllt. Die zweite, die die von uns benötigten Informationen anzeigte, wurde in einem vorgefertigten Formular verwendet, dem wir lediglich die Parameter übergaben. Programmierer können ihre eigenen nutzerdefinierten Funktionen erstellen, die sie zur Lösung ihrer spezifischen Aufgaben benötigen.

Jede Funktion besteht aus sehr elementaren Schritten - Aktionen, die als Anweisungen bezeichnet werden. Solche Aktionen sind recht einfach: zwei Zahlen vergleichen, ein Stück Code mehrmals wiederholen, zwei Textstücke zusammenfügen, eine andere Funktion aufrufen usw. Es gibt nicht viele von ihnen. Wir werden einige der Aussagen in diesem Artikel betrachten.

Eine Folge von Anweisungen bildet einen Algorithmus.

Ein Algorithmus besteht aus klaren und verständlichen Anweisungen an den Ausführenden (in diesem Fall den Computer), bestimmte Aktionen auszuführen, die zur Lösung einer bestimmten, eher globalen Aufgabe führen. Es gibt eine große Anzahl von Algorithmen, da ein und dasselbe Problem in der Regel auf viele verschiedene Arten gelöst werden kann.

Dies betrifft vor allem den Handel. Das Erfassen eines Geschäfts, das Beenden eines Geschäfts, das Drucken der entsprechenden Protokolle und andere Aktionen können auf unterschiedliche Weise realisiert werden. Wir müssen dem Computer ganz klar erklären, was genau Sie (oder Ihr Kunde) in diesem speziellen Fall wollen.

Wir können sagen, dass komplexere Algorithmen aus einfacheren bestehen, und jeder Algorithmus wird durch eine Funktion implementiert, die bestimmte Aktionen ausführt. Diese Aktionen werden auf Daten angewendet. Bei diesen Daten kann es sich um Brief- und Geldkurse oder um Geschäftsvolumina handeln, die mehrmals pro Sekunde eingehen. Andere Beispiele für Daten sind Punkte auf dem Bildschirm, zwischen denen Sie eine gerade Linie oder eine Kurve zeichnen können. Es kann sich auch um einen Ton handeln, der bei der Ausführung eines Geschäfts abgespielt werden soll. Bei den Daten kann es sich um einen Text handeln, z. B. um eine Liste von Kursen für einen bestimmten Zeitraum. Es kann eine Vielzahl von Beispielen geben. Ich hoffe, die Idee ist einfach.

Nun kommen wir zu dem Punkt, dass diese Daten irgendwo gespeichert werden müssen.

Heute werden wir darüber sprechen, wie Daten im RAM gespeichert werden. Die Daten können als Variablen oder Konstanten im Speicher abgelegt werden.

Die Unterschiede sind offensichtlich:

  • Variablen können variieren, d.h. das Programm hat das Recht, solche Daten umzuschreiben.
  • Konstanten bleiben konstant (unverändert) während der gesamten Programmlaufzeit, und wenn der Programmierer versucht, ihre Werte zu überschreiben, wird ein Kompilierungsfehler zurückgegeben.

Ansonsten ist ihre Bedeutung absolut ähnlich: Es handelt sich um einen bestimmten Bereich des Arbeitsspeichers, in dem Daten und keine Prozessorbefehle gespeichert werden. Normalerweise geben die Menschen diesen Speicherbereichen aussagekräftige Namen, um zu verstehen, wofür sie verwendet werden.

Der Compiler entfernt diese Namen, aber wenn Sie Zugriff auf den Quellcode (die Textdatei) haben, können Sie den Zweck der Variablen immer anhand ihres Namens erkennen. Vorausgesetzt natürlich, dass sie richtig beschrieben sind.

Konstanten können in manchen Fällen keine Namen haben. Der Programmierer schreibt einfach, was genau verarbeitet werden soll (z. B. die Zeichenketten, die wir an die Druckfunktion übergeben haben). Solche namenlosen Konstanten werden als Literale bezeichnet.

In diesem Artikel werden wir uns die grundlegenden Datentypen, die Möglichkeiten zur Beschreibung von Variablen und Konstanten sowie die grundlegenden Anweisungen, die ein Programmierer zur Erstellung von Algorithmen verwenden kann, genauer ansehen. Dies wiederum ermöglicht es Ihnen, mehr nützliche Programme als nur „Hello, World“ zu erstellen.


Basiscode zum Testen aller Ausdrücke aus dem Artikel

Im vorigen Artikel haben wir ein einfaches Programm erstellt: ein Skript, das Daten auf der Registerkarte „Experten“ im unteren Bereich des Terminals ausgibt. Und zwar so:

//+------------------------------------------------------------------+
//|                                                   HelloWorld.mq5 |
//|                                       Oleg Fedorov (aka certain) |
//|                                   mailto:coder.fedorov@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Oleg Fedorov (aka certain)"
#property link      "mailto:coder.fedorov@gmail.com"
#property version   "1.00"
//#property script_show_inputs

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
  Print("Hello, MQL5 world!");
  }

//+------------------------------------------------------------------+

Beispiel 1. Vollständiger Text des einfachsten Skripts

Heute werden wir mit diesem Code arbeiten: Wir werden ihn ändern, indem wir die Zeilen aus den Beispielen in geschweifte Klammern einfügen (es sei denn, in den Erläuterungen zu den Beispielen wird ausdrücklich eine andere Stelle für das Einfügen angegeben).


Literale

Schauen wir uns an, wie wir Daten drucken können.

Wir beginnen mit der Zeichenkette.

Ein Zeichenfolgenliteral wird in doppelte Anführungszeichen <"> eingeschlossen. Allerdings lassen sich nicht alle Symbole auf einfache Art und Weise darstellen. Einige von ihnen haben eine besondere Bedeutung in der Sprache (dieselben Anführungszeichen), andere werden überhaupt nicht angezeigt, wie z. B. das Zeilenvorschubzeichen.

Für solche Zeichen gibt es eine besondere Konvention: Sie werden mit einem Backslash geschrieben:

Print(
    "Symbol <\"> can't be placed"
    " without (\\).\n  And we can carrying over the string now."
  );

Beispiel 2. Verwendung von Backslashes zum Drucken von Sonderzeichen

In Beispiel 3 sind die Anführungszeichen, die den ausgegebenen Text beschreiben, grün hervorgehoben, und Sonderzeichen sind gelb hervorgehoben. So bezeichnet „\n“ einen Zeilenumbruch.

Beispiel für die Ausgabe von String-Literalen

Abbildung 1. Beispiel für die Ausgabe von String-Literalen

Bitte beachten Sie auch die folgende Besonderheit. In MQL5 können sehr lange Zeichenketten (strings) an jeder beliebigen Stelle aufgeteilt werden (indem jeder Teil in Anführungszeichen gesetzt wird). Es ist nicht erforderlich, weitere Aktionen hinzuzufügen, um diese Zeilen zusammenzuführen. Wenn der Compiler auf zwei aufeinanderfolgende Zeichenketten-Literale stößt (wie im Beispiel), fügt er die Zeichenketten automatisch zu einer großen Zeichenkette zusammen und sucht dann darin nach Sonderzeichen.

Eine vollständige Tabelle der Sonderzeichen sowie eine genauere Beschreibung der Zeichenkonstanten finden Sie in der offiziellen Hilfe.

Die am zweithäufigsten verwendete Art sind Zahlen.

Ganze Zahlen (integer) haben eine gemeinsame Form:

Print(5);

Beispiel 3. Ganzzahlige Ausgabe

Dezimalzahlen lassen sich ebenfalls recht einfach ausgeben. Das Trennzeichen zwischen dem ganzzahligen und dem dezimalen Teil ist ein Punkt:

Print(5.5);

Beispiel 4. Dezimale Ausgabe

Für sehr große oder sehr kleine Zahlen können Sie die Fließkommadarstellung verwenden (manchmal auch Exponentialform genannt):

Print(5.5e3);
Print(5.5e-3);

Beispiel 5. Verwendung von Fließkomma-Literalen

Das Ergebnis eines Skripts, das alle diese Zahlenformen verwendet, ist in Abbildung 2 dargestellt.

Drucken von Zahlen mit der Funktion Print

Abbildung 2. Das Ergebnis des Druckens von Zahlen mit der Funktion Print

Beachten Sie, wie die Funktion die ihr in den letzten beiden Zeilen übergebenen Daten umwandelt. Dies lässt darauf schließen, dass die Daten als Zahlen erkannt und angemessen verarbeitet wurden.

Manchmal müssen Programmierer mit hexadezimalen Zahlen arbeiten. Anfänger brauchen diesen Typ nur selten, aber manchmal kann er nützlich sein, zum Beispiel um Farben zu beschreiben. Hexadezimale Zahlen bestehen aus Zahlen (0..9) und/oder Buchstaben (a..f).

Damit das Programm versteht, dass es sich um ein hexadezimales Literal handelt, müssen Sie das „0x“ am Anfang der Zahl hinzufügen (Null und den Buchstaben x).

Bei der Darstellung wird nicht zwischen Groß- und Kleinschreibung unterschieden.

Print(0xAF35);

Beispiel 6. Verwendung von Hexadezimalzahlen

Hexadezimale Zahlenausgabe

Abbildung 3. Hexadezimale Zahlenausgabe Ergebnis

Das Ergebnis des Skripts ist in Abbildung 3 dargestellt. Die Zahl wurde umgewandelt (in eine normale ganze Zahl), was bedeutet, dass der Computer sie genau so verstanden hat, wie sie gebraucht wurde.

Ein MQL5-Programmierer muss sehr oft Datumsangaben verwenden.

Für eine vollständige Schreibweise von Datum und Uhrzeit beginnen Sie mit einem Großbuchstaben „D“, gefolgt von einem Apostroph <'>. Dann wird das gewünschte Datum mit Punkten oder Schrägstrichen geschrieben und dann die Uhrzeit nach einem Leerzeichen. Minuten und Sekunden werden mit Doppelpunkten getrennt ein weiteres Apostroph schließt alles ab:

  Print(D'24/12/23');
  Print(D'24.12');
  Print(D'24.12.2023 7:55:34');

Beispiel 7. Verwendung von Datum und Uhrzeit

Beachten Sie, dass im Falle der zweiten Zeile eine Compiler-Warnung erscheint, die besagt, dass das Datum nicht vollständig ist. Die Datei wird jedoch kompiliert, und alle drei Zeilen funktionieren korrekt:

Unvollständige wörtliche Warnung

Abbildung 4. Warnung (MetaEditor) vor unvollständigem Datumsliteral

Ergebnisse des Skripts (Ausgabe der Daten)

Abbildung 5. Ergebnisse des Skripts für die Datumsausgabe (Terminal)

Bitte beachten Sie, dass bei der Kompilierung der ersten Zeile die Startzeit des Tages und bei der Kompilierung der zweiten Zeile die Kompilierungszeit ersetzt wurde. Da das Format korrekt konvertiert wurde, können wir davon ausgehen, dass das Programm es richtig verstanden hat.

Für beliebige Literale können Sie alle Aktionen durchführen, die für einen bestimmten Datentyp zulässig sind.

Sie können zum Beispiel Zahlen vergleichen, arithmetische Operationen durchführen und sie als Parameter an Funktionen übergeben.

Zeichenketten können addiert werden (sie werden zusammengeklebt), aber nicht subtrahiert werden.

Betrachten wir das folgende Beispiel:

Print( "This will be calculated: "+4+9 );
Print( "This will be calculated: "+(4+9) );

Beispiel 8. Verwendung von Klammern beim Schreiben von Ausdrücken.

Compiler-Warnungen über die Verwendung von Zahlen in einem String-Ausdruck

Abbildung 6. Compiler-Warnung über die Verwendung von Zahlen in einem String-Ausdruck

Berechnungsergebnisse

Abbildung 7. Die Funktion gibt das Berechnungsergebnis aus

Wo keine Klammern vorhanden waren, sind die Zahlen einfach in den Text „eingeklebt“. Wenn wir Klammern verwenden, wird alles richtig berechnet. Dies ist ein ziemlich schwer fassbarer Fehler, weshalb uns der Compiler sofort davor warnt. Für die explizite Umwandlung von Zahlen in Zeichenketten gibt es spezielle Funktionen. Aber denken Sie bitte daran: Klammern sind wichtig.


Definition von Konstanten mit der Präprozessoranweisung #define

Wenn Sie in Ihrem eigenen Code nicht durcheinander kommen wollen und den Zweck der in Ihrem Programm verwendeten Daten verstehen wollen, sollten Sie immer versuchen, für alle Konstanten aussagekräftige Namen zu vergeben. Zu diesem Zweck wird normalerweise die Präprozessoranweisung #define verwendet:
#define name value

Beispiel 9. Die Richtlinie #define

Ich möchte Sie daran erinnern, dass die Präprozessorsprache wie eine „Sprache in der Sprache“ ist, und diese Sprache beschreibt Aktionen , bevor die Kompilierung beginnt.

In der Regel zielt der Präprozessor darauf ab, einige Codefragmente durch andere zu ersetzen. Beispielsweise weist die #define-Direktive im ersten Durchgang den Compiler an, im gesamten Code „name“ durch „value“ zu ersetzen und erst danach eine Syntaxprüfung durchzuführen.

Wir können zum Beispiel schreiben:

  #define MY_SUPER_CONSTANT 354
  Print(MY_SUPER_CONSTANT);

Beispiel 10. Die Richtlinie #define

Das Programm gibt den Wert aus, nicht den Namen

Abbildung 8. Das Programm gibt den Wert der Konstante aus, nicht den Namen

Wenn das Programm ausgeführt wird, zeigt es genau die Zahl 354 und nicht den Namen an.

Beachten Sie, dass das Literal, das die Zahl beschreibt, nicht von einem Semikolon gefolgt wird.

Bei der Deklaration von Konstanten mit einer Präprozessoranweisung ist kein Semikolon erforderlich.

Hätten wir ein Semikolon eingefügt, hätte der Präprozessor dieses Zeichen zusammen mit der Zahl innerhalb der Klammer Print eingefügt, und wir hätten eine Fehlermeldung bei der Kompilierung erhalten.

Denken Sie also daran, dass wir eine Konstante benennen und in Ausdrücken ihren Namen und nicht ihren Wert verwenden.

Übrigens sind Namen sehr nützlich, wenn dieselbe Konstante mehrmals an verschiedenen Stellen im Programm verwendet wird oder wenn mehrere Konstanten denselben Wert haben. Wenn sich der Wert einer Konstante ändert, ist es viel einfacher, ihn an einer einzigen Stelle zu ändern, in der Regel ganz am Anfang des Dokuments oder sogar in einer separaten Datei, als ihn an mehreren Stellen suchen und ändern zu müssen.


Beschreibung der Variablen

Denken Sie daran: Wenn Sie damit rechnen, dass sich die Daten im Speicher im Laufe der Arbeit ändern, verwenden Sie Variablen.

Auch die Beschreibung von Variablen ist recht einfach. Schreiben Sie einfach auf, was genau Sie speichern möchten:

type variable_name;

Beispiel 11. Vorlage für Variablendeklaration

Dieser Eintrag bedeutet, dass der Compiler eine bestimmte Menge an Speicher für die Daten reservieren muss. Wir werden später noch genauer auf die Arten und Größen eingehen.

Auf diese Daten kann nun über den Namen (variable_name) zugegriffen werden.


Konventionen zur Kennzeichnung

Der Variablenname (oft Bezeichner genannt) sowie jeder Name, den Sie erstellen, muss:

  • informativ sein („chartNumber“ ist besser als „sss“),
  • aus Buchstaben des lateinischen Alphabets, Zahlen und Unterstrichen (_) bestehen. 

Der Name darf NICHT:

Bei den Namen wird zwischen Groß- und Kleinschreibung unterschieden. Zum Beispiel sind myVariable und MyVariable zwei verschiedene Namen. (Die Verwendung dieser beiden Namen in derselben Datei wird natürlich nicht empfohlen).

Wenn Sie irgendwo im Programmtext versehentlich eine Groß-/Kleinschreibung verwechseln, gibt der Compiler eine Fehlermeldung aus: „Undeclared variable“ (Nicht deklarierte Variable), damit Sie das Problem leicht beheben können. Wenn Sie aber beide Variablen nach allen Regeln der Kunst beschreiben, aber ähnliche Namen verwenden, die sich nur in der Groß- und Kleinschreibung unterscheiden, ist es zu einfach, sie zu verwechseln.

Ansonsten gibt es keine Einschränkungen. Sie können Ihre Variable sogar nach einer integrierten Funktion benennen, wenn Sie wollen (hoffentlich nicht).


Zuweisungsoperator

Um Daten in eine Variable zu schreiben, verwenden Sie die Zuweisungsoperation. Manchmal geschieht dies zum Zeitpunkt der Beschreibung – dieser Fall wird als Initialisierung bezeichnet:

// Initialization (at creation)
int counter = 0;
// Normal assignment
counter = 10;

Beispiel 12. Einfache Zuweisung

Das Wort int zeigt an, dass die Variable nur Daten vom Typ Ganzzahl enthalten kann.

Das Zeichen „=“ steht in diesem Beispiel für den Zuweisungsoperator. In diesem Fall wird eine ganze Zahl in die Zelle mit dem Namen „counter“ geschrieben.

Alle Daten, die sich vor der Zuweisung in der Zelle befanden, gehen verloren.

Die Daten in dieser Variablen können überall im Programm namentlich verwendet werden, z. B. können Sie sie als Parameter an eine beliebige Funktion übergeben oder in einem Ausdruck verwenden (Beispiele finden Sie später im Artikel).


Zuweisungsvorgang - besondere Merkmale

Die Zuordnung kann sehr einfach sein, wie im vorherigen Abschnitt beschrieben. Wenn Sie diese Operation jedoch in Ausdrücken verwenden, werden Ihnen die folgenden Hinweise helfen, sie effektiver zu nutzen.

  • Die Zuweisungsoperation hat die niedrigste Priorität und wird daher von rechts nach links ausgeführt. Auf der rechten Seite befindet sich also ein Ausdruck und auf der linken Seite eine Variable, in die die Daten geschrieben werden. Erstens, der Ausdruck ist:
a = b + c;

Beispiel 13. Die Zuweisung hat die niedrigste Priorität.

Der obige Ausdruck addiert zunächst b und c und schreibt dann das Ergebnis dieses Ausdrucks in die Variable a.

  • Als Folge der vorangegangenen Bemerkung kann der Wert einer Variablen in einem Ausdruck verwendet werden, und das Ergebnis kann dann in dieselbe Variable geschrieben werden:
a = a — c;

    Beispiel 14. Sie können den vorherigen Wert einer Variablen in einem Ausdruck verwenden

    • In MQL5 können Ausdrücke, in denen dieselbe Variable einmal rechts und einmal links erscheint (wie im obigen Beispiel), vereinfacht werden, indem das Vorzeichen des Ausdrucks auf die linke Seite der Operation verschoben wird:
    a -= c;

    Beispiel 15. Kurze Verwendung der Zuordnung

    Diese kurze Verwendung gilt für alle binären Operatoren (zwei Werte verwendenden, wie eine Summe oder Multiplikation): Multiplikation, Division, Verschiebung usw. Es ist jedoch zu beachten, dass die Variable in diesem Ausdruck leicht isoliert werden sollte.

    Für den Ausdruck a = a*(1+1/a) zum Beispiel funktioniert dieser Trick nicht mehr, wenn Sie die Klammern nicht öffnen, aber für a = a*(b+c) ist es einfach: a *= b+c.

    • Wenn Sie eine ganze Zahl um 1 erhöhen oder verringern müssen, brauchen Sie überhaupt keine Zuweisung zu verwenden. Stattdessen können Inkrement- und Dekrementoperationen verwendet werden:
    a++; // Increment. Increase a by 1
    b--; // Decrement. Decreases b by 1
    

    Beispiel 16. Inkrement und Dekrement

    Diese Operationen sind unär, d.h. sie benötigen nur eine Variable, um zu funktionieren. Für solche Operationen gibt es zwei Notationsformen: Präfix und Postfix.

    Bei der Verwendung in der Präfixform wird zuerst die Aktion ausgeführt, und dann wird das Ergebnis im Ausdruck verwendet.

    Bei der Verwendung in der Postfix-Form wird zuerst der alte Wert der Variablen verwendet, und dann wird die Variable um 1 geändert:

    int a = 1;
    Print (++a); // 2, and a == 2
    Print (a++); // 2, but a == 3
    

      Beispiel 17. Präfix- und Postfix-Formen von Inkrement (Dekrement wird auf die gleiche Weise verwendet)

      • Mit der „Kaskadierung“ können Sie mehrere Zuweisungsoperatoren in einer Reihe verwenden. Die Reihenfolge der Aktionen von rechts nach links bleibt erhalten.
      int a=1, c=3;
      a = c = a+c; // first a+c (4), then c = 4, then a = c (i.e. a = 4)
      

      Beispiel 18. „Kaskadierende“ Zuweisung


      Grundlegende Datentypen

      Es gibt relativ viele Datentypen.

      Einige von ihnen sind „einfach“ (oder „grundlegend“). Dies sind Typen wie Zeichenketten, Zahlen, Daten, Farben usw. Andere sind „komplex“; der MQL5-Programmierer erstellt solche Typen. In der Regel sind „komplexe“ Datentypen eine Kombination einfacher Datentypen, bei denen mehrere Variablen der Einfachheit halber in einem Block zusammengefasst werden.

      In diesem Artikel werden nur die Basistypen behandelt. Im nächsten Teil werden wir uns mit den komplexen Themen befassen.

      Ganzzahlige Typen

      Ganzzahlen sind die wichtigste Art und Weise, wie ein Computer „denkt“.

      Ganzzahlige Operationen auf einem Computer sind einfach und schnell. Wenn das Ergebnis der Operation jedoch einen bestimmten Wertebereich überschreitet, kann dies zu Datenverlusten führen.

      Der zweite wichtige Punkt: Ganzzahlen können „mit Vorzeichen“ oder „ohne Vorzeichen“ sein.

      Wenn die Zahl „ohne Vorzeichen“ ist, können Sie Zahlen von 0 bis maximal verwenden. Zum Beispiel können Zahlen, die 1 Byte belegen, von 0 bis 28-1= 255 wachsen, was insgesamt 256 Werte ergibt.

      Wenn jemand versucht, die Zahl „256“ oder „-1“ in eine solche Variable zu schreiben, wird ein „Überlauf“ auftreten. In diesem Fall wird das Ergebnis innerhalb der gleichen Grenzen [0..255] liegen, während der Rest der Daten verloren geht. Manchmal kann dies nützlich sein, aber in den allermeisten Fällen ist es besser, andere Methoden für solche Umwandlungen zu verwenden. Sie können z. B. den Rest-Operator verwenden (später in diesem Artikel). Es ist besser, Variablen der Typen zu verwenden, die alle Ihre Daten ohne Verlust aufnehmen können.

      Den Namen der Typen, die mit 0 beginnen (und eigentlich natürliche Zahlen beschreiben), wird der Buchstabe „u“ (für unsigned) vorangestellt.

      „Vorzeichenbehaftete“ Zahlen verwenden denselben Wertebereich, der halbiert wird. In der ersten Hälfte werden negative Zahlen gespeichert, in der zweiten Hälfte positive Zahlen. Somit sind die gleichen Ein-Byte-Zahlen im Bereich [-128..127] korrekt.

      Tabelle 1. Ganzzahlige Datentypen.

      Name
      Größe, Bytes
       Minimaler Wert
      Maximaler Wert
      char
      1 (8 Bit)
      -128
      127
      uchar
      1 (8 Bit)
      0
      255
      short
      2 (16 bits)
      -32 768
      32 767
      ushort
      2 (16 bits)
      0
      65 535
      int
      4 (32 bits)
      -2 147 483 648
      2 147 483 647
      uint
      4 (32 bits)
      0
      4 294 967 295
      long
      8 (64 bits)
      -9 223 372 036 854 775 808
      9 223 372 036 854 775 807
      ulong
      8 (64 bits)
       0  18 446 744 073 709 551 615

      In der Praxis werden am häufigsten die Typen int (weil dieses Wort schnell zu schreiben ist und Daten dieses Typs recht groß sind) und long (die Größe ist für die meisten Aufgaben ausreichend, der Compiler kann den Bytecode für die beste Leistung auf modernen Computern optimieren) verwendet.

      Aber auch andere Arten sind nützlich.

      Logisch

      Dieser Typ wird durch das Schlüsselwort bool angegeben, belegt 1 Byte Speicherplatz und kann nur zwei Werte annehmen: true oder false (wahr oder falsch).

      Wenn es unbedingt erforderlich ist, kann eine beliebige Zahl als logischer Wert verwendet werden. Ist die Zahl z. B. gleich 0, so ist sie „falsch“, in allen anderen Fällen ist sie „wahr“. Sie sollten jedoch sehr vorsichtig sein, wenn Sie Zahlen für diesen Zweck verwenden.

      Reelle Zahlen (auch Gleitkommazahlen genannt)

      Tabelle 2. Datrentyp reelle Zahlen

      Name
       Größe, Bytes Minimaler positiver Wert  Maximaler Wert  
      float
      4 (32 bits)
      1.175494351e-38
      3.402823466e+38
      double
      8 (64 bits)
      2.2250738585072014e-308
      1.7976931348623158e+308

      Der Typ „double“ wird hauptsächlich in der modernen Praxis verwendet. Ich habe den Typ „float“ schon sehr lange nicht mehr im Code anderer Leute gesehen. Sie wird wahrscheinlich aus Gründen der Kompatibilität mit älteren Versionen verwendet. Bei sehr großen Datensätzen kann dies jedoch nützlich sein, um Speicherplatz zu sparen.

      Reelle Zahlen können Preise, Währungsbeträge und andere nützliche Konzepte darstellen.

      Sie decken einen viel größeren Wertebereich ab als ganze Zahlen.

      Allerdings ist es für einen Computer nicht sehr bequem, mit diesen Typen zu arbeiten. Erstens sind Operationen mit reellen Zahlen etwas langsamer als mit ganzen Zahlen. Zweitens sind die Berechnungen aufgrund der Besonderheiten des Formats fast immer mit Fehlern in den letzten Ziffern verbunden. Daher können Sie statt 1,0 in einigen Fällen 1,00000001 und in anderen Fällen 0,99999999 erhalten.

      Wenn es also notwendig ist, zwei reelle Zahlen zu vergleichen, sollte man in der Regel ihre Differenz nehmen und sie mit einem kleinen Wert vergleichen, der aber definitiv größer als der Fehler ist. Das ist ein zuverlässigerer Weg.

      Datum und Uhrzeit

      Der Typ wird durch das Wort datetime bezeichnet; er belegt 8 Bytes im Speicher.

      Jede Variable dieses Typs enthält die Anzahl der Sekunden, die seit dem 1. Januar 1970 bis zum gewünschten Datum vergangen sind. Es handelt sich also um eine reguläre ganze Zahl.

      Der letztmögliche Termin ist der 31. Dezember 3000. Das reicht für unsere Lebenszeit aus, sodass wir das „Jahr-2000-Problem“ (falls Sie sich erinnern) nicht fürchten müssen.

      Es gibt spezielle vordefinierte Konstanten:

      • __DATE__ — Datum der Kompilierung
      • __DATETIME__ — Datum und Uhrzeit der Kompilierung
      • Sie können den Ausdruck __DATETIME__- __DATE__ verwenden - er beschreibt nur die Kompilierungszeit, ohne das Datum.

      Wenn Sie ein Literal schreiben, können Sie alles weglassen und den Wert als D'' (D und zwei Apostrophe) schreiben. Diese Notation ist äquivalent zu __DATETIME__. Dies verschlechtert jedoch die Lesbarkeit des Codes.

      Farben

      Die Farbe in MQL5 wird durch einen separaten Typ color bestimmt. Wenn Sie eine Farbe beschreiben, können Sie ein Literal verwenden:

        color myColor1=C'100,200,30';
        color myColor2=C'0xFF,0x00,0x5A';
      

      Beispiel 19. Beschreiben von Farben mit dezimalen oder hexadezimalen Zahlen

      Sie können auch vordefinierte Konstanten für Webfarben verwenden. Die Namen der Farbkonstanten beginnen mit clr (z. B. clrBlue für Blau). Eine vollständige Liste der Konstanten kann durch Eingabe von clr in MetaEditor oder in der offiziellen Dokumentation eingesehen werden.

      In Beispiel 12 können Sie sehen, dass jede Farbbeschreibung aus drei Fragmenten besteht. Jedes dieser Fragmente beschreibt die Intensität des roten, grünen oder blauen Lichts eines Punktes auf dem Bildschirm (Red, Green, Blue = RGB). Zusammen ergeben sie eine ganze Palette von Farben.

      Wenn man Rot und Grün mischt, erhält man alle Schattierungen von gelb-braun-orange.

      Rot und Blau erzeugen violett-rosa Töne.

      Grün und Blau ergeben verschiedene Variationen von Türkis, Cyan usw.

      Mischt man alle drei Farbtöne in gleichen Anteilen, erhält man eine Reihe von Grautönen: von Schwarz - wenn alle Komponenten „aus“ sind, d. h. eine Intensität von 0 haben - bis hin zu Weiß, wo alle Komponenten eine maximale Intensität von 255 (0xFF) haben.

      Wenn die Proportionen ungleich sind, d. h. die Intensität der einzelnen Komponenten sich von den anderen unterscheidet, werden alle anderen Farbtöne auf dem Bildschirm angezeigt. Grün hellt normalerweise die Gesamtfarbe auf, während Blau sie verdunkelt. Im Allgemeinen gilt natürlich: Je heller die Komponente, desto heller ist sie (und desto heller ist die Gesamtfarbe).

      Alle diese Regeln sind in Tabelle 3 dargestellt, wobei ich die Zellen einfach mit den im Editor verfügbaren Farben eingefärbt habe.

      In der Praxis ist es meist nicht notwendig, die numerischen Werte für jede Farbe zu kennen. Sie können einfach eine Farbe aus einer speziellen Palette auswählen oder eine vordefinierte Konstante übergeben. Ich glaube jedenfalls, dass es nützlich ist zu verstehen, wie alles funktioniert.

      Die Farbdaten belegen 4 Bytes im Speicher, obwohl nur 3 davon verwendet werden. Dies ist in der Vergangenheit geschehen, und dies ist eine allgemeine Vereinbarung für alle Programme, die mit diesem Farbbeschreibungsmodell arbeiten können.

      Tabelle 3. Color examples

      0, 0, 0 156, 15, 15 106, 0, 86 0, 49, 110 0, 110, 41 56, 37, 9 56, 37, 9
      51, 51, 51 191, 3, 3 133, 2, 108 0, 67, 138 0, 137, 44 243, 195, 0 87, 64, 30
      102, 102, 102 226, 8, 0 160, 39, 134 0, 87, 174 55, 164, 44 255, 221, 0 117, 81, 26
      153, 153, 153 232, 87, 82 177, 79, 154 44, 114, 199 119, 183, 83 255, 235, 85 143, 107, 50
      204, 204, 204 240, 134, 130 193, 115, 176 97, 147, 207 177, 210, 143 255, 242, 153 179, 146, 93
      255, 255, 255 249, 204, 202 232, 183, 215 164, 192, 228 216, 232, 194 255, 246, 200 222, 188, 133

      Wenn Sie möchten, können Sie mit Farben auf die gleiche Weise arbeiten wie mit gewöhnlichen ganzen Zahlen.

      Hier ist zum Beispiel der Code:

        color a = C'255,0,0';
        color b = C'0,255,0';
        color d = a+b;
        Print(a," ",b," ",d);
      

      Beispiel 20. Verwendung von Farben in arithmetischen Ausdrücken

      Dies führt zu folgendem Ergebnis:

      Die Ergebnisse der Verwendung von Farben in arithmetischen Ausdrücken

      Abbildung 9. Die Ergebnisse der Verwendung von Farben in arithmetischen Ausdrücken

      Enumerationen

      Der letzte Grundtyp ist die Enumeration.

      Es gibt Situationen, in denen eine Variable je nach den Besonderheiten des Problems nur bestimmte Werte annehmen darf. Ein Trend kann zum Beispiel abwärts, aufwärts oder seitwärts verlaufen. Außerdem gibt es nur die folgenden Arten von Kaufaufträgen: Buy (Kauf zum Marktpreis), Buy Stop (ausstehend, bis der Preis ein bestimmtes Niveau für einen Ausbruch erreicht) und Buy Limit (ausstehend, in Erwartung eines Rebounds). Die Wochentage sind immer dieselben. Ich denke, das Prinzip ist klar.

      In solchen Fällen verwenden wir Enumerationen.

      Die Beschreibung von Enumerationen besteht aus drei Schritten.

      1. Im ersten Schritt müssen Sie die Liste selbst erstellen und sie irgendwie benennen. Der resultierende Name ist der Typname für alle Variablen oder Funktionen. Der einzige Unterschied zwischen diesem Namen und den vordefinierten Typen ist, dass wir ihn uns selbst ausgedacht haben.
      2. Im zweiten Schritt legen Sie eine Variable dieses Typs an.
      3. Und schließlich können Sie im dritten Schritt diese Variable verwenden.
      Beispiel 15 zeigt, wie man eine Enumeration beschreibt und verwendet. Zur Veranschaulichung habe ich die Richtungsbeschreibung (DIRECTION) genommen, die nur drei Werte verwenden kann: „Upward “, „Downward “ and „Aside “ (Auf-, Ab- und Seitwärts).

      //--- First step: creating a new list (new data type)
        enum ENUM_DIRECTION
         {
          Upward,
          Downward,
          Aside
         };
      
      //--- Second step: description (and, if necessary, initialization) of a variable of this type
        ENUM_DIRECTION next=Upward;
      
      //--- Third step: using the variable
        Print(next);
      

      Beispiel 21. Beschreibung und Verwendung der Enumeration

      Normalerweise wird eine Enumerationsliste ganz am Anfang einer Datei erstellt, unmittelbar nach den Präprozessoranweisungen. In diesem Fall ist sie für alle Funktionen unserer Anwendung weltweit verfügbar.

      Sie können es zwar lokal, innerhalb einer Funktion, beschreiben. Dann wird diese Enumeration von anderen Funktionen aus nicht sichtbar sein. Meistens macht das nicht viel Sinn, aber man weiß nie, welche Aufgaben auf einen zukommen.

      Die Namen der Enumerationselemente werden in geschweiften Klammern und durch Kommata getrennt angegeben.

      Nach der schließenden geschweiften Klammer jeder Typbeschreibung (einschließlich der Enumeration) ist ein Semikolon erforderlich. Bei anderen Blöcken ist dies möglicherweise nicht der Fall.

      In der Sprache vordefinierte Enumerationen haben Namen, die in Großbuchstaben geschrieben sind und mit dem Präfix ENUM_ beginnen. Sie können Ihre Enumerationen benennen, wie Sie wollen (innerhalb der Grenzen), aber es ist gute Praxis, sich an dieselben Standards zu halten.

      Die interne Darstellung für Enumerationen ist eine Ganzzahl mit Vorzeichen, die 4 Byte im Speicher belegt.

      Wenn wir versuchen, den Code aus Beispiel 21 auszuführen, werden wir die Zahl 0 sehen. Das bedeutet, dass MQL5 bei der Auswahl von Zahlen für Enumerationselemente ganz von vorne anfängt, wenn wir sie selbst auswählen lassen.

      Sie können aber auch eine andere Zahl angeben, Sie müssen sie nur explizit festlegen:

      //--- First step: creating a new list (new data type)
        enum DIRECTION
         {
          Upward = 1,
          Downward = -1,
          Aside = 0
         };
      

      Beispiel 22. Enumerationswerte explizit setzen

      Es ist nicht notwendig, alle Werte anzugeben.

      Wenn einige Werte angegeben sind und andere nicht, wählt MQL5 die Zahlen selbst aus, basierend auf der Reihenfolge der Elemente und der letzten höchsten Zahl. Das heißt, wenn wir in Beispiel 15 Upward = 1 setzen und alle anderen Initialisierungen entfernen, dann ist Downward gleich 2 und Aside gleich 3. Sie sollten dies selbst ausprobieren.


      Ausdrücke und einfache Operatoren

      Wenn wir mit Daten arbeiten, ist es wichtig, dass wir sie vergleichen, mathematische Operationen durchführen können usw. Für verschiedene Datentypen können unterschiedliche Ausdrücke verwendet werden.

      Vergleichende Operatoren

      Diese Operatoren sind für alle Datentypen sinnvoll.

      Das Ergebnis des Vergleichs ist logisch.

      Es gibt die folgenden Vergleichsoperatoren:

      • Größer als ( > ), 
      • Kleiner als ( < ), 
      • Größer als oder gleich ( >= ), 
      • Kleiner als oder gleich ( <= ), 
      • gleich ( == ), 
      • nicht gleich ( != )

      Die Priorität all dieser Operationen ist die gleiche.

      Beim Vergleich von Zeichenketten richtet sich der Computer nach der Anordnung der Zeichen in der Kodierung. Zum Beispiel steht das große „A“ vor dem kleinen „a“ und ist daher kleiner. Deshalb:

      "An apple" < "a pal" //true

      Beispiel 23. Streicher vergleichen. Großbuchstaben sind kleiner als Kleinbuchstaben

      Befinden sich mehrere gleiche Symbole in einer Reihe, wird das erste ungleiche Symbol zum Vergleich ausgewählt.

      "An apple" > "A pal" //true

      Beispiel 24. Die ersten Buchstaben sind die gleichen

      Der Ausdruck in Beispiel 24 ist korrekt, da das Leerzeichen in der Kodierung vor den alphabetischen Zeichen steht und die ersten Buchstaben gleich sind.

      Wenn eine Zeile bereits beendet ist und die zweite fortgesetzt wird, während der Anfang identisch ist, wird die beendete Zeile als weniger lang angesehen. Zum Beispiel:

      "An apple" < "An apple was found" //true

      Beispiel 25. Unterschiedliche Zeilenlängen

      Arithmetische Operationen

      Das Ergebnis wird durch den im Ausdruck verwendeten Datentyp bestimmt.

      Sie können arithmetische Operationen mit Zahlen durchführen:

      • Vorzeichen vor der Zahl ( -3) (manchmal auch als „unäres“ Minuszeichen bezeichnet);
      • Multiplikation ( * ), Division ( / ) (bei ganzen Zahlen wird abgerundet), Rest der Division ( % ) (nur bei ganzen Zahlen, 5%2 == 1);
      • Addition ( + ), Subtraktion ( - );
      • Inkrement ( ++ ), Dekrement ( -- )

      Die Liste ist in der Reihenfolge ihrer Priorität aufgeführt.

      Es ist jedoch besser, Inkrement und Dekrement in gewöhnlichen Ausdrücken nicht mit anderen arithmetischen Operatoren zu mischen, da es Situationen geben kann, in denen das Ergebnis nicht definiert ist.

      Die Operation ( + ) ist auch für Zeichenketten definiert, aber hier bedeutet sie ankleben (aus zwei kurzen Zeichenketten eine lange Zeichenkette machen).

      Bitweise Operationen

      Das Ergebnis ist eine ganze Zahl.

      Für ganze Zahlen gibt es auch die folgenden bitweisen Operationen:

      • bitweise Negation ( ~ )
      • Rechtsverschiebung ( >> )
      • Linksverschiebung ( << )
      • bitweise „und“ ( & )
      • bitweise „oder“ ( | )
      • ausschließlich „oder“ ( ^ )

      Wenn Sie diese benötigen, sind Sie definitiv kein Anfänger mehr und können die erforderlichen Informationen in der Sprachdokumentation finden :-)

      Die Liste ist in der Reihenfolge ihrer Priorität aufgeführt.

      Logische Operatoren

      Das Ergebnis ist logisch.

      • logische Negation ( ! )
      • logische Multiplikation - logisches „und“ ( && );
      • logische Ergänzung - logisches „oder“ ( || ).

      Die Liste ist in der Reihenfolge ihrer Priorität aufgeführt.

      Es gibt noch weitere Operationen, die in anderen Artikeln behandelt werden. In anderen Artikeln werden wir Beispiele für die Verwendung aller oben genannten Operatoren ausführlicher behandeln. Sie können vorerst das verwenden, was Sie verstehen, oder die Sprachdokumentation einsehen. Es sollte keine besonderen Schwierigkeiten geben.


      Typen Umwandlung (casting)

      Manchmal umfasst ein arithmetischer Ausdruck mehrere Datentypen. Zum Beispiel drucken wir mit der Print-Funktion ständig Zeichenketten zusammen mit Zahlen, und in diesem Artikel sind wir sogar auf Farben gestoßen.

      Welcher Art wird das Ergebnis sein? Hier haben wir die Wahl zwischen zwei Möglichkeiten: Entweder wir bestimmen selbst, was am Ende herauskommt, oder wir vertrauen dem Compiler.

      Der Compiler ist natürlich intelligent und kann das herausfinden. Aber nicht immer.

      Sehen wir uns also an, was der Compiler macht und was man „von Hand“ tun kann, um keine wichtigen Daten zu verlieren, keine Warnungen während der Kompilierung zu erhalten und sich auf das Ergebnis verlassen zu können.

      Was macht der Compiler?

      Erstens: Wenn der Ausdruck Daten desselben Typs verwendet, dann ist auch das Ergebnis vom selben Typ. Dies ist der einfachste Fall.

      Wenn verschiedene Typen beteiligt sind, wird der Compiler versuchen, das Ergebnis auf den genauesten zu erweitern. Wenn wir zum Beispiel versuchen, eine 4-Byte-Ganzzahl ( int ) mit einem Datum ( datetime ) zu addieren, erhalten wir ein Datum (da der Bereich größer ist).

      Ein Integer-Literal ist vom Typ int, ein Fließkomma-Literal ist normalerweise vom Typ double, es sei denn, es wird durch ein kleines „f“ abgeschlossen:

      5 + 3.4f + 4.25 // The result is double, since 5 is first converted to float, and then 4.25 sets double precision

      Beispiel 26. Typisierung bei der Verwendung von Literalen

      Die Hilfedokumentation enthält das Prioritätsschema für den Typ Casting:

      Prioritäten bei der Typenwahl

      Abbildung 10. Prioritäten bei der Typenwahl

      Es ist zu beachten, dass die Umwandlung von vorzeichenbehafteten und vorzeichenlosen Typen ineinander potenziell zu Datenverlusten führen kann, und die Umwandlung in den Float-Typ kann zu einer geringeren Genauigkeit führen.

      Wenn Sie also nicht sicher sind, wie der Compiler die Daten konvertieren wird, können Sie überlegen, ob Sie manuell angeben, was in was konvertiert werden soll.

      Wenn Sie ein Ergebnis (oder einen bestimmten Wert) in einen bestimmten Typ umwandeln müssen, können Sie das tun:

      • Schreiben Sie das Ergebnis in eine Variable eines bestimmten Typs. Bei dieser Methode handelt es sich im Wesentlichen um eine Variante des automatischen Gießens, sodass sie mit Vorsicht zu verwenden ist.
      • Verwenden Sie spezielle Datenkonvertierungsfunktionen;
      • Verwenden Sie die Kurzform der Typenumwandlung.
      (int)a+b // converts a to an integer. b remains unchanged
      double (c+d) // absolutely similar to the previous one. In this case, the result of the summation is converted
      
      // and so on - you can use any suitable type
      
      

      Beispiel 27. Kurzform der Typenumwandlung.

      Vergessen Sie nicht, dass Sie mit Klammern die Reihenfolge der Operationen ändern können, da sie die höchste Priorität haben. Wenn Sie sich nicht sicher sind, verwenden Sie Klammern.


      Schlussfolgerung

      Wir haben einen großen Teil der Theorie über grundlegende Datentypen, Variablen und Ausdrücke behandelt. Wenn Sie den Stoff dieses und des nächsten Artikels verstehen, werden Sie fast kein Anfänger mehr sein und eine höhere Stufe erreichen. Wenn Sie verstehen, wie Variablen (das Thema dieses Artikels) und Funktionen (wird im nächsten Artikel behandelt) funktionieren, können Sie sich getrost komplexeren Themen wie OOP zuwenden.

      OOP, objektorientierte Programmierung, gilt als komplexe Materie. Nun, es gibt mehr ideologische als technische Schwierigkeiten

      Denjenigen, die einige Punkte nicht verstanden haben, empfehle ich, den Artikel noch einmal (ein oder mehrere Male) ganz langsam zu lesen, ein Konzept nach dem anderen, und alles zu überprüfen, was im Code steht.

      Wer alles verstanden hat und nicht warten will, bis ich mit dem nächsten Artikel fertig bin, dem empfehle ich, sich die Wartezeit zu verkürzen, indem er ein eigenes Skript schreibt, das nützliche Informationen über seine Arbeitssymbole und sein Gleichgewicht anzeigt. Ein Großteil dieser Informationen kann über die Funktionsfamilien AccountInfo und SymbolInfo abgerufen werden.

      Versuchen Sie, die vollständigen Namen für jede Funktion in diesen Familien mit MetaEditor zu finden, und schlagen Sie dann ihre Beschreibungen in der Hilfe nach. Mit diesen Beschreibungen und dem in diesem Artikel behandelten Material wird die Erstellung dieses Skripts nicht allzu viel Aufwand für Sie bedeuten.

      P.S. Ein Beispiel für ein solches Skript finden Sie in der Standardbibliothek. Wenn Sie Ihr eigenes Skript nicht schreiben wollen, versuchen Sie, das fertige Skript zu analysieren. Wenn es Ihnen gelingt, ein eigenes Programm zu schreiben, vergleichen Sie es mit dem Programm aus der Standardbibliothek.

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

      Neuronale Netze leicht gemacht (Teil 70): Operatoren der Closed-Form Policy Improvement (CFPI) Neuronale Netze leicht gemacht (Teil 70): Operatoren der Closed-Form Policy Improvement (CFPI)
      In diesem Artikel werden wir uns mit einem Algorithmus vertraut machen, der geschlossene Operatoren zur Verbesserung der Politik verwendet, um die Aktionen des Agenten im Offline-Modus zu optimieren.
      Neuronale Netze leicht gemacht (Teil 69): Dichte-basierte Unterstützungsbedingung für die Verhaltenspolitik (SPOT) Neuronale Netze leicht gemacht (Teil 69): Dichte-basierte Unterstützungsbedingung für die Verhaltenspolitik (SPOT)
      Beim Offline-Lernen verwenden wir einen festen Datensatz, der die Umweltvielfalt nur begrenzt abdeckt. Während des Lernprozesses kann unser Agent Aktionen generieren, die über diesen Datensatz hinausgehen. Wenn es keine Rückmeldungen aus der Umwelt gibt, wie können wir dann sicher sein, dass die Bewertungen solcher Maßnahmen korrekt sind? Die Beibehaltung der Agentenpolitik innerhalb des Trainingsdatensatzes ist ein wichtiger Aspekt, um die Zuverlässigkeit des Trainings zu gewährleisten. Darüber werden wir in diesem Artikel sprechen.
      Kausalschluss in den Problemen bei Zeitreihenklassifizierungen Kausalschluss in den Problemen bei Zeitreihenklassifizierungen
      In diesem Artikel werden wir uns mit der Theorie des Kausalschlusses unter Verwendung von maschinellem Lernen sowie mit der Implementierung des nutzerdefinierten Ansatzes in Python befassen. Kausalschlüsse und kausales Denken haben ihre Wurzeln in der Philosophie und Psychologie und spielen eine wichtige Rolle für unser Verständnis der Realität.
      Die Gruppenmethode der Datenverarbeitung: Implementierung des Kombinatorischen Algorithmus in MQL5 Die Gruppenmethode der Datenverarbeitung: Implementierung des Kombinatorischen Algorithmus in MQL5
      In diesem Artikel setzen wir unsere Untersuchung der Algorithmenfamilie Group Method of Data Handling mit der Implementierung des Kombinatorischen Algorithmus und seiner verfeinerten Variante, dem Kombinatorischen Selektiven Algorithmus in MQL5 fort.