English 日本語
preview
Handelsstrategie kaskadierender Aufträge basierend auf EMA Crossovers für MetaTrader 5

Handelsstrategie kaskadierender Aufträge basierend auf EMA Crossovers für MetaTrader 5

MetaTrader 5Handel | 4 September 2024, 10:39
17 0
Kikkih25
Kikkih25

Einführung 

In diesem Artikel demonstrieren wir die Handelsstrategie kaskadierender Aufträge des Forex Trading Expert Advisor (EA) in MetaQuotes Language 5 (MQL5) für MetaTrader 5. In diesem Artikel über einen MQL5 Expert Advisor mit dem Kreuzen von gleitenden Durchschnitten als Grundlage für die Handelsstrategie werden die Handelsentscheidungen auf dem MetaTrader 5-Plattform automatisiert. Dieser Artikel enthält wesentliche Funktionen für die Positionsinitialisierung, -anpassung und -überwachung und nutzt die Bibliothek Trade.mqh für eine effektive Auftragsverwaltung.

Zunächst werden zwei exponentiell gleitende Durchschnitte (EMA) mit vorgegebenen Periodenlänge als Teil der Technik verwendet. Je nach Richtung des Kreuzes wird ein Kauf- oder Verkaufssignal erzeugt, wenn sich diese gleitenden Durchschnitte kreuzen. Die Aufträge werden mit einem bestimmten Take-Profit und Stop-Loss versehen, die dynamisch angepasst werden, wenn sich der Markt weiterentwickelt.

Darüber hinaus verfügt das Skript über eine Routine zur Erkennung neuer Balken, die unerlässlich sind, um sicherzustellen, dass Handelsentscheidungen auf der Grundlage abgeschlossener Kerzenformationen getroffen werden. Darüber hinaus wird eine Funktion zur Anpassung des aktuellen Bestands bei Erreichen von Gewinnzielen angeboten.

Diese Expertenempfehlung zeigt in ihrer Gesamtheit, wie MQL5 zur Umsetzung einer systematischen Handelsstrategie genutzt werden kann, indem die automatische Ausführung und technische Indikatoren zur Durchführung von Geschäften nach vorher festgelegten Regeln verwendet werden.

In diesem Artikel werden die folgenden Themen behandelt:

  1. Erläuterung der Handelsstrategie kaskadierender Aufträge
  2. Implementierung von EA in MQL5
  3. Schlussfolgerung


Erläuterung der Handelsstrategie kaskadierender Aufträge 

Die Handelsstrategie kaskadierender Aufträge beschreibt eine Technik, bei der die Ergebnisse oder Bedingungen früherer Aufträge verwendet werden, um die Platzierung eines späteren Auftrags zu bestimmen. Diese Strategie wird häufig im Handel eingesetzt, um Ein- und Ausstiege sowie Positionsgrößen auf der Grundlage von Marktbewegungen und vorher festgelegten Regeln zu verwalten und zu optimieren. Hier finden Sie eine detaillierte Beschreibung, wie eine Handelsstrategie mit kaskadierender Aufträge funktionieren könnte.

Wesentliche Bestandteile der Handelsstrategie kaskadierender Aufträge:

  1. Konsekutive Auftragserteilung: - Eine Handelsstrategie kaskadierender Aufträge beinhaltet die konsekutive Einleitung von Transaktionen als Reaktion auf die vorher festgelegten Ereignisse oder Bedingungen. Ein erster Auftrag könnte von einem Händler erteilt werden, zum Beispiel als Reaktion auf ein bestimmtes Signal eines technischen Indikators.
  2. Bedingter Auftrag: - Zukünftige Aufträge werden in Abhängigkeit von den Ergebnissen früherer Transaktionen oder der Marktlage erteilt. Wenn sich der Markt zu Ihren Gunsten entwickelt, kann dies dazu führen, dass Sie mehr Aufträge erteilen, um eine Position zu vergrößern.
  3. Ein- und Ausstieg: - Um das Risiko zu kontrollieren und das Gewinnpotenzial zu optimieren, besteht die Kaskadenstrategie häufig darin, schrittweise in eine Position einzusteigen. Auf der anderen Seite wird die Positionsgröße reduziert, wenn die Gewinnziele erreicht werden oder wenn sich der Markt negativ entwickelt.
  4. Risikomanagement: - Um Verluste zu minimieren, ist ein wirksames Risikomanagement bei Kaskadentechniken unerlässlich. Dies bedeutet, dass für jeden Auftrag Stop-Loss-Schwellenwerte festgelegt werden oder dass diese dynamisch geändert werden, wenn sich die Position ändert.

Gewinnmitnahmen: Wenn bestimmte Voraussetzungen erfüllt sind, werden Maßnahmen ergriffen, um die Gewinne zu sichern. Für jeden Auftrag werden in allen Phasen der Transaktion Gewinnziele festgelegt. Dies garantiert den Händlern einen Gewinn und ermöglicht gleichzeitig ein zusätzliches Plus, wenn die Marktbedingungen dies erfordern.

