English Русский 中文 Español 日本語 Português
preview
Verstehen von Funktionen in MQL5 mit Anwendungen

Verstehen von Funktionen in MQL5 mit Anwendungen

MetaTrader 5Handel | 8 August 2023, 10:28
341 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Einführung

In der Welt der Programmierung gibt es einen sehr beliebten Begriff, den wir verwenden und hören eine Menge, wie pro seine Bedeutung in jeder Software, die die Funktion ist. In diesem Artikel werden wir uns ausführlich damit befassen, um zu lernen, wie man sehr funktionale und hochwertige Software erstellt. Wir werden versuchen, dieses wichtige Thema zu behandeln, um zu wissen, was Funktionen sind, warum wir Funktionen verwenden müssen und wie wir sie in unseren Anwendungen einsetzen können. Danach werden wir einige einfache Funktionen, die in jedem Handelssystem verwendet werden können, als Beispiele für die Anwendung dessen, was wir in diesem Artikel lernen, vorstellen. Die folgenden Punkte sind die wichtigsten Ideen, die wir in diesem Artikel zu diesem interessanten Thema behandeln werden:

Haftungsausschluss: Alle Informationen werden in der vorliegenden Form nur zu Informationszwecken bereitgestellt und sind nicht für Handelszwecke oder als Ratschläge gedacht. Die Informationen garantieren keinen Erfolg. Wenn Sie sich dafür entscheiden, diese Materialien auf einem Ihrer Handelskonten zu verwenden, tun Sie dies auf eigenes Risiko und Sie sind allein verantwortlich.


Definition der Funktion

In diesem Teil werden wir die Funktion in der Programmierung identifizieren, die Arten von ihnen, und warum wir sie verwenden müssen. Die Funktion ist ein mit einem aussagekräftigen Namen deklarierter Codeblock, der in jedem anderen Teil der Software durch wiederholten Aufruf verwendet werden kann, um eine bestimmte Aufgabe zu erfüllen. Wenn wir eine bestimmte Aufgabe haben, die die Software in vielen Teilen unserer Software oder in vielen Programmen ausführen muss, erstellen wir eine Funktion oder einen Codeblock, um diese Aufgabe auszuführen, und rufen ihn dann nur in diesen Teilen auf, ohne den gesamten Code noch einmal neu zu schreiben, sodass wir sagen können, dass die Funktion eine Methode ist, unseren Code zu abstrahieren, ohne eine Menge unordentlichen Code zu haben, wie wir in diesem Artikel sehen werden. Es gibt zwei Haupttypen dieser Funktionen: integrierte Funktionen und nutzerdefinierte Funktionen. Die integrierte Funktion ist die fertige Funktion von der Programmiersprache selbst, während die nutzerdefinierte Funktion die Funktion ist, die vom Nutzer nach seinen Bedürfnissen oder Aufgaben, die er braucht die Software zu erfüllen erstellt werden kann. In diesem Artikel werden wir uns auf nutzerdefinierte Funktionen konzentrieren. Wir werden uns also eingehend mit dieser Art von Funktion befassen, um zu sehen, warum wir diese Art von Funktion verwenden müssen und wie wichtig sie ist bzw. welche Eigenschaften sie hat.

Angenommen, die Software soll alle offenen Positionen schließen, wenn der Aktienkurs einen maximalen Drawdown erreicht hat, und wir müssen diese Aufgabe in vielen Teilen der Software ausführen. In diesem Fall wäre es besser, eine Funktion zu erstellen und den gesamten erforderlichen Code oder die Logik zur Ausführung dieser Aufgabe einzuschließen und diese Funktion dann in anderen Teilen aufzurufen. Aber es wäre nicht gut oder zu aufwändig, den gleichen Code in vielen Teilen zu schreiben und zu wiederholen, um die Aufgabe zu erfüllen.

