MetaTrader 5 herunterladen

MQL4 Sprache für Einsteiger. Schwierige Fragen in Einfachen Sätzen.

9 Februar 2016, 11:37
Antoniuk Oleg
0
752

Einführung

Dies ist der zweite Artikel "MQL4 Sprache für Einsteiger". Der erste Artikel "MQL4 Sprache für Einsteiger. Einführung" beschreibt was wie mit MQL4 machen können, haben wir haben gelernt einfache Skripte zu schreiben, untersuchten was eine Variable ist, erfuhren, wie wir mit Variablen arbeiten, analysierten Funktionen, Arrays, eingebaute Arrays und Variablen, die Zyklen 'for', sowie einfache und komplexe Bedingungen. Nun werden wir komplexere und fortschrittlichere Konstruktionen der Sprache untersuchen, neue Möglichkeiten erfahren und sehen, wie diese in der täglichen Praxis angewandt werden können. Sie werden sich vertraut machen mit einem neuen Zyklus-Typ 'while, neuen Bedingungs-Typ 'switch', den Operatoren 'break' und 'continue'. Außerdem werden Sie lernen Ihre eigenen Funktionen zu schreiben und mit mehrdimensionalen Arrays zu arbeiten. Und als Nachtisch habe ich eine Erklärung über einen Präprozessor vorbereitet.


Empfehlung

Fangen Sie nicht an diesen Artikel zu lesen, wenn Sie den ersten nicht vollständig verstanden haben. Sie werden viele Fehler machen und weiter nichts verstehen. Dieser Artikel basiert auf dem vorherigen Material, also hetzen Sie sich nicht! Ich möchte es Ihnen einfach machen - die Schwierigkeiten auf die Sie treffen, wenn Sie das neue Material lernen, sind tückisch. Es wird die Zeit kommen, in der Sie nicht nachdenken müssen, wie die Zyklen geschrieben werden, welche Bedingungen gesetzt werden müssen - alles wird mechanisch ablaufen. Je mehr Sie mit der MQL4 Sprache arbeiten, je einfache wird deren Verwendung für Sie sein.

Neuer Typ Zyklus - while

Ich möchte erwähnen, dass der Zyklus 'for', beschrieben im vorherigen Artikel, eine universeller ist und für jeden anderen Typ ersetzt werden kann, die wir jetzt lernen werden. Allerdings ist es nicht immer komfortabel und geeignet. Manchmal ist es effizienter while zu verwenden. Sie werden bald verstehen, welcher Zyklus-Typ sinnvoller ist. Machen wir eine Aufgabe auf zwei Arten: Lassen Sie und das Geamtvolumen aller Balken finden, mit beiden Zyklen, und die Unterschiede betrachten:

// using the cycle for
double sum = 0.0;
 
for(int a = 0; a < Bars; a++)
    sum += Volume[a];
 
// now using while, the result is the same
double sum = 0.0;
int a = 0;
 
while(a < Bars)
  {
    sum += Volume[a];
    a++;
  }

Sie sehen, der Zähle ist deklariert und getrennt verwendet. 'While' zeigt hier, dass während die Bedingung erfüllt ist, der Zyklus weiterläuft. Hier ist eine allgemeine Form:
while(condition of cycle fulfillment)
  {
    code
  }

Hier ein einfacheres Beispiel:

while(I haven't eaten up the apple) // condition
  {
    // what to do, if the condition is not fulfilled
    bite more;                 
  }

Tatsächlich unterscheidet sich der Zyklus 'whle' von dem Zyklus 'for' nur durch das Fehlen eines Zählers. Wenn Sie ihn nicht benötigen, verwenden Sie 'while'. Zum Beispiel, ich verwende while häufig mit einem Zähler, es ist Geschmackssache. Wie im Fall von for, wenn der Zyklus body nur eine Anweisung enthält, können sie Klammern auslassen. Denken Sie auch für Ihre Entwicklung an die Bedeutung des Wortes Iteration. Es ist einer von mehreren Durchläufen (Wiederholungen), durchgeführt durch den Zyklus. Das heißt, einmaliges Ausführen eines Zyklus body bedeutet, dass eine Iteration ausgeführt wird.

Neuer Typ von Bedingungen - switch

Wie in dem Fall mit Zyklen, muss angemerkt werden, dass switch durch eine Kombination der Ihnen bekannten Bedingungen 'if' und 'else' ersetzt werden kann. Die Konstruktion 'switch' wird verwendet, wenn Sie einige Vorgänge ausführen müssen, die von dem Wert einer Variable abhängen. Das ist wie ein normaler Modus-Schalter an einem Mikrowellenherd. Zum Beispiel, stellen Sie sich vor, dass Sie einen Expert Advisor schreiben und er sein Verhalten abhängig von der Marktsituation ändert. Lassen Sie ien Variable int marketState dafür verantwortlich sein. Sie kann die folgenden Bedeutungen annehmen:

  • 1 - Aufwärtstrend
  • 2 - Abwärtstrend
  • 3 - Seitwärtsbewegung (Flat)

Egal wie diese Position definiert wird, unsere Aufgabe ist es eine Art Mechanismus umzusetzen, damit der Expert Advisor, abhängig von der Marktsituation, die entsprechenden Vorgänge ausführt. Nun, Sie wissen wie man das macht. Die offensichtlichste Variante ist die folgende:

if(marketState == 1)
  {
    // trading strategy for an uptrend
  }
else 
    if(marketState == 2)
      {
        // strategy for a downtrend
      }
    else 
        if(marketState == 3)
          {
            // strategy for a flat
          }
        else
          {
            // error: this state is not supported!
          }

Hier sind einige Besonderheiten:

  • alle Bedingungen werden mit ein und derselben Variable durchgeführt,
  • alle Bedingungen kommen zum Vergleichen der Variable zu einer der Bedeutungen, die die Variable annehmen kann.

Also, alles dies bezieht sich auch auf die switch Struktur. Hier ist ein Code, der switch verwendet, das Ergebnis ist das gleiche:

switch(marketState)
  {
    case 1:  // trading strategy for an uptrend
             break;
    case 2:  // strategy for a downtrend
             break;
    case 3:  // strategy for a flat
             break;
    default: // error: this state is not supported!
             break;
  }

Beachten Sie, dass wir zuerst bestimmen, welch Variable verglichen wird:

// switch - key word, marketState - 
// a variable for comparison
switch(marketState)

und dann angeben, was in bestimmten Fällen getan wird:

 
case 1:                        // case - key word; 
   // trading strategy         // if marketState is equal to 1, then 
   // for an uptrend           // perform this code
   break;                      // key word that indicates  
                               // the end of actions in this case
 
case 2:                        // if marketState is equal to 2, then
    // startegy for            // perform this
    // a downtrend          
    break;                     // end
 
case 3:                        // identical
    // strategy for flat
    break;
 
default:                       // otherwise, perform this
    // error: this   
    // state is not 
    // supported!
    break;

In einer allgemeinen Sicht, hat switch die folgende Form:

switch(a variable for comparison)
  {
    case [a variable value]:
    // a code for this case 
    break;
   
    case [another value of the variable]
    // a code for this case
    break;
   
    default:
    // a code for all other cases
    break;
  }

Verwenden Sie switch, wenn Sie eine Variable mit mehreren Werten vergleichen und ein bestimmter Code Block einem Wert entspricht. In anderen Fällen verwenden Sie eine übliche Kombination aus 'if' und 'else' Bedingungen. Manchmal müssen Sie Code in mehreren Werten einer Variable ausführen. Zum Beispiel, wenn marketState == 1 oder 2, dann führe einen bestimmten Code aus. So kann dies mit switch gemacht werden:

switch(marketState)
  {
    case 1:  // if marketState is equal to 1
    case 2:  // or if marketState is equal to 2, then
             // perform this
             break;
 
    default: // in any other case perform 
             // this code
             break;
  }

Operatoren: continue and break

Wir haben gerade den Operator break gesehen. Er wird verwendet um den body von switch zu verlassen. Außerdem können Sie ihn für das Verlassen eines Zyklus verwenden. Zum Beispiel, wenn Sie unter einigen Bedingungen keine Ausführung eines Zyklus benötigen. Angenommen wir müssen die Anzahl der ersten Balken finden, die gebraucht werden um 1000 Punkte zu einzuschließen. Wir können den folgenden Code scheiben:

int a = 0;
double volume = 0.0;
 
while(volume < 1000.0)
  {
    volume += Volume[a]; // equivalent to volume = volume + Volume[a]; 
    a++;
  }
 
// now variable "a" includes the amount of bars, the volume of their sums 
// is no less than 1000 points

Schreiben wir nun einen analogen Code mit dem Operator break:

int a = 0;
double volume = 0.0;
 
while(a < Bars)
  {
    // if the volume is exceeds 1000 points, then
    if(volume > 1000.0) // exit the cycle   
        break;            
 
    volume += Volume[a];
    a++;
  }

Sie sehen, der Operator break ist einfach-zu-verwenden und ermöglicht unerwünschte Zyklus-Iterationen zu vermeiden. Ein weiterer nützlicher Operator, continue , ist gedacht zum 'Weglassen' unerwünschter Iterationen. Angenommen wir müssen das Gesamtvolumen berechnen, aber wir dürfen das Volumen von Balken in Momenten wichtiger Nachrichten nicht berücksichtigen. Wie Sie wissen, beinhalten wichtige Nachrichten große Volumen an Punkten. Stellen wir uns vor, wir sind naive Kinder und nehmen an, dass Balkenvolumen von 50 Punkten oder mehr Nachrichten sind. Um die Aufgabe zu lösen, verwenden wir den continue Operator :

int a = -1;
double volume = 0.0;
 
while(a < Bars)
  {
    a++;
    // if the volume exceeds 50 points, then it must 
    // be news, omit it 
    if(Volume[a] > 50.0)          
        continue;          
    volume += Volume[a];
  }

Sie sehen, die Verwendung des continue Operator ist ziemlich trivial, aber manchmal kann es Ihnen helfen. Es ist klar, dass dieses Skript für kleine Zeitrahmen gedacht ist.


Eigene Funktionen schreiben

Aber warum brauchen wir sie? Tatsache ist, dass Sie sehr oft Duplikationen Ihres Codes finden. Das heißt, sie verwenden ein und denselben Satz Anweisungen in verschiedenen Fällen. Um Zeit und Kraft zu sparen, können Sie diesen duplizierten Code in eine separate Funktion schreiben. Und wenn Sie ihn brauchen, schreiben sie einfach den Namen der Funktion und sie wird alles für Sie machen. Sehen wir uns an, wie es funktioniert. Angenommen Sie müssen die Farbe einer Kerze finden. Es ist bekannt, dass eine weiße Kerze diejenige ist, die höher schließt als sie geöffnet hat, die Schwarze - umgekehrt. Schreiben wir einen Code zur Bestimmung der Farbe einer Kerze:

bool color; // as there are only 2 variants 
            // (white or black candlestick), 
            // then suppose that the velue 
            // false corresponds to a black 
            // candlestick, and true - white
 
if(Close[0] > Open[0])
    color = true;      // white candlestick
    
if(Open[0] > Close[0])
    color = false;     // black candlestick

Das ist alles, nun enthält die Variable color die Farbe der letzten Kerze. Um die Farbe einer anderen Kerze zu bestimmen, zum Beispiel die vorletzte, müssen Sie den Index von 0 auf 1 ändern. Aber müssen Sie den Code nicht jedes Mal angeben, wenn Sie die Farbe einer Kerze finden müssen? Und was, wenn es dutzende solcher Fälle gibt? Deshalb brauchen wir Funktionen. Überlegen wir, wie es funktionieren kann. Eine solche Funktion sollte ein Argument annehmen - den Index der Kerze, deren Farbe Sie bestimmen müssen, und die Farbe zurückgeben - eine Variable des bool Typs. Nehmen wir an, die Funktion ist geschrieben und wir aktivieren sie:

bool color; // here will be the color of a wanted candlestick
 
color = GetColor(0);

Wie Sie vielleicht vermutet haben, nennt sich unsere Funktion GetColor. In diesem Funktionsaufruf möchten wir die Farbe der letzten Kerze finden. Deshalb ist das einzige Argument gleich Null. Die Funktion gibt die Farbe einer Kerze zurück, also machen wir eine Zuordnung auf einmal. Es ist ein sehr wichtiger Moment! Eine Variable wird innerhalb der Funktion erstellt, dann wird ihr Wert den Funktionsaufruf ersetzen. Letztlich wird der Funktionsaufruf und der Code der Funktionsbestimmung, oben beschrieben, das gleiche Ergebnis ergeben - die Variable wird die Farbe der letzten Kerze enthalten, aber durch die Verwendung von Funktionen benötigen wir weniger Aufwand.

Und jetzt gehen wir unerwartet zurück zu dem Code eines leeren Skripts. Tatsache ist, dass er bereits die volle Beschreibung der Funktion start() enthält. Das interessanteste daran ist, dass Sie die ganze Zeit Skripte 0n dieser Funktion geschrieben haben! Wen Sie ein Skript starten, aktiviert das Terminal die Funktion start(). Untersuchen wir den Code eines leeren Skripts:

int start()

Diese Zeile ist sehr wichtig! Sie enthält den Name der Funktion, d.h. ein Schlüsselwort, dass Sie schreiben werden um diese Funktion zu aktivieren. In unserem Fall ist es 'start'. Sie enthält außerdem den Typ eines zurückgegebenen Werts - int. Es bedeutet, dass nach der Ausführung der Funktion ein Wert vom Typ int von ihr zurückgegeben wird. Die Klammer enthält eine Liste mit Argumenten, aber in unserem Fall nimmt die Funktion keine Parameter an.

Dann sehen Sie in Klammern die Funktionsbeschreibung, d.h. ein Code, der bei Funktionsaufruf ausgeführt wird:

  {
    //----
    // a code that will be performed 
    // at the function call.
    //----
    return(0);
  }

Es ist klar, dass wir einen Code in den body der start() Funktion geschrieben haben. Am Ende der Funktion sehen wir den Operator return, der den Funktions-Wert zurückgibt. In unserem Fall gibt er Null zurück.

Schauen Sie nun auf die allgemeine Form des Schreibens einer Funktion:

[type of return value] [function name] ([list of arguments])
  {
    // function code
    return([a value, which the function returns]);
  }

Gehen wir zurück zu unserer Kerze und der GetColor Funktion. Sehen Sie sich den Code dieser Funktion an:

bool GetColor(int index)
  {
    bool color;
    if(Close[index] > Open[index])
        color = true;      // white candlestick
    if(Open[index] > Close[index])
        color = false;     // black candlestick
    return(color);
  }

Bleiben wie bei der ersten Zeile:

bool GetColor(int index)

Hier haben wir: bool - Typ des zurückgegebenen Wertes, GetColor - Name der Funktion, int - Typ des Arguments index - Name des Arguments. Beachten Sie, wir verwenden index innerhalb des Funktion, aber in dem Funktionsaufruf wird dieser Name niemals genannt. Zum Beispiel:

bool lastColor = GetColor(0);

Dann:

{
   bool color;
   if(Close[index]>Open[index])
       color=true;      // white candlestick
   if(Open[index]>Close[index])
       color=false;     // black candlestick

Dieser Funktions-body ist ein allgemeiner Code, der bei jedem Funktionsaufruf ausgeführt wird. Danach:

   return(color);
}

Die Rückgabe des Operators gibt an, was die Funktion Zurückgeben sollte. Der Rückgabewert sollte dem Typ entsprechen, der ganz am Anfang festgelegt wurde. Wenn nötig, können Sie mehrere Operatoren 'return' in einer Funktion verwenden, zum Beispiel:

bool GetColor(int index)
  {
   if(Close[index] > Open[index])
       return(true);      // white candlestick
   if(Open[index] > Close[index])
       return(false);     // black candlestick
  }

Es ist klar, dass die Verwendung mehrerer return Operatoren ermöglicht die Variable color zu vermeiden. Außerdem können Sie in dem Operator return sogar logische Ausdrücke verwenden:

return(Close[index] > Open[index]);

Es ist möglich, weil des Vergleichs auch Variablen des Typs bool (true oder false) zurückgibt, wie einige andere gemeinsame Funktionen. Sieht schwierig aus, aber Sie werden schnell lernen es zu verwenden.

Gehen wir jetzt zurück zu einer Liste von Argumenten. nur das Argument int index wird in unserer Funktion verwendet. Wenn Sie mehrere Argumente verwenden müssen, zählen Sie diese durch Komma getrennt auf:

bool SomeСomplicatedFunction(int fistArgument, int secondArgument, 
                             sting stringArgument)

Um auf die Argumente zu verweisen, verwenden Sie deren Namen wie in der vorherigen Funktion. Wenn ein Funktionsaufruf mit mehreren Argumenten erfolgt, achten Sie auf die Abfolge der Argumente-Reihenfolge: vermischen Sie nichts! Wenn die Funktion keinen Wert zurückgeben soll, verwenden Sie das Schlüsselwort void, um dies anzugeben. Beachten Sie, dass der return Operator in diesem Fall nicht verwendet wird:

void function()
  {
    // code
  }

Ein weiteres Detail: Sie können die Werte für die Funktions-Argumente als Standard festlegen. Was ist das? Angenommen, Sie haben eine komplexe Funktion geschrieben, die 5 Argumente beinhaltet, die ihr Verhalten beeinflussen. Aber mehrere Argumente werden fast immer mit demselben Wert verwendet. Nur für zwei Dutzend Funktionsaufrufe müssen Sie verschiedene Werte verwenden. Um nicht jedes Mal den Wert des letzten Arguments anzugeben, die fast immer dieselben sind, werden Standardwerte von Argumenten verwendet. In einem solchen Fall können Sie das letzte Argument einfach weglassen, so, als würden sie nicht existieren, obwohl sie tatsächlich verwendet werden, aber die Argumente sind als Standard zugewiesen. Wenn Sie auf diese Sonderfälle treffen, geben Sie alle Argumente an. Sehen wir uns an, wie wir eine Funktion mit Standard-Argumenten deklarieren:

void someFunction(int argument1, int argument2, 
                  int specialArgument = 1)
  {
    // code
  }

Sie sehen, alles ich einfach: wir weisen einen benötigten Wert einem benötigten Argument zu und nun kann es bei einem Funktionsaufruf weggelassen werden

someFunction(10,20);   // we omitted the last argument, but 
                       // actually it is assigned a value by default
 
someFunction(10,20,1); // this activation is fully identical to the previous one
 
someFunction(10,20,2); // here we indicate another value,  
                       // it is a rare case

Sie können so viele Standardwerte von Argumenten angeben wie Sie möchten. Aber vergessen Sie nicht eine wichtige Regel: sie sollten alle am Ende platziert sein. Zum Beispiel:

void someFunction(int argument1, int argument2, 
                  int specialArgument = 1)   // all right
 
void someFunction(int argument1, int argument2 = 10, 
                  int specialArgument=1)     // all right
 
void someFunction(int argument1, int argument2 = 10, 
                  int specialArgument)     // wrong! default
                                           // values must stay
                                           // at the end of the 
                                           // list of arguments
                                                                           
void someFunction(int argument1 = 0, int argument2 = 10, 
                  int specialArgument = 1) // you can assign  
                                           // default values  
                                           // to all arguments

Mehrdimensionale Arrays

Sie werden häufig Arrays beider Programmierung verwenden, und in den meisten Fällen werden eindimensionale Arrays ausreichend sein. Aber in einigen Fällen werden Sie zweidimensionale, dreidimensionale Arrays benötigen. Sie werden jetzt lernen diese zu verwenden.

Um damit zu beginnen, lassen Sie uns eindimensionale Arrays, revidierte Deklaration, Initialisierung, Indizes und Wert visuell darstellen:


Jedes eindimensionale Array kann als Reihe von Werten aus einem Typ dargestellt werden. Sehen Sie, wie verschiedene Verweise auf ein eindimensionales Array verarbeitet werden:



Zweidimensionale Arrays sind wie normale Tabellen, sehen Sie:


Wie im Bild zu sehen, haben zweidimensionale Arrays zwei Indizes zum Verweis auf den Wert: der erste Index bestimmt eine Reihe, der zweite Index - eine Spalte. Wie in eindimensionalen Arrays, wird eine Liste mit Werten für die Initialisierung verwendet. So werden die Werte der Tabellenzellen verwiesen an:



Sie sehen, alles ist klar. Sehen wir uns an, wie wir durch alle Werte eines zweidimensionalen Arrays gehen können. Es sollten 2 Zyklen verwendet werden:

int array2D[3][3]={10,20,30,
                   40,50,60,
                   70,80,90};
 
for(int y=0;y<3;y++)
   for(int x=0;x<3;x++)
      MessageBox("array2D["+y+"]["+x+"]="+array2D[y][x]);

In diesem Beispiel geht die Referenzierung abwärts von links nach rechts. Nur als Training, versuchen Sie die Richtung zu änderen, zum Beispiel aufwärts.

Dreidimensionale Arrays unterscheiden sich nur durch das Vorhandensein von einem weiteren Index zum Refenrenzieren der Zellenwerte. Ein dreidimensionales Array kann einfach als mehrere Tabellen (zweidimensionale Arrays) dargestellt werden. So können wir durch alle Elemente eines dreidimensionalen Arrays gehen:

int array3D[3][3][3] = {11, 12, 13,
                        14, 15, 16,
                        17, 18, 19,
 
                        21, 22, 23,
                        24, 25, 26,
                        27, 28, 29,
 
                        31, 32, 33,
                        34, 35, 36,
                        37, 38, 39};
 
for(int z = 0; z < 3; z++)
    for(int y = 0; y < 3; y++)
        for(int x = 0; x < 3; x++)
            MessageBox("array3D["+z+"]["+y+"]["+x+"]=" + 
                       array3D[z][y][x]);

Studieren Sie zweidimensionale und dreidimensionale Arrays gründlich - es ist sehr wichtig. Einmal mehr die aufmerksam die erklärenden Bilder durchsehen. Viele verschiedene Aufgaben werden mit Arrays gelöst, also widmen Sie ihnen genügend Zeit und sie werden in der Zukunft sehr nützlich für Sie sein. Wenn Sie das Prinzip der Arbeit mit Arrays verstehen, werden Sie keine Probleme haben, mit jedem n-dimensionalen Array zu arbeiten.


Einige Funktionen zum Arbeiten mit Arrays

Beginnen wir mit einfachen Funktonen.

int ArraySize(object array[]);

Diese Funktion gibt die Anzahl der Elemente zurück, die das Arrays beinhaltet. Es funktioniert mit allen Typen. Zum Beispiel:

// create two different arrays
int arrayInt[] = {1, 2, 3, 4};           
double arrayDouble[] = {5.9, 2.1, 4.7};
// here store the amount of elements 
int amount;                        
 
amount = ArraySize(arrayInt);      // note: 
                                   // to define a specific 
                                   // array, you need to indicate
                                   // only its name.
                                   // Now amount is equal to 4
 
 
amount = ArraySize(arrayDouble);   // amount is equal to 3

Nächste Funktion:

int ArrayInitialize(object array[],double value);
АrrayInitialize

weist allen Array-Elementen einen Wert zu, gibt die Anzahl der Elemente zurück, denen ein Wert zugewiesen wurde. Verwenden Sie diese Funktion für Arrays des int oder double Typs.


Nächste:

int ArrayMaximum(double array[], int count = WHOLE_ARRAY, 
                 int start = 0);
int ArrayMinimum(double array[], int count = WHOLE_ARRAY, 
                 int start = 0);

Diese zwei Funktionen geben den Index des maximalen und minimalen Zellwertes zurück. Um sie zu verwenden, geben Sie einfach an in welchem Array gesucht werden soll:

int array[] = {10, 100, 190, 3, 1};
// will be returned 1, because array[1] - maximal value 
ArrayMaximum(array); 
// will be returned 4, because array[4] - minimal value
ArrayMinimum(array);

Nächste:


int ArrayDimension(object array[]);

Mit dieser Funktion können Sie die Dimensionalität eines Array bestimmen. Das heißt, Sie können bestimmen, ob es ein eindimensionales, zweidimensionales oder n-dimensionales Array ist. Zum Beispiel:

int array1D[15];
int array4D[3][3][3];
 
ArrayDimension(array1D); // get 1
ArrayDimension(array3D); // 3

Hier sind komplexere und nützliche Funktionen:

int ArraySort(double&array[], int count = WHOLE_ARRAY, int start = 0,
              int sort_dir = MODE_ASCEND);

Diese Funktion sortiert Elemente. Wenn Sie nicht direkt sie Argumente als Standard angeben, zum Beispiel auf diese Weise:

int array[5] = {1, 10, 5, 7, 8};
 
ArraySort(array);

Elemente werden aufsteigend sortiert. Sie können zusätzliche Parameter verwenden, um das Funktionsverhalten festzulegen:

  • int count - die Anzahl der Elemente, die sortiert werden sollen
  • int start - der Index eines Elements, von dem aus die Sortierung beginnen soll
  • int sort_dir - die Richtung der Sortierung (aufsteigend - MODE_ASCEND oder absteigend - MODE_DESCEND)

Hier sollten Sie sich fragen: was ist MODE_ASCEND und MODE_DESCEND?? Nach int, muss es eine Ganzzahl (integer) sein! Seien Sie nicht nervös, alles wird sich im nächsten Teil begradigen - "Präprozessor". Zum Beispiel, wenn Sie 5 Elemente absteigend sortieren müssen, beginnend bei dem zweiten, geben Sie etwas wie dies an:

ArraySort(array, 5, 1, MODE_DESCEND);

Und die letzte Funktion für heute:

int ArrayCopy(object&dest[], object source[], int start_dest = 0,
              int start_source=0, int count=WHOLE_ARRAY);

Sie wird verwendet für das Kopieren von einem Array in ein anderes. Sehen wir uns die obligatorischen Parameter an:

  • dest[] - in welches Array kopiert werden soll
  • source[] - von welchem Array aus kopiert werden soll

Optionale Parameter:

  • start_dest - Index eines Array-Elements, in das das Kopieren ausgeführt wird
  • start_source - Index eines Array-Elements, von dem aus das Kopieren durchgeführt wird
  • int count - die Anzahl der zu kopierenden Elemente

Die Funktion gibt die Anzahl der kopierten Elemente zurück. Verwenden Sie ArrayCopy sehr vorsichtig: stellen Sie sicher, dass Arrays ausreichend Kapazität haben, wenn Sie in sie hinein kopieren!


Präprozessor

Was ist das? Präprozessor ist ein spezieller Mechanismus, vorgesehen für die Verarbeitung von Quellcode. Das heißt, zuerst bereitet ein Präprozessor einen Code vor, und leitet in dann zum Kompilieren. Heute werden wir eine weitere nützliche Möglichkeit lernen - Konstanten.

Was ist der wichtigste Punkt? Um dies zu verstehen, erinnern wir uns an ein Beispiel aus dem Teil über switch:

switch(marketState)
  {
    case 1:
    // trading strategy for an uptrend
    break;
 
    case 2:
    // strategy for a downtrend
    break;
 
    case 3:
    // strategy for a flat
    break;
 
    default:
    // error: this state is not supported!
    break;
  }

Hier haben wir einen Mechanismus aktiviert, der auf verschiedene Arten fungiert, abhängig von der Marktsituation. Sie erinnern sich? Also, es wäre einfacher und beschreibender etwas zu schreiben wie TREND_UP, TREND_DOWN, FLAT anstatt 1, 2 und 3:

switch(marketState)
  {
    case TREND_UP:
    // trading strategy for an uptrend
    break;
 
    case TREND_DOWN:
    // strategy for a downtrend
    break;
 
    case FLAT:
    // strategy for a flat
    break;
 
    default:
    // error: this state is not supported!
    break;
  }

In diesem Fall erscheint ein Quellcode viel verständlicher und klarer, oder nicht? Also, Konstanten ermöglichen das Ersetzen von TREND_UP, TREND_DOWN und FLAT durch die entsprechenden Werte 1, 2 und 3 vor der Kompilierung, alles was Sie tun müssen, ist anzugeben, was der Präprozessor ändern soll. Es wird gemacht mit Hilfe der Präprozessordirektiven, die mit einem speziellen Symbol beginnen "#". Die Präprozessordirektiven sollten am Anfang einer Quelldatei platziert werden, zusammen mit anderen Richtlinien. Sehen wir uns ein komplettes Beispiel der Verwendung von Konstanten an:

//+------------------------------------------------------------------+
//|                                                 preprocessor.mq4 |
//|         Copyright © 2007, Antonio Banderass. All rights reserved |
//|                                               banderassa@ukr.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Antonio Banderass. All rights reserved"
#property link      "banderassa@ukr.net"
 
#define TREND_UP   1
#define TREND_DOWN 2
#define FLAT       3
 
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
   MessageBox("TREND_UP=" + TREND_UP + " TREND_DOWN=" + TREND_DOWN + 
              " FLAT=" + FLAT);
 
   return(0);
  }