Das folgende Diagramm fasst die Handelsstrategie der Kaskadenaufträge zusammen:

Handelsstrategie kaskadierender Aufträge


Implementierung des EA in MQL5

Erstens ist die Bibliothek Trade.mqh von MQL5 eine starke und praktische Bibliothek, die die Handelsaktivitäten erleichtert. Es bietet eine übersichtliche Oberfläche zum Öffnen, Ändern und Löschen von Positionen und Aufträgen. Wenn wir Trade.mqh einbinden, erhalten wir Zugriff auf die Klasse CTrade, die viele der komplizierten Details der Handelsaktivitäten vereinfacht und kapselt und so die Lese- und Wartungsfähigkeit unseres Codes verbessert.

#include <Trade/Trade.mqh>
CTrade obj_Trade;

Nach dem Einfügen der Datei Trade.mqh können wir auf die Klasse CTrade zugreifen, die als obj_Trade instanziiert ist. Wir haben festgestellt, dass die vielen Funktionen, die wir für den Handel haben, in der Klasse CTrade gekapselt sind. Im Folgenden finden Sie einige der wichtigsten Techniken, die die CTrade-Klasse bietet:

  1.  Auftragserteilung
  2.  Änderung des Auftrags
  3.  Beendigung des Auftrags

Als Nächstes gehen wir zu den globalen Variablen über, die für die Funktionsweise der Handelsstrategie sehr wichtig sind und im Expert Advisor (EA) eine Vielzahl von Funktionen erfüllen. Lassen Sie uns über jede globale Variable sprechen und was sie bedeutet:

  •  Ganzzahlige Variablen

int handleMAFast;
int handleMASlow;

Die Handles oder IDs für die von der OnInit-Funktion berechneten Slow- und Fast-Moving Average Indicators werden in diesen Variablen gespeichert; um die aktuellen Werte dieser Indikatoren abzurufen, müssen die Handler auf ihre Puffer zugreifen.

  • Double-Arrays für gleitende Durchschnitte

double maSlow[],maFast[];

Die Werte der aus den Indikatorpuffern abgeleiteten schnellen und langsamen Durchschnittswerte werden in diesen Feldern gespeichert. Für Analysen und Handelsentscheidungen werden sie genutzt, um die aktuellen und vergangenen Werte der Indikatoren zu speichern.

  • Die double-Variablen für Take-Profit und Stop-Loss

double takeProfit = 0;
double stopLoss = 0;

Die Take-Profit (TP) und Stop-Loss (SL) für die Handelsoperationen werden derzeit in dieser Variablen gespeichert. Sie werden verwendet, um Handelsaufträge zu erteilen oder zu ändern, und sie werden entsprechend den Marktbedingungen aktualisiert.

  •  Boolsche Variablen des Systemzustandes

bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

Diese Flags überwachen den Ausgangszustand der Kauf- und Verkaufshandelssysteme. Sie helfen dabei, unnötige oder doppelte Aufträge zu vermeiden und sicherzustellen, dass Aufträge nur dann erteilt werden, wenn bestimmte Kriterien (wie das Überschreiten des gleitenden Durchschnitts) erfüllt sind.

  • Parameter für die Eingabe

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

Diese Variablen sind Eingabeparameter, die es ermöglichen, das Verhalten des EA von außen zu konfigurieren, ohne den Code selbst zu ändern. Händler können diese Parameter über die EA-Einstellungen der MetaTrader-Oberfläche ändern. Sie verwalten Variablen wie Take-Profit, Stop-Loss, Losgröße und schnellen Periodenlängen.

Nachdem wir die Bedeutung von Variablen erklärt haben, haben wir erkannt, dass Daten, auf die über Ticks und Funktionen hinweg zugegriffen werden muss, in globalen Variablen in MQL5 gespeichert werden. Denn sie dienen der Speicherung wichtiger Daten, darunter Auftragsparameter, Handelsstatus, Indikatorwerte und nutzerdefinierte Einstellungen. Sie werden verwendet, um die Handelsstrategie auszuführen, Positionen zu halten und auf Marktbedingungen zu reagieren.

Gewiss! Schauen wir uns den Initialisierungsteil des Codes an. Die Funktion OnInit ist für die Einrichtung des Anfangszustands des Expertenberaters zuständig. Zunächst werden mit der Funktion iMA Handles für die schnellen und langsamen Durchschnitte erstellt. Wir prüfen, ob diese Handles gültig sind. Wenn ein Handle ungültig ist, schlägt die Initialisierung fehl. Wir definieren dann die Arrays maFast und maSlow mit ArraySetAsSeries als Zeitreihen-Arrays und geben schließlich den Erfolg zurück.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   
   handleMAFast = iMA(_Symbol,_Period,fastPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMAFast == INVALID_HANDLE){
      Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   handleMASlow = iMA(_Symbol,_Period,slowPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMASlow == INVALID_HANDLE){
      Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   ArraySetAsSeries(maFast,true);
   ArraySetAsSeries(maSlow,true);
   
   return(INIT_SUCCEEDED);
}

Jetzt kommen wir die Deinitialisierungsfunktion. Innerhalb des MQL5-Expertenberatersystems wird die Funktion aufgerufen, wenn der Expertenberater geschlossen oder aus dem Chart entfernt wird. Hier findet die Bereinigung der Aufgaben statt.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }

In diesem Fall ist die Funktion leer, was bedeutet, dass bei der Deinitialisierung des EA keine besonderen Aktionen durchgeführt werden. 

Ein ganzzahliger Parameter „reason“, der die Ursache der Deinitialisierung angibt, wird von der Funktion übernommen. Dies kann passieren, weil das Terminal geschlossen ist, der EA aus dem Chart genommen wurde oder aus anderen Gründen.

Wir gehen nun zur Funktion OnTick über, die jedes Mal ausgelöst wird, wenn ein neuer Tick (Preisänderung) empfangen wird. Die Handelslogik wird in dieser Funktion angewendet. Die Funktion OnTick im bereitgestellten Code führt die auf dem gleitenden Durchschnitts-Crossover basierende Handelsstrategie aus.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   
   if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   
   //if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }
   
   if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }
   
   else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }
      else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

Hier ist die detaillierte Aufschlüsselung der OnTick-Funktion zum besseren Verständnis:

Wir rufen Bid und Ask ab: Die Funktion ermittelt die aktuellen Brief- und Geldkurse und rundet sie auf die entsprechende Anzahl von Dezimalstellen. Das Abrufen und Normalisieren aktueller Preise ist für eine Handelsstrategie mit Kaskadenaufträgen unerlässlich, um fundierte Entscheidungen über die Platzierung von Aufträgen zu verschiedenen Preispunkten zu treffen. Bei der Umsetzung der Handelsstrategie kaskadierender Aufträge ist es notwendig, die aktuellen Marktpreise genau im Auge zu behalten. Dies bedeutet, dass Sie die Geld- und Briefkurse für das Symbol, mit dem Sie im MetaTrader handeln, abrufen. Der aktuelle Briefkurs für das angegebene Symbol (_Symbol) wird durch Aufruf der Funktion ermittelt. Der Preis, zu dem Sie diesen Vermögenswert kaufen können, wird als Briefkurs (Ask) bezeichnet. Mit diesem Funktionsaufruf wird der aktuelle Geldkurs (Bid) für das Symbol abgefragt. Der Preis, zu dem Sie diesen Vermögenswert erwerben können, wird als Geldkurs bezeichnet.

double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

Die Normalisierung stellt sicher, dass die abgerufenen Preise den Anforderungen an die Genauigkeit der Handelssymbole entsprechen. Davon hängt auch die Vermeidung von Problemen mit der Fließkommamathematik ab. Der Wert wird durch diesen Funktionsaufruf auf die angegebene Anzahl von Dezimalstellen (_Digits) gerundet. Die Anzahl der Nachkommastellen, die das Symbol unterstützt, ist in der Regel für das Symbol vordefiniert.

Wir duplizieren die Puffer für den gleitenden Durchschnitt: Die Funktion ermittelt die neuesten Werte für die gleitenden Durchschnitte, sowohl für die langsamen als auch für die schnellen. Die Funktion bricht ab, und es wird eine Fehlermeldung ausgegeben, wenn nicht genügend Daten vorhanden sind. Gleitende Durchschnitte werden in einer Handelsstrategie mit Kaskadenaufträgen verwendet, um Abschlüsse zu erkennen und den richtigen Zeitpunkt für die Platzierung von Aufträgen zu bestimmen. Damit die Strategie zuverlässig ist, müssen vor Beginn der Studie genügend Daten zu den gleitenden Durchschnitten vorliegen.

if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }

Diese Funktion überträgt Informationen aus dem Puffer für schnelllaufende Durchschnittsindikatoren in das Array maFast. Das Handle des Indikators für den gleitenden Durchschnitt, die Puffernummer, die für die Hauptzeile des Indikators normalerweise 0 ist, der Anfangspunkt, von dem aus die Daten kopiert werden sollen, die Anzahl der zu duplizierenden Elemente und das Array, in dem die Datenkopie gespeichert wird. Die Anzahl der erfolgreich kopierten Elemente wird von der Funktion zurückgegeben. Bei der Überprüfung der Lebensfähigkeit der Daten wird festgestellt, ob die maFast weniger als drei Elemente kopiert hatte. Weniger als drei übertragene Komponenten deuten darauf hin, dass die Daten des schnell gleitenden Durchschnitts nicht ausreichen, um eine solide Analyse zu erstellen. Die Funktion beendet die Ausführung, indem sie eine Meldung ausgibt und vorzeitig zurückkehrt. Der sich langsam bewegende Durchschnitt mit den Griffen MASlow und maSlow folgt der gleichen Logik.