Wenn Sie sich fragen, warum wir diese Art von Funktion verwenden müssen, wird die Antwort auf diese Frage dazu führen, dass wir die Merkmale der Verwendung von nutzerdefinierten Funktionen kennen lernen, und das Folgende ist dafür:

  • Es ist hilfreich, das DRY-Konzept (do not repeat yourself = keine Wiederholungen) anzuwenden: Die Verwendung von nutzerdefinierten Funktionen hilft uns, denselben Code nicht immer wieder zu wiederholen, sondern eine Funktion zu erstellen, die unsere Aufgabe einmal ausführen und dann an einer beliebigen Stelle in der Software aufrufen kann.
  • Wiederverwendbarkeit: Nachdem wir unsere Funktion erstellt haben, können wir sie jederzeit wieder verwenden.
  • Es ist hilfreich, das Konzept des „Teile und herrsche“ anzuwenden: Wenn wir Software erstellen, kann der Code komplex sein, um ein Problem zu lösen, aber wenn wir das große Problem in kleine Probleme unterteilen und jedes einzelne durch Funktionen lösen, kann dies sehr hilfreich sein, um unser Ziel bei der Lösung des großen Problems zu erreichen.
  • Dies trägt dazu bei, dass der Code besser lesbar und verständlich ist: Wenn wir Funktionen verwenden, hilft das, unsern Code lesbarer zu machen, da er durch die Funktionen übersichtlicher wird und jeder ein bestimmtes Problem behandelt und eine bestimmte Aufgabe hat.
  • Es ist hilfreich, das Konzept der Abstraktion anzuwenden: Die Verwendung von Funktionen bietet eine Methode zur Abstraktion unseres Codes, denn wenn wir sie nicht verwenden, müssen wir möglicherweise mehr Codezeilen schreiben als bei der Verwendung von Funktionen.
  • Es ist hilfreich, das Konzept der Kapselung anzuwenden: Wenn wir Funktionen verwenden, können wir unseren Code und unsere Daten besser sichern und verwalten, als wenn wir sie nicht verwenden würden.
  • Es verbessert den Debugging-Prozess: Wenn wir Funktionen verwenden, hilft das, Fehler besser zu erforschen und sie viel einfacher zu lösen.

Nach dem, was wir über die Merkmale der Verwendung von Funktionen erwähnt haben, können wir leicht herausfinden, wie viel vorteilhaft sein wird, wenn wir diese nutzerdefinierten Funktionen in unserer Software verwenden.


Struktur der Funktion

In diesem Teil werden wir mehr Details über Funktionen und die Struktur von Funktionen lernen und zwar in den folgenden zwei Schritten:

  • Funktionsdeklaration oder -definition
  • Funktionsaufruf

Als Erstes müssen wir eine neue Funktion definieren oder deklarieren, also müssen wir etwas Ähnliches wie die folgende Struktur tun:

returnedDataType functionName(param1, param2)
{
        bodyOfFunction
}
  • „returnedDataType“ ist der Datentyp, den die Funktion nach der Ausführung zurückgeben soll.
  • „functionName“ ist der Name der Funktion und wir benennen sie entsprechend der Aufgabe, die die Funktion ausführt.
  • „param1“, „param2“ sind Variablen oder Platzhalter, die übergeben werden, die wir benötigen.
  • „bodyOfFunction“ beinhaltet den gesamten Code, der unsere Aufgabe erfüllen soll. 

Wenden wir das auf ein einfaches Beispiel an, wenn wir eine einfache Funktion erstellen müssen, um eine Addition zweier Werte durchzuführen, können wir das durch den folgenden Codeblock tun:

//addition function
// returned data type is an integer - the name of the function is add - parameters or arguments are two int variables val1 and val2
int add(int val1, int val2)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of val1 and val2 addition
   int result = val1+val2;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

Nachdem wir unsere Funktion definiert haben, müssen wir den zweiten Schritt tun, nämlich die Funktion aufrufen. Das können wir tun, indem wir den Namen der Funktion aufrufen und die gewünschten Parameter gemäß unserer Funktion im gewünschten Teil des Softwarecodes angeben. Zurück zu unserem Beispiel: Wenn wir unsere Funktion aufrufen wollen, sieht das wie folgt aus:

   //calling our defined function by its name and specifying arguments
   add(5,15);

Wenn wir die Funktion aufrufen, können wir das Ergebnis des Wertes 20 in der Registerkarte „Experten“ gemäß unserer Funktion und den angegebenen Argumenten erhalten, wie in der folgenden Abbildung dargestellt.

Funktionsergebnis

Das obige Beispiel ist nur ein Beispiel dafür, was wir mit Hilfe von Funktionen tun können, aber es gibt viele verfügbare Eigenschaften, die wir bei Funktionen verwenden können, und die folgenden sind einige davon.

Funktion mit Argumenten

Im letzten Beispiel der Additionsfunktion haben wir zwei ganzzahlige Variablen verwendet, nämlich val1 und val2, die in unserer Funktion als Argumente gelten. Bei diesen Argumenten kann es sich um Datentypen wie Integer, String, ..etc. handeln. In unserem letzten Beispiel handelte es sich um Integer-Variablen, wie wir sie gesehen haben, und wir können ein weiteres Beispiel für String-Argumente sehen, wie das folgende:

//sayHello function
// returned data type is string - name of function is sayHello - parameters or arguments are two string variables greeting and name
string sayHello(string greeting, string name)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string result = greeting+name;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