Beachten Sie, dass wir die Deklaration der Konstanten an den Anfang der Datei platziert haben, unter den Präprozessordirektiven. Untersuchen wir die Deklaration etwas näher:

#define TREND_UP 1

Zuerst schreiben wir das Schlüsselwort #define. Es zeigt dem Präprozessor, dass danach die Konstanten Deklaration kommt. Dann schreiben wir den Namen der Konstante, ihre Kennung (identifier), d.h. ein Wort, durch das wir auf den Wert der Konstante verweisen. In unserem Fall ist es TRND_UP. Der Wert 1 kommt danach. Wenn nun der Präprozessor TREND_UP im Quellcode sieht, wird er es durch 1 ersetzen, das gleiche mit allen anderen Konstanten. Hier ist der Quellcode vor der Verarbeitung durch einen Präprozessor:

int start()
  {
   MessageBox("TREND_UP=" + TREND_UP + " TREND_DOWN=" + 
              TREND_DOWN + " FLAT=" + FLAT);
   return(0);
  }

und danach:

int start()
  {
   MessageBox("TREND_UP=" + 1 + " TREND_DOWN=" + 2 + 
              " FLAT=" + 3);
   return(0);
  }

Nun sollten Sie verstehen, was MODE_ASCEND und MODE_DESCEND aus dem vorherigen Teil bedeuten. Sie sind Konstanten mit entsprechenden Werten.