Hier ist ein Chart der gleitenden Durchschnitte im Vergleich zu den Kursdaten. Die Darstellung umfasst die Kursreihe, den schnell gleitenden Durchschnitt (10-Tage-EMA) und die langsam gleitenden Durchschnitte (20-Tage-EMA).

KREUZEN GLEITENDER DURCHSCHNITTE

Bevor wir irgendwelche Handelsentscheidungen treffen, stellt die Strategie sicher, dass eine Mindestmenge an historischen Daten aus den gleitenden Durchschnitten vorhanden ist. Das hilft, eine vertrauenswürdige und sachkundige Auswahl zu treffen. Die Strategie verhindert unzureichende Informationen, die zu falschen Signalen und möglicherweise zu Verlusten führen könnten, indem sie prüft, ob genügend Daten vorhanden sind. Dieses Snippet dient als Validierungsschritt vor dem Handel. Wenn die Bedingung nicht erfüllt ist, kehrt die Strategie zurück und führt für diesen Tick keine Handelsgeschäfte oder Analysen aus.

Gleitende Durchschnitte werden verwendet, um die Richtung und Stärke eines Trends in einer Kaskadenhandelsstrategie zu bestimmen. Wenn der sich schnell bewegende Durchschnitt beispielsweise den sich langsam bewegenden Durchschnitt über- oder unterschreitet, können Sie Aufträge auf unterschiedlichen Niveaus platzieren.

Prüfen, ob wir eine Position eröffnen: Die Auslöseflags des Systems für Kauf- und Verkaufs werden zurückgesetzt, wenn keine offenen Positionen vorhanden sind. Um Transaktionsüberschneidungen zu vermeiden und den Status des Handelssystems effizient zu verwalten, ist es bei der Verwendung einer Handelsstrategie mit Kaskadenaufträgen unerlässlich, auf offene Positionen zu achten. Einer der Mechanismen, die wir in dieser Funktion realisiert haben, ist das Zurücksetzen bestimmter Flags, wenn keine freien Plätze vorhanden sind.

//if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }

Mit dieser Funktion wird die Gesamtzahl der offenen Positionen für das aktuelle Handelskonto zurückgegeben. Es ist hilfreich herauszufinden, ob es einen aktiven Handel gibt. Wenn wir annehmen, dass PositionasTotal() == 0 bestimmt diese Bedingung, dass es insgesamt 0 offene Positionen gibt, was bedeutet, dass im Moment keine Handelsgeschäfte offen sind. Die Flags isBuySytemInitiated und isSellSystemInitiated werden auf false gesetzt, wenn es keine offenen Positionen gibt. Wir setzten das Flag zurück, das anzeigt, ob das Kaufsystem initiiert wurde oder nicht (_isBuySystemInitiated = false;). Wir setzten das Flag zurück, das anzeigt, ob das Verkaufssystem eingeleitet wurde oder nicht (_isSellSystemInitiated = false;).

Der Ansatz stellt sicher, dass neue Handelsgeschäfte nur dann begonnen werden, wenn es keine offenen Positionen gibt, indem in regelmäßigen Abständen überprüft wird, ob offene Positionen vorhanden sind, und die Auslöse-Flag zurückgesetzt werden. Auf diese Weise werden sich überschneidende Handelsgeschäfte, die zu einem übermäßigen Risiko oder zu widersprüchlichen Handelsaktionen führen können, vermieden. Wir verwalten das Handelssystem durch das Auslösen von Flags, isBuySystemInitiated und isSellSystemInitiated. Diese Flags sorgen dafür, dass das System bis zur Schließung der aktuellen Positionen nicht mehr als einmal identische Kauf- oder Verkaufsaufträge innerhalb eines bestimmten Trends startet. Diese Prüfung hilft uns auch dabei, den logischen Ablauf der Strategie aufrechtzuerhalten. Der Ansatz kann genau auf die Marktbedingungen und -trends reagieren, indem er sicherstellt, dass neue Aufträge genau dann platziert werden, wenn es angebracht ist, d. h. wenn keine offenen Positionen bestehen. Wir erreichen ein besseres Risikomanagement, indem wir verhindern, dass zahlreiche Positionen gleichzeitig offen sind. Auf diese Weise kann die Strategie das Marktengagement begrenzen und ein mögliches Überstrapazieren verhindern.

 Erkennen eines neuen Balkens: Auf der Grundlage der Überkreuzungen der gleitenden Durchschnitte sucht es nach Kauf- oder Verkaufssignalen, wenn sich ein neuer Balken (Kerze) gebildet hat und keine offenen Positionen bestehen. Um eine mehrfache Ausführung der Handelsstrategie zu verhindern, ist es wichtig, das Entstehen eines neuen Balkens zu erkennen. Die Verwendung der Daten des letzten Balkens als Grundlage für Handelsentscheidungen im Gegensatz zu den möglicherweise instabilen Preisänderungen innerhalb des Balkens verbessert die Handelsgenauigkeit.