Wir können diese Funktion wie oben beschrieben aufrufen und das Ergebnis nach der Ausführung wie folgt ermitteln:

sayHello Funktionsergebnis

Sie können auch eine Mischung dieser Datentypen sein, je nachdem, was wir in unserer Funktion als Parameter oder Argumente benötigen, um den Hauptteil der Funktion von ihnen auszuführen. Diese Argumente können auch die Anzahl sein, die wir je nach unseren Bedürfnissen benötigen.

Funktion ohne Argumente

Die Funktion kann deklariert oder definiert werden, ohne dass Parameter oder Argumente angegeben werden. Geben Sie einfach einen aussagekräftigen Namen für die Funktion an und lassen Sie die Argumente leer, füllen Sie dann den Hauptteil der Funktion aus, um die Aufgabe zu erfüllen, und rufen Sie die Funktion auf, ohne Argumente anzugeben:

//sayHello function
// returned data type is a string - the name of the function is sayHello - no parameters
string sayHello()
  {
   //body of the function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string greeting= "Hello, ";
   string name= "World!";
   string result = greeting+name;
   //Print the result in the experts' tab
   Print(result);
   //returning value
   return result;
  }

Wenn wir die Funktion aufrufen, sieht das wie folgt aus:

sayHello();

Das Ergebnis wird dasselbe sein wie bei der Funktion mit Argumenten, da der Hauptteil der Funktion derselbe ist.

Funktion mit Standardwerten

Wir definieren auch eine Funktion und geben Anfangs- oder Standardwerte für die Parameter an, können sie aber immer noch ändern oder mit den gewünschten Werten aktualisieren, und das kann bei Anwendung desselben Beispiels wie folgt aussehen

//defining function with default values
string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

Dann können wir die Funktion zweimal aufrufen, um den Unterschied zwischen den Standardwerten zu ermitteln und wenn wir sie aktualisieren, aber ich muss hier auch erwähnen, dass wir hier Parameter angeben können, wenn wir sie aktualisieren wollen, aber wenn wir sie nicht angeben, gibt die Funktion Standardwerte zurück, wie im Folgenden:

   sayHello();
   sayHello("Hi, ", "Developer!");

Das Ergebnis ist dasselbe wie das folgende:

Funktionsergebnis von sayHello mit Werten

Übergabe von Parametern

Wir können der Funktion Werte übergeben und diese Werte können beliebige Datentypen sein, wie z.B. int, string, array,... etc. Durch die Übergabe von Parametern nach Werten bleiben die ursprünglichen Variablen in der Funktion gleich oder unverändert, da wir den Wert der Parameter an die Funktion übergeben haben. Wir können auch Parameter per Verweis an die Funktion übergeben, wenn wir die ursprünglichen Variablen aktualisieren müssen.

Es folgt ein einfaches Beispiel, um zu verstehen, was wir über die Übergabe per Verweis gesagt haben.

//passing by reference
void updateNums(int &val1, int &val2)
  {
   val1*=2;
   val2/=2;
  }

Dann werden wir neue Variablen erstellen, ihre Werte ausgeben und dann unsere Funktion mit diesen neuen Variablen als Parameter aufrufen und ihre Werte nach dem Aufruf ausgeben, um die Differenz freizugeben:

//new variables
   int firstNum = 10;
   int secondNum = 20;
   