Fazit

Also, Sie haben viel neues Material in diesem Artikel gelernt: Neuer Zyklus Typ - while, neuer Bedingungs-Typ - switch, Operatoren break und continue. Sie haben gelernt eigene Funktionen zu schreiben und mit mehrdimensionalen Arrays zu arbeiten, erfahren wie man Konstanten verwendet. All dies ist Ihr wichtigstes Instrument, eine Grundlage zum Schreiben anspruchsvollere Dinge zu schreiben, wie Benutzer-Indikatoren und Expert Advisors. Deshalb sollten Sie sicherstellen, dass Sie das Material des Artikels sorgfältig studiert haben, weil es sehr wichtig ist und in der Zukunft ständig verwendet wird.



Übersetzt aus dem Englischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/en/articles/1483

Beigefügte Dateien |
preprocessor.mq4 (0.86 KB)
Kursprognose mit Neuralen Netzen Kursprognose mit Neuralen Netzen

Viele Trader sprechen über Neurale Netze, aber was diese sind und was sie wirklich können, wissen nur wenige Menschen. Dieser Artikel wirft etwas Licht auf die Welt der künstlichen Intelligenz. Er beschreibt, wie die Daten für das Netzwerk richtig vorbereitet werden. Außerdem finden Sie hier ein Beispiel der Prognose mit Hilfe des Programms Matlab.