if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }

Wenn PositionsTotal == 0, Diese Bedingung stellt sicher, dass die Funktion des if-Blocks nur ausgeführt wird, wenn keine offenen Positionen vorhanden sind. Auf diese Weise wird verhindert, dass sich die Handelsgeschäfte überschneiden, und neue Handelsgeschäfte werden erst nach der Schließung älterer Geschäfte eröffnet. Die Funktion IsNewBar() ermittelt, ob sich seit dem letzten Lauf ein neuer Balken gebildet hat. Im Wesentlichen sollte diese Methode true zurückgeben, wenn die Öffnungszeit zuvor erfasst wurde.

Beim Kaufsignal wird festgestellt, ob der jüngste Balken eine Aufwärtskreuzung erlebt hat oder ob der sich schnell bewegende Durchschnitt (MA) den sich langsam bewegenden Durchschnitt nach oben überquert hat. Wenn dies der Fall ist, werden Take-Profit und Stop-Loss berechnet und die Meldung „BUY SIGNAL“ veröffentlicht Danach wird das Flag isBuySystemInitiated auf true gesetzt und eine Kauforder mit obj_Trade.Buy() übermittelt. Unten sehen Sie ein EMA Crossover Kaufsignal der Handelsstrategie kaskadierender Aufträge:

Kaufsignal

Beim Verkaufssignal bestimmen wir hier, ob der jüngste Balken ein Abwärtskreuzung zeigt, was bedeutet, dass der sich schnell bewegende Durchschnitt (MA) den sich langsam bewegenden Durchschnitt unterschritten hat. Ist dies der Fall, werden Take-Profit und Stop-Loss berechnet und gibt die Meldung „SELL SIGNAL“ ausgegeben. Danach verwendet er obj_Trade, um einen Verkaufsauftrag zu senden. Das Flag isSellSystemInitiated wird von Sell() auf true gesetzt. Unten sehen Sie ein EMA Crossover Verkaufssignal der Handelsstrategie kaskadierender Aufträge:

Verkaufssignal

Die Strategie stellt sicher, dass die Handelslogik nur einmal pro Balken ausgeführt wird, indem sie erkennt, wenn ein neuer Balken erkannt wird. Auf diese Weise wird das Problem vermieden, dass mehrere Aufträge innerhalb desselben Balkens erteilt werden, was zu einem übermäßigen Handel und höheren Transaktionsgebühren führen kann. Wenn wir fertige Balken-Daten verwenden, um Handelsentscheidungen zu treffen, ist gewährleistet, dass die Entscheidungen auf vertrauenswürdigen Informationen beruhen. Kursveränderungen innerhalb von Balken können verrauscht sein und zu fehlerhaften Konsequenzen führen. Der Zustand des Handelssystems wird effektiv verwaltet, indem die Prüfung, dass keine offenen Positionen vorhanden sind, mit der Erkennung eines neuen Balkens kombiniert wird. Dadurch wird gewährleistet, dass neue Geschäfte nur dann getätigt werden, wenn es notwendig ist, und der logische Ablauf der Strategie erhalten bleibt. 

Ausführen von Kauf- oder Verkaufsaufträgen: - Ein Kaufauftrag wird erteilt, wenn der sich schnell bewegende Durchschnitt den sich langsam bewegenden Durchschnitt überquert. Er löst einen Verkaufsauftrag aus, wenn der schnelle MA unter den langsamen MA fällt. Außerdem werden die Auslösungs-Flags geändert und die Einstellungen für Take Profit und Stop Loss (SL) festgelegt. Diese „Kaskadierung“ der Aufträge trägt dazu bei, allmählich eine Position aufzubauen, wenn sich der Preis zugunsten des ersten Geschäfts bewegt.

else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }

In den Kaskaden der Kaufaufträge stellt die Strategie fest, ob das Take-Profit erreicht wurde und ob der Briefkurs derzeit über oder gleich diesem Level liegt. Dieser Umstand bedeutet, dass ein zusätzlicher Kaufauftrag ausgelöst wurde, da sich der Kurs zu Gunsten der aktuellen Kaufposition entwickelt hat. Take-Profit wird um eine vorher festgelegte Anzahl von Punkten angehoben, wodurch ein neuer globaler Wert für das nächste Inkrement in der Kaskade festgelegt wird. Durch die Änderung von Stop-Loss wird sichergestellt, dass das Risiko für den neuen Auftrag kontrolliert wird, und Stop-Loss wird auf ein neues Niveau unterhalb des Angebotspreises geändert. „Additional of Buy Order“ platziert einen zweiten Kaufauftrag mit der angegebenen Lotgröße, der zum aktuellen Ask-Kurs wirksam wird. Durch die Änderung laufender Handelsgeschäfte wird das Risiko für die Gesamtposition gesteuert, der Stop-Loss für laufende Kaufpositionen wird auf das neue Stop-Loss-Niveau geändert.