//before calling function
   Print("before calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 
   
// calling   
   updateNums(firstNum, secondNum);

// after calling  
   Print("after calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 

Das Ergebnis von zwei Ausdrucken wird also sein, dass der erste die Werte der neuen Variablen 10 und 20 sein wird, und nach dem Aufruf werden wir die Werte nach der Aktualisierung durch 20 und 10 im Hauptteil der Funktion finden. Das Ergebnis ist dasselbe:

Übergabe durch Referenz

Rückgabe-Operator

Wenn wir eine Funktion haben, die einen Wert zurückgibt, muss sie einen Rückgabeoperator haben. Je nach Aufgabe der Funktion können wir mehr als einen Rückgabeoperator in der Funktion haben, aber wenn die Funktion einen Wert zurückgibt, muss sie mindestens eine Rückgabe in der letzten Zeile der Funktion haben. Dieser Rückgabeoperator kann ein beliebiger Typ sein, darf aber kein Array sein, aber wir können ein Element aus dem Array zurückgeben. Wenn wir wollen, dass die Funktion ein Array zurückgibt, können wir das Array per Referenz an die Funktion übergeben, so wie wir es bereits erwähnt haben.

Nachfolgend ein Beispiel aus dem zuvor erwähnten Beispiel, das einen Rückgabeoperator enthält

string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

Funktion vom Typ Void

Wenn wir eine Funktion haben, die keinen Wert zurückgibt, verwenden wir die Funktion vom Typ void, da dieser Typ keinen Wert zurückgibt. Wir können dieser Art von Funktion normalerweise Parameter übergeben, aber sie braucht keinen Rückgabeoperator. Im Folgenden finden Sie ein Beispiel für diese Art von Funktionen.

void add(int val1, int val2)
  {
   int result= val1+val2;
  }

Überladen von Funktionen

Es gibt Fälle, in denen bei der Definition von Funktionen mehrere Funktionen unter demselben Namen definiert werden müssen, um die gleiche Aufgabe mit unterschiedlichen Parametern zu erfüllen. Wenn wir z. B. eine Additionsaufgabe haben, aber diese Addition für zwei Werte durchführen müssen, und wir dieselbe Aufgabe für drei Werte durchführen müssen, erstellen wir in diesem Fall zwei Funktionen unter demselben Namen der Funktion, aber wir ändern die Parameter entsprechend der Aufgabe. Das bedeutet, dass wir eine Funktion überladen. Das bedeutet, dass dieselbe Aufgabe ausgeführt wird, aber mit anderen Parametern.

Bei diesen verschiedenen Parametern kann es sich um unterschiedliche Datentypen von Parametern, um Zahlen desselben Datentyps oder um beides handeln. Es folgt das Beispiel einer überladenen Funktion mit demselben Datentyp, aber einer anderen Anzahl von Parametern:

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(int val1, int val2, int val3)
{
   int result=val1+val2+val3;
}

Wie wir sehen können, haben wir die gleiche Funktion, aber die Parameter sind unterschiedlich. Wenn wir die Funktion aufrufen, finden wir, dass diese zwei Funktionen erscheinen, wenn wir den Namen der Funktion eingeben, dann können wir wählen, was wir gemäß unserer Aufgabenbeschreibung benötigen. Es folgt das Beispiel einer überladenen Funktion mit verschiedenen Parametern mit unterschiedlichen Datentypen:

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(string message, int val1, int val2)
{
   int result=message+val1+val2;
}

Wir können auch die Funktion auswählen, die wir als Parameter beim Aufruf der Funktion benötigen.


Funktion Anwendungen

In diesem Teil werden wir einfache Anwendungen erstellen, für die wir die Funktion verwenden können, um von der nutzerdefinierten Funktion zu profitieren und den Kodierungsprozess zu vereinfachen. Nachdem wir diese Anwendungen erstellt haben, können wir sie in verschiedenen Teilen der Software oder sogar in einer anderen Software aufrufen, indem wir sie einbinden.

Nachrichten Alarm App

Wir alle wissen, dass der Handel während der Wirtschaftsnachrichten sehr riskant ist, und es gibt viele professionelle Ratschläge, dass wir während der Nachrichten nicht handeln sollten. Wenn Sie nicht wissen, was ein Wirtschaftskalender ist: Es ist ein vorgefertigter Kalender, der makroökonomische Nachrichten und Indikatoren mit Beschreibungen, deren Datum, Uhrzeit und Grad der Wichtigkeit sowie freigegebene Werte dieser wirtschaftlichen Ereignisse enthält, und es gibt viele Quellen, die verwendet werden können, um diese wichtigen Werte zu erhalten, um mit dem, was den Markt beeinflussen kann, aktualisiert zu werden und entsprechend zu handeln. Wir haben diesen Kalender auch im MetaTrader 5-Handelsterminal, da Sie seine Registerkarte im Toolbox-Fenster finden können, und Sie können steuern, was Sie in Bezug auf Bedeutung, Währungen und Länder sehen müssen. Es gibt auch integrierte Funktionen für die Arbeit mit dem Wirtschaftskalender und Sie können sie alle in der MQL5-Dokumentation über den folgenden Link überprüfen:

Wirtschaftskalender-Funktionen

Wir müssen also den Wirtschaftskalender manuell prüfen, um den Handel während der Nachrichten zu vermeiden, oder wir erstellen eine App, die uns warnt, wenn wir uns den Nachrichten nähern, um den Handel zu stoppen. Diese Aufgabe ist eine ständige Aufgabe, sodass wir sie in jedem Handelssystem oder in vielen Teilen der Software benötigen. Wir können also eine Funktion dafür erstellen und sie dann einfach aufrufen, und das werden wir in diesem Teil durch die folgenden Schritte tun:

Diese Anwendung wird ein EA sein, im globalen Bereich werden wir einen bool-Typ für den Namen unserer Funktion „isNewsComing“ (es gibt Nachrichten) lautet, und da werden wir keine Parameter hinzufügen, die Klammer bleibt leer:

bool isNewsComing()

Der Hauptteil der Funktion erstellt ein Array mit dem Namen „values“ und dem Typ „MqlCalendarValue“, das die Werte der Pressemitteilung enthält, wie zum Beispiel den aktuellen Wert

MqlCalendarValue values[];

Wir müssen den aktuellen Tag definieren, indem wir die Startzeit des Tages mit „iTime“ definieren, um die Öffnungszeit des Balkens zurückzugeben, nachdem wir eine neue Zeit-Variable vom Typ datetime mit dem Namen „startTime“ deklariert haben, und die Endzeit des Tages, die gleich der definierten Startzeit sein soll, und die Anzahl der Sekunden des Tages, indem wir die Funktion „PeriodSeconds“ verwenden, nachdem wir eine neue Zeit-Variable mit dem Namen „endTime“ deklariert haben:

   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);

Abrufen des Arrays der Werte aller Ereignisse des Tages, indem die Startzeit und die Endzeit zur Bestimmung des Zeitbereichs und zur Sortierung nach dem aktuellen Land und der Währung mit der Funktion CalendarValueHistory verwendet werden:

CalendarValueHistory(values,startTime,endTime,NULL,NULL);

Wir werden eine Schleife erstellen und diese Schleife wird mit einem Wert von 0 für die erstellte int-Variable „i“ beginnen und die Schleife fortsetzen, wenn „i“ kleiner als die Array-Größe des Werte-Arrays ist und „i“ um einen Wert inkrementieren:

for(int i=0; i<ArraySize(values); i++)

Im Hauptteil der for-Schleife wird eine Ereignisvariable vom Typ „MqlCalendarEvent“ für die Ereignisbeschreibungen erstellt, die in der Funktion „CalendarEventById“ verwendet werden kann:

MqlCalendarEvent event;

Zum Abrufen der Ereignisbeschreibung anhand der ID mit Hilfe der Funktion „CalendarEventById“, deren Parameter event_id und das Ereignis verwenden wir:

CalendarEventById(values[i].event_id,event);

Wir erstellen eine Ländervariable vom Typ „MqlCalendarCountry“ für die Länderbeschreibungen, die mit dem Befehl „CalendarCountryById“ verwendet werden kann:

MqlCalendarCountry country;

Zum Abrufen der Länderbeschreibungen anhand ihrer ID mit der Funktion „MqlCalendarCountry“, deren Parameter country_id und das Land verwenden wir:

CalendarCountryById(event.country_id,country);

Zum Einstellen von Bedingungen, um Ereignisse nach dem aktuellen Symbol oder Währungsnachrichten, der Wichtigkeit von Nachrichten ist mittel oder hoch zu filtern, und wenn es etwas anderes gibt, das weitergeht:

      if(StringFind(_Symbol,country.currency)<0)
         continue;

      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;

Zum Einstellen der Bedingung für die Zeitspanne der Warnung, die wir brauchen, verwenden wir 30 Sekunden vor der Zeit der Nachrichten:

      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))