Was ist Martingale? Was ist Martingale?

Dieser Artikel enthält eine detaillierte Beschreibung des Martingale Systems, sowie präzise Berechnungen, die notwendig sind um die Frage zu beantworten: "Ist es vernünftig Martingale zu verwenden?".

Die MQL4-Programmiersprache für Neueinsteiger: Individuelle Indikatoren (Teil 1) Die MQL4-Programmiersprache für Neueinsteiger: Individuelle Indikatoren (Teil 1)

Dies ist der vierte Artikel aus der Reihe "Die MQL4-Programmiersprache für Neueinsteiger". Heute werden wir lernen, individuelle Indikatoren zu erstellen. Wir werden uns mit der Klassifizierung von Indikatorfunktionen vertraut machen und erfahren, wie diese Funktionen den Indikator beeinflussen. Wir werden neue Funktionen und Optimierungsmöglichkeiten kennenlernen und schließlich unsere eigenen Indikatoren programmieren. Darüber hinaus werden wir Ihnen zum Schluss des Artikels einige Tipps zum Programmierstil an die Hand geben. Falls dies der erste Artikel aus der Reihe „für Neueinsteiger“ sein sollte, welchen Sie lesen, dann wäre es möglicherweise besser für Sie, zunächst die vorhergehenden Artikel aus dieser Reihe zu lesen. Darüber hinaus sollten Sie zunächst sicherstellen, dass Sie die bereits behandelten Themen gut verstanden haben, weil dieser Artikel nämlich die Grundlagen der Programmierung nicht erneut behandelt.

Geheimnisse des Client Terminals MetaTrader 4: Indikatoren Geheimnisse des Client Terminals MetaTrader 4: Indikatoren

Möchten Sie Ihren eigenen Indikator erstellen? Vielleicht gibt es schon, was Sie brauchen, in eingebauten Indikatoren des Client Terminals, wo sie bereits realisiert wurden. Hat es doch einen Sinn, das Rad neu zu erfinden? Die Übersichtstabelle der Parameter (technische Daten) der eingebauten Indikatoren; Besonderheiten und Methoden des Indikatoren-Hinzufügen zum Chart; Die Konstruktion der Ebenen; Die Darstellung der Indikatoren in verschiedenen Timeframes (Zeitrahmen).