Die Strategie „Sequentieller Verkaufsauftrag“ bestimmt, ob der aktuelle Geldkurs kleiner oder gleich dem Take-Profit ist und ob das Verkaufssystem begonnen hat. Diese Situation bedeutet, dass ein zusätzlicher Verkaufsauftrag ausgelöst wurde, da sich der Kurs zugunsten der aktuellen Verkaufsposition bewegt hat. Take-Profit wird um eine vorher festgelegte Anzahl von Punkten gesenkt, wodurch ein neues Ziel für die nächste Stufe der Kaskade festgelegt wird. Durch die Aktualisierung des Stop-Loss wird sichergestellt, dass das Risiko für den neuen Verkaufsauftrag kontrolliert wird; das Stop-Loss wird auf ein neues Niveau oberhalb des bestehenden Geldkurses geändert. Ein zusätzlicher Verkaufsauftrag mit der angegebenen Losgröße wird zum aktuellen Geldkurs ausgeführt. Durch die Änderung der laufenden Handelsgeschäfte wird das Risiko auf breiter Front kontrolliert, der Stop-Loss für laufende Verkaufspositionen wird auf das neue Stop-Loss-Niveau geändert.

Aktuelle Positionen anpassen: Wenn es offene Positionen gibt und der Kurs die Take-Profit-Schwelle erreicht, werden weitere Aufträge erteilt und die Stop-Loss-Beträge entsprechend aktualisiert. Dies hilft bei der schrittweisen Gewinnmaximierung und dem Risikomanagement.

else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

Ein boolesches Flag mit der Bezeichnung isBuySystemInitiated zeigt an, ob das Kaufsystem gestartet wurde oder nicht. Ein boolesches Flag namens isSellSystemInitiated zeigt an, ob das Verkaufssystem gestartet wurde oder nicht. Der Briefkurs, der aktuelle Geldkurs, die Höhe des Take-Profits, die Anzahl der Punkte, die zur Änderung der Take-Profit-Schwelle erforderlich sind, die Höhe des Stop-Loss, der Minimalpunkt der Stop-Loss-Anpassung, die Lotgröße des Trades, die Möglichkeit, einen Kaufauftrag zu erteilen, die Möglichkeit, einen Verkaufsauftrag zu erteilen, und die Funktion, mit der Sie den Stop-Loss einer bestehenden Position ändern können.

Wir überprüfen nun, ob das UT-System gestartet wurde und ob der Angebotspreis zum jetzigen Zeitpunkt die Gewinnschwelle erreicht oder überstiegen hat. Anhebung des Take-Profit-Levels um eine vorher festgelegte Anzahl von Punkten. Dies ermöglicht es der Strategie, zusätzliche mögliche Gewinne zu erzielen, indem ein neues Take-Profit-Ziel gesetzt wird, das höher als das bestehende ist. Setzen des Stop-Loss auf einen neuen, niedrigeren Kurs als den Briefkurs. Das Festhalten eines Teils der früheren Gewinne hilft beim Risikomanagement. Durch die Ausführung zusätzlicher Kaufaufträge zum Briefkurs wurde der zweite Kaufauftrag mit der angegebenen Losgröße zum Briefkurs ausgeführt. Wenn sich der Kurs zu Gunsten des anfänglichen Handelsgeschäftes entwickelt, wird die Position schrittweise erhöht. Die Stop-Loss-Werte aller aktuellen Kaufpositionen werden aktualisiert, um den neuen Stop-Loss-Wert zu berücksichtigen. Dies trägt dazu bei, das mit der Kaufposition verbundene Gesamtrisiko zu kontrollieren.

Als Nächstes überprüfen wir, ob der Verkaufsmechanismus gestartet wurde und ob der Bid-Preis die Gewinnschwelle erreicht oder unterschritten hat. Wir reduzieren Take-Profit um eine feste Anzahl von Punkten. Infolgedessen ist das neue Ziel für die Take-Profit niedriger als das bisherige Niveau. Nach der Aktualisierung des Stop-Loss wird der Stop-Loss auf ein neues Niveau oberhalb des Geldkurses verschoben. Das Festhalten eines Teils der früheren Gewinne hilft beim Risikomanagement. Wir schließen einen zusätzlichen Verkaufsauftrag mit einer bestimmten Losgröße zum aktuellen Geldkurs ab. Wenn sich der Kurs zu Gunsten des anfänglichen Handels bewegt, wird die Position schrittweise erhöht. Stop Loss aller aktuellen Verkaufspositionen wird aktualisiert, um den neuen Stop Loss-Betrag zu berücksichtigen. Dies trägt dazu bei, das mit der Verkaufsposition verbundene Gesamtrisiko zu kontrollieren.