Dann müssen wir auf der Registerkarte „Experten“ eine Meldung mit dem Namen des Ereignisses und dem Text „... is coming! Stop Trading...“

Print(event.name, " is coming! Stop Trading...");

Der zurückgegebene Wert ist true:

return true;

Wenn die Bedingungen falsch sind, beenden Sie die Schleife und geben false zurück, um die Funktion zu beenden:

return false;

Dann können wir die Funktion in der OnTick-Funktion aufrufen, und wenn sie true zurückgibt, brauchen wir eine gedruckte Nachricht von „News is coming...!“:

   if(isNewsComing())
     {
      Print("News is comming...!");
     }

Jetzt haben wir die Funktion erstellt und aufgerufen, und wir können sie in jedem Teil unserer Software nach unseren Bedürfnissen verwenden. Im Folgenden finden Sie den vollständigen Code in einem Block, um ihn leicht wieder lesen zu können, und Sie werden die Quellcode-Dateien aller Anwendungen im Anhang des Artikels finden:

//+------------------------------------------------------------------+
//| News Alert Function                                              |
//+------------------------------------------------------------------+ 
void OnTick()
  {
   if(isNewsComing())
     {
      Print("News is comming...!");
     }
  }
//+------------------------------------------------------------------+
bool isNewsComing()
  {
   MqlCalendarValue values[];
   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);
   CalendarValueHistory(values,startTime,endTime,NULL,NULL);
   for(int i=0; i<ArraySize(values); i++)
     {
      MqlCalendarEvent event;
      CalendarEventById(values[i].event_id,event);
      MqlCalendarCountry country;
      CalendarCountryById(event.country_id,country);
      if(StringFind(_Symbol,country.currency)<0)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;
      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))
        {
         Print(event.name, " is coming! Stop Trading...");
         return true;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+

App zu Berechnung der Losgröße

Wir müssen eine App erstellen, die in der Lage ist, die optimale Losgröße zu berechnen, nachdem wir den Risikoprozentsatz und den maximalen Verlust in Pips bestimmt haben, und wir müssen eine überladene Funktion erstellen, um die optimale Losgröße zu berechnen, nachdem wir den Risikoprozentsatz, den Einstiegspreis und den Stop-Loss-Preis bestimmt haben. Wir werden diese Anwendung als Skript erstellen, wie in den folgenden Schritten beschrieben:

Wir erstellen eine Funktion mit dem Namen OptimalLotSize vom Type double und mit zwei Parametern für die erste Funktion, die Double-Variable des maximalen Risikoprozentsatzes und die Double-Variable des maximalen Verlustes in Pips, wie folgt:

double OptimalLotSize(double maxRiskPrc, double maxLossInPips)

Dann legen wir fest, was wir mit diesen Parametern machen wollen. Zuerst holen wir und den Kapitalwert des Kontos, indem wir die Funktion „AccountInfoDouble“ verwenden, die das aktuelle Kapital des entsprechenden Kontos zurückgibt, hier der Bezeichner „ENUM_ACCOUNT_INFO_DOUBLE“ ist, und erstellen eine Meldung mit dem Wert:

   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);

Wir rufen die Kontraktgröße des Symbols mit der Funktion „SymbolInfoDouble“, die die entsprechende Eigenschaft eines angegebenen Symbols mit der Variante des Symbolnamens „_Symbol“ zurückgibt, um das aktuelle Symbol und prop_id „SYMBOL_TRADE_CONTRACT_SIZE“ als einen der Werte von „ENUM_SYMBOL_INFO_DOUBLE“ zurückzugeben, woraufhin wir eine Hinweis mit diesem zurückgegebenen Wert benötigen:

   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);

Berechnen des Pip-Wertes und Abrufen einer Warnung mit diesem Wert:

   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);

Berechnung des Maximalwerts des Verlusts aus dem definierten Kontokapital und Erhalt einer Warnung mit diesem Wert:

   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);

Berechnung des Höchstwerts in der Kurswährung auf der Grundlage des berechneten maximalen Verlustwerts und Rückgabe einer Meldung mit diesem Wert:

   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);

Berechnung der optimalen Losgröße und Rückgabe einer Meldung mit dem Wert:

   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);

Der Rückgabeoperator gibt OptimalLotSize als Wert vom Typ double zurück:

return OptimalLotSize;

Danach erstellen wir die Überladungsfunktion, indem wir drei Parameter vom Typ Double für den maximalen Risikoprozentsatz, den Einstiegskurs und den Stop-Loss-Kurs übergeben:

double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)

Definition des maximalen Verlustes in Pips als absoluter Wert, der auf den Eingabeparametern Einstiegskurs und Stop-Loss-Kurs basiert und dann durch 0,0001 geteilt wird:

double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;

Der Rückgabeoperator ist die erstellte Funktion OptimalLotSize mit den Parametern maximales Risiko in Prozent und maximaler Verlust in Pips:

return OptimalLotSize(maxRiskPrc,maxLossInPips);

Dann können wir eine der beiden Funktionen im Teil OnStart() aufrufen, je nachdem, was wir brauchen, z. B. die folgende:

OptimalLotSize(0.01, 1.12303, 1.11920);

Nachfolgend finden Sie den vollständigen Code, um diese Art von Funktion für diese Art von Anwendung zu erstellen:

//+------------------------------------------------------------------+
//| lotSize Calc Function                                            |
//+------------------------------------------------------------------+
void OnStart()
  {
   OptimalLotSize(0.01, 1.12303, 1.11920);
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double maxLossInPips)
  {
   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);
   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);
   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);
   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);
   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);
   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);
   return OptimalLotSize;
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)
  {
   double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;
   return OptimalLotSize(maxRiskPrc,maxLossInPips);
  }
//+------------------------------------------------------------------+

Wenn wir dieses Skript ausführen, erhalten wir die folgende Meldung:

App lotSize

Wie in der zuvor erwähnten Anwendung haben wir die lotSize Calc-Funktion, die wir in verschiedenen Softwareteilen verwenden und aufrufen können, um die Aufgabe einfach auszuführen, ohne den Code erneut zu schreiben.

Alle App schließen