Wenn sich der Markt zu Gunsten der ersten Transaktion verschiebt, erhöht die Strategie schrittweise die Handelsposition. Auf diese Weise kann der Händler seine Position erhöhen, ohne zunächst ein übermäßiges Risiko einzugehen, und von bedeutenden Trends profitieren. Die Strategie ermöglicht ein effektives Risikomanagement, indem sie die Stop-Loss-Niveaus sowohl für neue Aufträge als auch für offene Positionen variiert. Wenn der Markt nach unten dreht, hilft dies, Gewinne zu sichern und Verluste zu reduzieren. Immer wenn sich der Markt in die von der Kaskadenstrategie bevorzugte Richtung bewegt, werden schrittweise neue Gewinnmitnahmen festgelegt, um die Gewinne zu maximieren. Dies ermöglicht künftiges Wachstum und garantiert gleichzeitig eine schrittweise Bindung der Erträge.

Schauen wir uns nun die beiden Utility-Funktionen in unserem MQL5 Expert Advisor (EA) Code an. IsNewBar und ModifyTrades. Diese Routinen bieten die notwendigen Hilfsoperationen zur Unterstützung der zentralen Handelslogik, die in der OnTick-Funktion enthalten ist.

Wir beginnen mit der Funktion IsNewBar. Diese Funktion prüft das Chart, um festzustellen, ob sich ein neuer Balken oder eine neue Kerze gebildet hat. Dies ist notwendig, um zu gewährleisten, dass bestimmte Aktionen, wie z. B. das Eröffnen neuer Geschäfte, nur einmal pro Bar ausgeführt werden.

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

bool IsNewBar(){
   static int prevBars = 0;
   int currBars = iBars(_Symbol,_Period);
   if (prevBars==currBars) return (false);
   prevBars = currBars;
   return (true);
}

Die Anzahl der Balken des vorangegangenen Ticks wird in der statischen Variable prevBars gespeichert. Der Wert der Variablen bleibt zwischen den Funktionsaufrufen dank des Schlüsselworts static erhalten. Present from Bar count**: currBars ruft die aktuelle Balkenanzahl des Charts ab. Vergleich**: Die Funktion gibt false zurück, wenn noch kein neuer Balken erzeugt wurde und prevBars und currBars gleich sind. Wenn sie sich nicht einig waren, entstand eine neue Situation. Die Funktion gibt true zurück, nachdem prevBars auf currBars aktualisiert wurde. 

Kommen wir nun zur Funktion Music ModifiyTrades. Basierend auf dem angegebenen Positionstyp passt die Funktion ModifyTrades die Stop-Loss-Niveaus (SL) der aktiven Positionen an.

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl){
   for (int i=0; i<=PositionsTotal(); i++){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (type==posType){
               obj_Trade.PositionModify(ticket,sl,0);
            }
         }
      }
   }
}

In dieser Funktion:

  1. Schleife über Positionen: verwendet positionsTotal(), um alle offenen Positionen durchzugehen.
  2. Ticket abrufen: Gibt den Ort mit der Ticketnummer von index{i} zurück.
  3. Ticket überprüfen: Überprüfen Sie, ob die Ticketnummer echt ist (größer als 0).
  4. Position wählen: Verwendet PositionSelectByTicket} zur Auswahl der Position.
  5.  **Positionstyp** prüfen: Überprüft, ob der angegebene posType mit dem Positionstyp übereinstimmt.
  6. **Position ändern**: Verwenden Sie PositionModify, um die Übereinstimmung der Positionsarten zu ändern.

Der vollständige Code der Cascade Order Trading Strategy lautet wie folgt:

//|                                                     CASCADE ORDERING.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
CTrade obj_Trade;

int handleMAFast;
int handleMASlow;
double maSlow[], maFast[];

double takeProfit = 0;
double stopLoss = 0;
bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    handleMAFast = iMA(_Symbol, _Period, fastPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMAFast == INVALID_HANDLE) {
        Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    handleMASlow = iMA(_Symbol, _Period, slowPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMASlow == INVALID_HANDLE) {
        Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    ArraySetAsSeries(maFast, true);
    ArraySetAsSeries(maSlow, true);

    return (INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    // Cleanup code if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    if (CopyBuffer(handleMAFast, 0, 1, 3, maFast) < 3) {
        Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
        return;
    }
    if (CopyBuffer(handleMASlow, 0, 1, 3, maSlow) < 3) {
        Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
        return;
    }

    if (PositionsTotal() == 0) {
        isBuySystemInitiated = false;
        isSellSystemInitiated = false;
    }

    if (PositionsTotal() == 0 && IsNewBar()) {
        if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]) {
            Print("BUY SIGNAL");
            takeProfit = Ask + tpPts * _Point;
            stopLoss = Ask - slPts * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, stopLoss, 0);
            isBuySystemInitiated = true;
        } else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]) {
            Print("SELL SIGNAL");
            takeProfit = Bid - tpPts * _Point;
            stopLoss = Bid + slPts * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, stopLoss, 0);
            isSellSystemInitiated = true;
        }
    } else {
        if (isBuySystemInitiated && Ask >= takeProfit) {
            takeProfit = takeProfit + tpPts * _Point;
            stopLoss = Ask - slPts_Min * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, 0);
            ModifyTrades(POSITION_TYPE_BUY, stopLoss);
        } else if (isSellSystemInitiated && Bid <= takeProfit) {
            takeProfit = takeProfit - tpPts * _Point;
            stopLoss = Bid + slPts_Min * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, 0);
            ModifyTrades(POSITION_TYPE_SELL, stopLoss);
        }
    }
}

    static int prevBars = 0;
    int currBars = iBars(_Symbol, _Period);
    if (prevBars == currBars) return (false);
    prevBars = currBars;
    return (true);
}