Wir müssen hier ein Skript erstellen, mit dem geöffnete und ausstehende Aufträge geschlossen werden können, indem wir eine Funktion erstellen, die in jedem geeigneten Teil der Software verwendet oder aufgerufen werden kann, um diese Aufgabe zu erfüllen. Wir können dies durch die folgenden Schritte erreichen:

Einbindung der Klasse Trade in den Code durch Verwendung von preprocess oder #include, um alle Handelsfunktionen in die Datei „Trade.mqh“ einzubinden:

#include <Trade/Trade.mqh>

Erstellen eines Objekts mit dem Typ der in der Software zu verwendenden Klasse CTrade:

CTrade trade;

Auch im globalen Bereich müssen wir eine Funktion void closeAll ohne Argumente erstellen:

void closeAll()

Der Hauptteil der Funktion erstellt eine for-Schleife, um nach offenen Aufträgen zu suchen:

for(int i=PositionsTotal()-1; i>=0; i--)

 Der Hauptteil der Schleife, in dem die Variable ulong posTicket erstellt und ihr das Ticket der geöffneten Bestellungen zugewiesen wird:

ulong posTicket=PositionGetTicket(i);

Schließen einer offenen Position mit der Funktion trade.PositionClose(posTicket):

trade.PositionClose(posTicket);

Wir löschen schwebende Aufträge, indem wir eine weitere for-Schleife erstellen, um solche Aufträge zu erkennen, ihre Tickets der ulong-Variablen von posTicket zuzuweisen und den schwebenden Auftrag anhand seines erkannten Tickets zu löschen:

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }

Danach können wir diese Funktion in OnStart() aufrufen:

closeAll();

Wenn Sie dieses Skript ausführen, werden alle Aufträge geschlossen und gelöscht. Im Folgenden finden Sie den vollständigen Code zur Erstellung dieser closeAllApp in einem Block:

//+------------------------------------------------------------------+
//| closeAll Function                                                |
//+------------------------------------------------------------------+ 
#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
void OnStart()
  {
   closeAll();
  }
//+------------------------------------------------------------------+
void closeAll()
  {
//close all open positions
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong posTicket=PositionGetTicket(i);
      trade.PositionClose(posTicket);
     }
//delete all pending orders
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }
  }
//+------------------------------------------------------------------+

Diese Anwendungen sind nur Beispiele dafür, was wir als nutzerdefinierte Funktionen erstellen können, und Sie können sie entwickeln oder andere Anwendungen oder Funktionen nach Ihren Bedürfnissen erstellen, wie z. B. Trailing-Stop- und Trade-Management-Anwendungen und Drawdown-Sicherheitstools usw.


Schlussfolgerung

Nach dem, was wir in diesem Artikel erwähnt, sollten Sie in der Lage sein, festzustellen, dass es von entscheidender Bedeutung ist, um Funktionen in Ihrer Software wegen aller Funktionen und Nutzen, die Sie erhalten, wenn Sie das tun, wie es angenommen wird, dass Sie identifiziert Funktionen der Verwendung von ihnen wie:

  • Es hilft bei der Anwendung des DRY-Konzepts (Do not repeat yourself, keine Wiederholungen) in der Programmierung.
  • Es hilft, ein großes Problem zu minimieren, indem man es in kleine Probleme aufteilt und sich mit ihnen befasst.
  • Verbesserung der Lesbarkeit des Codes.
  • Wiederverwendbarkeit.
  • Abstrahieren des Codes.
  • Verkapselung des Codes.
  • Verbesserte Fehlersuche.

Es wird auch vorausgesetzt, dass Sie gut verstanden haben, was die Funktion ist, ihre Typen, die integrierte und die nutzerdefinierte Funktion, und wie Sie Funktionen erstellen oder definieren können, indem Sie die Struktur von Funktionen und alle Eigenschaften von ihnen lernen, wie z. B. Funktionen mit Argumenten und wie wir diese Argumente oder Parameter übergeben können, ohne Argumente und Funktionen mit Standardwerten. Es wird davon ausgegangen, dass Sie Ihre Funktion unter Verwendung eines beliebigen Datentyps definieren und mit dem darauf basierenden Rückgabeoperator umgehen können, und Sie wissen, wie Sie viele Überladefunktionen mit demselben Namen, aber unterschiedlichen Argumenten erstellen können, um dieselbe Aufgabe zu erfüllen.

Nach der gemeinsamen Nutzung von Anwendungen zur Erstellung von Funktionen als Beispiele, glaube ich, dass dies sehr geholfen hat, Ihr Verständnis für das Thema zu vertiefen, da wir zwei verschiedene Funktionen erstellen:

  • Nachrichten App (newsAlertApp): Sie kann in jedem Teil der Software verwendet oder aufgerufen werden, um Benachrichtigungen zu erhalten, wenn wichtige Nachrichten anstehen. Den Quellcode der newsAlertApp finden Sie im Anhang.
  • App zu Berechnung der Losgröße (lotSizeCalcApp): Sie kann in jedem Teil der Software verwendet oder aufgerufen werden, um die optimale Lotgröße für die Eröffnung eines Handels auf der Grundlage des definierten Risikoprozentsatzes, Einstiegskurses und Stop-Loss-Kurses zu ermitteln. Oder, basierend auf dem definierten Risikoprozentsatz und dem maximalen Verlust in Pips, was bedeutet, dass wir eine Überladungsfunktion in dieser Anwendung erstellt haben. Sie finden den Quellcode von lotSizeCalcApp im Anhang.
  • closeAllApp: Sie wird verwendet oder aufgerufen, um alle offenen und schwebenden Aufträge zu schließen. Sie finden den Quellcode von closeAllApp im Anhang.

Die Welt der Funktionen ist sehr interessant, und es ist sehr wichtig, sich mit ihr zu beschäftigen, um nützliche Codestücke einfach, reibungslos und effektiv erstellen zu können. Ich hoffe, dass dieser Artikel für Sie nützlich war, um Ihre Programmierfähigkeiten zu entwickeln und Ihre Handelskarriere zu verbessern, indem Sie nützliche Tools erstellen, die Ihnen helfen können, gut zu handeln. Wenn Sie weitere Artikel über die Programmierung oder über die Erstellung von Handelssystemen auf der Grundlage der beliebtesten technischen Indikatoren wie gleitender Durchschnitt, RSI, MACD, Stochastik, Bollinger Bands, Parabolic Sar...usw. lesen möchten. Sie können in meinen Veröffentlichungen Artikel darüber finden, und ich hoffe, dass Sie diese auch nützlich finden.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/12970

Beigefügte Dateien |
newsAlertApp.mq5 (1.37 KB)
lotSizeCalcApp.mq5 (1.45 KB)
closeAllApp.mq5 (0.86 KB)
Kategorientheorie in MQL5 (Teil 11): Graphen Kategorientheorie in MQL5 (Teil 11): Graphen
Dieser Artikel ist die Fortsetzung einer Serie, die sich mit der Implementierung der Kategorientheorie in MQL5 beschäftigt. Hier untersuchen wir, wie die Graphentheorie mit Monoiden und anderen Datenstrukturen bei der Entwicklung einer Ausstiegsstrategie für ein Handelssystem integriert werden kann.
Kann Heiken-Ashi in Kombination mit gleitenden Durchschnitten gute Signale liefern? Kann Heiken-Ashi in Kombination mit gleitenden Durchschnitten gute Signale liefern?
Kombinationen von Strategien können bessere Chancen bieten. Wir können Indikatoren oder Muster miteinander kombinieren, oder noch besser, Indikatoren mit Mustern, sodass wir einen zusätzlichen Bestätigungsfaktor erhalten. Gleitende Durchschnitte helfen uns, den Trend zu bestätigen und zu verfolgen. Sie sind die bekanntesten technischen Indikatoren, und das liegt an ihrer Einfachheit und ihrer erwiesenen Fähigkeit, einen Mehrwert für Analysen zu schaffen.
Kategorientheorie in MQL5 (Teil 12): Ordnungsrelationen Kategorientheorie in MQL5 (Teil 12): Ordnungsrelationen
Dieser Artikel, der Teil einer Serie ist, die der kategorientheoretischen Implementierung von Graphen in MQL5 folgt, befasst sich mit Ordnungen. Wir untersuchen, wie Konzepte der Ordnungstheorie monoide Mengen bei der Information über Handelsentscheidungen unterstützen können, indem wir zwei wichtige Ordnungstypen betrachten.
Die Wiederaufnahme einer alten Trendhandelsstrategie: Zwei Stochastik-Oszillatoren, ein MA und Fibonacci Die Wiederaufnahme einer alten Trendhandelsstrategie: Zwei Stochastik-Oszillatoren, ein MA und Fibonacci
Eine alte Handelsstrategie. In diesem Artikel wird eine der Strategien vorgestellt, mit denen sich der Trend auf rein technische Weise verfolgen lässt. Die Strategie ist rein technisch und verwendet einige technische Indikatoren und Werkzeuge, um Signale und Ziele zu liefern. Die Komponenten der Strategie sind wie folgt: Ein stochastischer Oszillator mit 14 Perioden. Ein 5-Perioden-Stochastik-Oszillator. Ein gleitender 200-Perioden-Durchschnitt. Ein Werkzeug zur Fibonacci-Projektion (für die Festlegung von Zielen).