//+------------------------------------------------------------------+
//| ModifyTrades Function                                            |
//+------------------------------------------------------------------+

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl) {
    for (int i = 0; i <= PositionsTotal(); i++) {
        ulong ticket = PositionGetTicket(i);
        if (ticket > 0) {
            if (PositionSelectByTicket(ticket)) {
                ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
                if (type == posType) {
                    obj_Trade.PositionModify(ticket, sl, 0);
                }
            }
        }
    }
}


Schlussfolgerung

Schließlich ist dieser MQL5-Expertenberater ein großartiges Beispiel für eine gut ausgeführte Handelsstrategie der Kreuzung von gleitenden Durchschnitten. Der Artikel zeigt die effiziente Automatisierung von Handelsentscheidungen durch die Verwendung der Trade.mqh-Bibliothek, um die Auftragsverwaltung zu optimieren und dynamische Ebenen für die Gewinnmitnahme und den Stopp-Loss einzubeziehen.

Zu den hervorstechenden Eigenschaften dieses Expertenberaters gehören:

  • Initialisierung und Verwaltung: Kauf- und Verkaufssignale auf Basis von Crossovers werden systematisch verwaltet und gleitende Durchschnitte effizient initialisiert.
  • Risikomanagement: Verwendung von Take-Profit- und Stop-Loss-Verfahren zur Risikominderung und zur Gewährleistung von Erträgen innerhalb eines vom Nutzer konfigurierbaren Rahmens.
  • Modularität und Flexibilität: Verwendung von Eingabeparametern und globalen Variablen zur Anpassung an unterschiedliche Marktsituationen und Handelspräferenzen. 

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

Erstellen einer interaktiven grafischen Nutzeroberfläche in MQL5 (Teil 2): Hinzufügen von Steuerelementen und Reaktionsfähigkeit Erstellen einer interaktiven grafischen Nutzeroberfläche in MQL5 (Teil 2): Hinzufügen von Steuerelementen und Reaktionsfähigkeit
Die Erweiterung des MQL5-GUI-Panels um dynamische Funktionen kann die Handelserfahrung für die Nutzer erheblich verbessern. Durch die Einbindung interaktiver Elemente, Hover-Effekte und Datenaktualisierungen in Echtzeit wird das Panel zu einem leistungsstarken Werkzeug für moderne Händler.
Aufbau des Kerzenmodells Trend-Constraint (Teil 6): Alles in einem integrieren Aufbau des Kerzenmodells Trend-Constraint (Teil 6): Alles in einem integrieren
Eine große Herausforderung ist die Verwaltung mehrerer Chartfenster desselben Paares, in denen das gleiche Programm mit unterschiedlichen Funktionen läuft. Lassen Sie uns besprechen, wie Sie mehrere Integrationen in einem Hauptprogramm zusammenfassen können. Darüber hinaus werden wir Einblicke in die Konfiguration des Programms für den Druck in ein Journal und die Kommentierung der erfolgreichen Signalübertragung auf der Chartschnittstelle geben. Weitere Informationen finden Sie in diesem Artikel, der eine Fortsetzung der Artikelserie ist.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Datenwissenschaft und ML (Teil 26): Der ultimative Kampf der Zeitreihenprognosen — LSTM vs. GRU Neuronale Netze Datenwissenschaft und ML (Teil 26): Der ultimative Kampf der Zeitreihenprognosen — LSTM vs. GRU Neuronale Netze
Im vorigen Artikel haben wir ein einfaches RNN besprochen, das trotz seiner Unfähigkeit, langfristige Abhängigkeiten in den Daten zu verstehen, in der Lage war, eine profitable Strategie zu entwickeln. In diesem Artikel werden sowohl das Long-Short Term Memory (LSTM) als auch die Gated Recurrent Unit (GRU) behandelt. Diese beiden wurden eingeführt, um die Unzulänglichkeiten eines einfachen RNN zu überwinden und es zu überlisten.