
Nutzerdefinierter Indikator: Darstellen von partiellen Eintritts-, Austritts- und Stornogeschäften für Netting-Konten
Inhalt
- Einführung
- Was ist ein Netting-Konto?
- Arbeiten mit Handelsereignissen
- Praktisches Beispiel für die Verwendung. Einführung
- Indikator-Eigenschaften
- Beschreibung des Algorithmus
- Ein weiteres praktisches Beispiel
- Integration mit einem Expert Advisor für den Handel
- Schlussfolgerung
1. Einführung
Wenn wir von Indikatoren sprechen, können wir an verschiedene Funktionen denken: Darstellen (Histogramme, Trendlinien, Pfeile oder Balken), Berechnen von Daten auf der Grundlage von Preis- und Volumenbewegungen und Beobachten von statistischen Mustern in unseren Geschäften. In diesem Artikel werden wir jedoch eine andere Art der Konstruktion eines Indikators in MQL5 betrachten. Wir werden darüber sprechen, wie Sie Ihre eigenen Positionen verwalten können, einschließlich Einstiege, partielle Ausstiege, usw. Wir werden ausgiebig Gebrauch von dynamischen Matrizen und einigen Handelsfunktionen machen, die sich auf die Handelshistorie und offene Positionen beziehen.
2. Was ist ein Netting-Konto?
Wie der Titel des Artikels andeutet, ist dieser Indikator nur für ein Konto mit einem Netting-Buchhaltungssystem sinnvoll. In diesem System ist nur eine Position desselben Symbols zulässig. Wenn wir in eine Richtung handeln, wird die Positionsgröße zunehmen. Wenn der Handel in die entgegengesetzte Richtung erfolgt, gibt es für die offene Position drei mögliche Optionen:
- Der neue Handel hat ein geringeres Volumen -> die Position wird verringert
- Die Volumina sind gleich -> die Position ist geschlossen
- Das neue Handelsgeschäft hat ein höheres Volumen -> die Position wird umgedreht
Auf einem Hedging-Konto können wir z. B. zwei EURUSD-Kaufgeschäfte mit je einer Losgröße (Lot) tätigen, was zu zwei verschiedenen Positionen für dasselbe Instrument führen wird. Wenn Sie auf einem Netting-Konto zwei EURUSD-Kaufgeschäfte mit je einer Losgröße tätigen, wird eine einzige Position mit zwei Losgrößen zum gewichteten Durchschnittspreis der beiden Handelsgeschäfte erstellt. Da die Volumina beider Abschlüsse gleich waren, ist der Positionspreis das arithmetische Mittel der Preise beider Abschlüsse.
Diese Berechnung wird wie folgt durchgeführt:
Wir haben einen Durchschnittspreis (P), gewichtet mit dem Volumen (N) in Lots für jedes Handelsgeschäft.
Für detailliertere Informationen über die Unterschiede zwischen den Systemen empfehle ich die Lektüre des von MetaQuotes verfassten Artikels: „Hedging-System zur Verrechnung von Positionen in MetaTrader 5 verfügbar“. Ab diesem Punkt werden wir in diesem Artikel alle Operationen betrachten, die auf einem Verrechnungskonto durchgeführt werden. Wenn Sie noch kein solches Konto haben, können Sie ein kostenloses Demokonto bei MetaQuotes eröffnen, wie unten gezeigt.
Klicken Sie in MetaTrader 5 auf Datei > Konto eröffnen:
Sobald das Demokonto eröffnet ist, klicken Sie auf die Schaltfläche Weiter und lassen Sie die Option „Absicherung im Handel verwenden“ deaktiviert.
3. Arbeiten mit Handelsereignissen
Operationen mit Handelsereignissen sind für die Verwaltung von Aufträgen, Geschäften und Positionen erforderlich. Handelsaufträge können sofort (market order) ausgeführt werden oder als schwebender Auftrag (pending order) platziert werden, und, sobald ein Auftrag ausgeführt wurde, können Operationen generiert werden, die eine Position eröffnen, schließen oder ändern.
Indikatoren dürfen keine Funktionen wie OrderSend() verwenden, aber sie können mit der Handelsgeschichte und den Positionseigenschaften abrufen. Mit der Funktion OnCalculate kann ein Indikator Informationen wie Eröffnungskurs, Schlusskurs, Volumen usw. erhalten. Obwohl die Funktion OnTrade() in erster Linie in Expert Advisors verwendet wird, ist sie auch auf Indikatoren anwendbar, da diese Handelsereignisse außerhalb des Strategietesters erkennen können, wodurch die Aktualisierung von Chart-Objekten schneller und effizienter wird.
4. Praktisches Beispiel für die Verwendung. Einführung
Die folgende Abbildung zeigt ein praktisches Beispiel für die Verwendung des von uns entwickelten nutzerdefinierten Indikators. Es gibt eine Kaufposition mit drei Lots, die aus einem größeren Handelsgeschäft stammt, das mehrere partielle Ein- und Ausstiege (und sogar Umkehrungen) hatte. Dies erklärt die offensichtliche Diskrepanz zwischen dem in der Tabelle angegebenen Durchschnittspreis und den notierten Preisen sowie den Losgrößen. Durch die Überwachung von Handelsereignissen können Sie die Kriterien verstehen, nach denen der Algorithmus Linien entfernt und die Anzahl der Lots auf dem Bildschirm aktualisiert, wenn partielle Ausstiege auftreten.
5. Indikator-Eigenschaften
Zu Beginn der Beschreibung müssen die Eigenschaften der Indikatoren angegeben werden. Unser Indikator hat die folgenden Eigenschaften:
#property indicator_chart_window // Indicator displayed in the main window #property indicator_buffers 0 // Zero buffers #property indicator_plots 0 // No plotting //--- plot Label1 #property indicator_label1 "Line properties" #property indicator_type1 DRAW_LINE // Line type for the first plot #property indicator_color1 clrRoyalBlue // Line color for the first plot #property indicator_style1 STYLE_SOLID // Line style for the first plot #property indicator_width1 1 // Line width for the first plot
Dieser Code wirkt sich auf die Informationen aus, die auf beim Start des Indikators angezeigt werden, wo die Anfangsparameter abgefragt werden.
6. Beschreibung des Algorithmus
Die Funktion OnInit(), die zu Beginn des Programms ausgeführt wird, ist für die Initialisierung eines Arrays vom Typ double mit der Bezeichnung „Element“ zuständig, das als der eigentliche Indikatorpuffer fungiert. Dieses Array besteht aus drei Spalten, und jeder Index speichert den Preis (0), die Menge (1) und die Ticketnummer (2). Jede Zeile dieses Feldes entspricht einem bestimmten Handelsgeschäft in der Vergangenheit. Ist die Initialisierung erfolgreich, d.h. es wird bestätigt, dass es sich nicht um ein Hedge-Konto handelt, wird als Nächstes die Funktion OnTrade() ausgelöst. Tritt während der Initialisierung ein Fehler auf, wird der Indikator geschlossen und aus dem Chart entfernt.
Siehe:
int OnInit() { ArrayResize(Element,0,0); int res=INIT_SUCCEEDED; if(AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) res=INIT_FAILED; else OnTrade(); return(res); }
Nach der Initialisierung wird die Funktion OnTrade() nativ durch die Funktion OnCalculate() ausgelöst, wenn Handelsereignisse auftreten. Um sicherzustellen, dass die Funktion nur einmal und nur dann ausgelöst wird, wenn sich ein neue Kerze bildet, fügen wir einen Filter hinzu, der die Funktion isNewBar und die boolesche Variable isOldBar verwendet. Die Funktion OnTrade wird also in drei Fällen aktiviert: bei der Initialisierung, bei einer neuen Kerze und bei jedem Handelsereignis. Diese Prozesse ermöglichen das Lesen, Verarbeiten und Speichern von Ereignissen im Element-Array, die dann als grafische Objekte in Form von Linien und Text auf dem Bildschirm angezeigt werden.
Die Funktion OnTrade() aktualisiert die Schlüsselvariablen des Handelsalgorithmus. Sie beginnt mit einer Datetime-Variablen namens „date“, die die Startzeit der Auswahl aus der Handelshistorie speichert. Wenn zu Beginn des Programms keine offene Position vorhanden ist, wird die Variable „date“ mit der Eröffnungszeit der aktuellen Kerze aktualisiert.
Wenn ein Handel ausgeführt wird, gibt die Funktion PositionsTotal() einen Wert größer als Null zurück und filtert in einer Schleife die Positionen des Symbols heraus, das dem Chart entspricht, auf dem der Indikator läuft. Die Historie wird dann ausgewählt und die ausgeführten Aufträge, die der Positions-ID entsprechen, werden abgerufen. Die Variable „date“ wird mit dem ältesten Zeitpunkt dieser Aufträge aktualisiert, der dem Zeitpunkt der Erstellung der ID entspricht.
Wenn eine zweite Position mit einer anderen ID erscheint, müssen Sie prüfen, ob es grafische Elemente gibt, die mit der Funktion ClearRectangles() entfernt werden müssen, um sicherzustellen, dass alles auf dem neuesten Stand ist. Danach setzen wir die Größe des Element-Arrays auf Null, wodurch die darin enthaltenen Daten entfernt werden. Wenn keine offenen Positionen vorhanden sind, aktiviert die Funktion auch die Funktion ClearRectangnles() und setzt das Element-Array zurück. Die Variable „date“ speichert den Wert der letzten bekannten Serverzeit, d. h. die aktuelle Zeit. Schließlich wird der verbleibende Wert der Variablen „date“ an die Funktion ListOrdersPositions() übergeben.
void OnTrade() { //--- static datetime date=0; if(date==0) date=lastTime; long positionId=-1,numberOfPositions=0; for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i)) if(m_position.Symbol()==ativo000) { numberOfPositions++; positionId=m_position.Identifier(); oldPositionId=positionId; } if(numberOfPositions!=0) { //Print("PositionId: "+positionId); HistorySelectByPosition(positionId); date=TimeCurrent(); for(int j=0; j<HistoryDealsTotal(); j++) { ulong ticket = HistoryDealGetTicket(j); if(ticket > 0) if(HistoryDealGetInteger(ticket,DEAL_TIME)<date) date=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME); } if(HistoryDealsTotal()==1 && (ArraySize(Element)/3)>1) if(ClearRectangles()) ArrayResize(Element,0,0); } else { bool isClean=ClearRectangles(); ArrayResize(Element,0,0); if(isClean) date=TimeCurrent(); // Do not use the array until there is new open position ArrayPrint(Element); // If there are no errors, this function will not be called here: the array with zero size } ListOrdersPositions(date); }
Die Funktion ListOrdersPositions() spielt eine wichtige Rolle, da sie für die Aktivierung der Funktionen verantwortlich ist, die Einträge zum Element-Array hinzufügen oder daraus entfernen: die Funktionen AddValue() und RemoveValue(). Für den erhaltenen Parameter dateInicio gibt es zwei Optionen. Wenn es in dem für die Funktion HistorySelect(start, end) angegebenen Zeitraum keinen Handelshistorie gibt, springt sie direkt zum Ende des Verlaufs und ruft die Funktion PlotRectangles() auf, die die Objekte auf dem Bildschirm entsprechend dem Inhalt des Element-Arrays aktualisiert. Wenn es jedoch Handelsgeschäfte in der Historie gibt, sollte die Funktion HistoryDealsTotal() einen Wert ungleich Null zurückgeben. In diesem Fall wird eine neue Prüfung durchgeführt, um jedes gefundene Geschäft zu untersuchen, es nach Eintragstyp zu klassifizieren und Informationen über Preis, Volumen und Ticketnummer zu sammeln. Mögliche Geschäftsarten: DEAL_ENTRY_IN, DEAL_ENTRY_OUT und DEAL_ENTRY_INOUT.
Handelt es sich um eine Eröffnung, so wird die Funktion AddValue aktiviert. Wenn ein Handelsgeschäft geschlossen wurde, wird RemoveValue mit den folgenden Parametern aktiviert: Preis, Volumen und zuvor erhaltene Ticketnummern. Bei einer Umkehrung wird die Funktion AddVolume() auch dann ausgelöst, wenn die Ticketnummer nicht zuvor in das Array eingegeben wurde. Zusätzlich werden die Parameter Preis und Volumen übergeben, wobei letzteres als Differenz zwischen dem gesammelten Volumen und dem Volumen der noch im Array vorhandenen früheren Abschlüsse berechnet wird.
Dieser Prozess simuliert die Rekonstruktion einer historischen Position: Wenn wir auf einen Umkehrposition stoßen, wird die Position umgekehrt und in das Array aufgenommen, als ob es sich um einen neuen Eintrag handeln würde, der die Lot-Zahl anpasst. Außerdem werden die Zeilen, die bis zu diesem Zeitpunkt auf dem Bildschirm zu sehen waren, gelöscht. Die Funktion Sort() sortiert das Element-Array in aufsteigender Reihenfolge nach der Preisspalte und entfernt aus dem Chart die Objekte, deren Werte in Spalte 1 (Volumen) des Arrays Null sind. Schließlich prüft diese Funktion auf Inkonsistenzen und entfernt aus dem Array die Zeilen, deren Indizes 0 und 1 (Preis und Volumen) gleich Null sind.
void ListOrdersPositions(datetime dateInicio) { //Analyze the history datetime inicio=dateInicio,fim=TimeCurrent(); if(inicio==0) return; HistorySelect(inicio, fim); double deal_price=0, volume=0,newVolume; bool encontrouTicket; uint tamanhoElement=0; for(int j=0; j<HistoryDealsTotal(); j++) { ulong ticket = HistoryDealGetTicket(j); if(ticket <= 0) return; if(HistoryDealGetString(ticket, DEAL_SYMBOL)==_Symbol) { encontrouTicket=false; newVolume=0; // Need to reset each 'for' loop volume=HistoryDealGetDouble(ticket,DEAL_VOLUME); deal_price=HistoryDealGetDouble(ticket,DEAL_PRICE); double auxArray[1][3] = {deal_price,volume,(double)ticket}; if(HistoryDealGetInteger(ticket,DEAL_ENTRY)==DEAL_ENTRY_IN) AddValue(deal_price,volume,(double)ticket); if(HistoryDealGetInteger(ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT) RemoveValue(deal_price,volume,(double)ticket); if(HistoryDealGetInteger(ticket,DEAL_ENTRY)==DEAL_ENTRY_INOUT) { tamanhoElement = ArraySize(Element)/3; //Always check the array size, it can vary with the Add/RemoveValue() functions for(uint i=0; i<tamanhoElement; i++) if(Element[i][2]==ticket) { encontrouTicket=true; break; } if(!encontrouTicket) // If after the previous scanning we don't find mentioning of the ticket in the array { for(uint i=0; i<tamanhoElement; i++) { newVolume+=Element[i][1]; Element[i][1]=0; } newVolume=volume-newVolume; AddValue(deal_price,newVolume,double(ticket)); } } } } PlotRectangles(); }
7. Ein weiteres praktisches Beispiel
Die oben dargestellte Beschreibung des Algorithmus reicht aus, um seine Funktionsweise besser zu verstehen. Betrachten wir sie nun genauer anhand eines Beispiels, das die beteiligten Operationen und den Inhalt der wichtigsten Variablen zeigt. Die Trades werden außerhalb des Strategietesters ausgeführt, und die Trade-Ereignisse werden erkannt. Wir wissen, dass auf einem Netting-Konto die Abschlüsse für jede Position die gleiche Kennung haben, sodass wir sie nach diesem Kriterium filtern können. Nachfolgend sind als Beispiel die Ereignisse einer bestimmten Position aufgeführt:
Zeit | Symbol | Deal | Typ | Richtung | Volumen | Preis |
---|---|---|---|---|---|---|
2023.05.04 09:42:05 | winm23 | 1352975 | buy | in | 1 | 104035 |
2023.05.04 09:43:16 | winm23 | 1356370 | sell | in/out | 2 | 103900 |
2023.05.04 16:34:51 | winm23 | 2193299 | buy | out | 1 | 103700 |
2023.05.04 16:35:05 | winm23 | 2193395 | buy | in | 1 | 103690 |
2023.05.04 16:35:24 | winm23 | 2193543 | buy | in | 1 | 103720 |
2023.05.04 16:55:00 | winm23 | 2206914 | sell | out | 1 | 103470 |
2023.05.04 17:27:26 | winm23 | 2214188 | sell | in/out | 2 | 103620 |
2023.05.04 17:30:21 | winm23 | 2215738 | buy | in/out | 4 | 103675 |
2023.05.05 09:03:28 | winm23 | 2229482 | buy | in | 1 | 104175 |
2023.05.05 09:12:27 | winm23 | 2236503 | sell | out | 1 | 104005 |
2023.05.05 09:19:18 | winm23 | 2246014 | sell | out | 1 | 103970 |
2023.05.05 09:22:45 | winm23 | 2250253 | buy | in | 1 | 103950 |
2023.05.05 16:00:10 | winm23 | 2854029 | sell | out | 1 | 106375 |
2023.05.05 16:15:40 | winm23 | 2864767 | sell | out | 1 | 106275 |
2023.05.05 16:59:41 | winm23 | 2884590 | sell | out | 1 | 106555 |
Unabhängig von den vorangegangenen Operationen hat das Element-Array zu diesem Zeitpunkt eine Größe von Null und keine offenen Positionen mehr. Um 09:42:05 Uhr am 04. Mai 2023 wird ein Verkaufsgeschäft mit einer ganzen Losgröße ausgeführt (das bereits in der Historie der Plattform aufgezeichnet ist), das sofort die Funktion OnTrade() aufruft. Da MetaTrader 5 einige Minuten zuvor (09:15 Uhr) auf dem Computer gestartet wurde, war genug Zeit, um die Datumsvariable auf 2023.05.04 09:15:00 zu aktualisieren, und dieser Wert wurde seitdem dort gespeichert. In OnTrade() gehen wir die Liste der offenen Positionen durch. Der von uns verwendete Kontotyp erlaubt nur eine Position pro Symbol. In diesem Fall ist es WINM23. Die Variable numberOfPositions nimmt den Wert 1 an, und die Variable positionID nimmt den Wert 1352975 an, der mit dem Ticket des ersten Handelsgeschäftes übereinstimmt, das wiederum die Nummer des Auftrags ist, durch den es erstellt wurde. Jetzt wird die Datumsvariable mit der Uhrzeit des Handelsgeschäfts aktualisiert, und alle künftigen Handelsgeschäfte bis zur Geschäftsnummer 2193299 erhalten von der Funktion Identifier() die gleiche Uhrzeit.
Die Funktion ListOrdersPositions(date) wird ausgelöst und wählt den Zeitraum von 09:42:05 bis TimeCurrent() aus, um die historischen Daten abzurufen. Innerhalb der Schleife wird bei Erkennung eines Eintrags vom Typ „IN“ die Funktion AddValue() mit den Parametern price=104035, volume=1 und ticket=1352975 aufgerufen. Da AddValue() dieses Ticket nicht in dem ursprünglich leeren Array findet, fügt es eine neue Zeile mit den drei angegebenen Werten ein. Die Funktion ArrayPrint(Element) zeigt diese Matrix dann auf dem Terminal an.
Anschließend wird die Funktion PlotRectangles() aufgerufen, die die Zeitstempel der aktuellen Kerze und der 15. vorherigen Kerze speichert. Diese Werte bestimmen die Länge der zu zeichnenden Linie. Die Funktion GetDigits() definiert die Anzahl der Dezimalstellen für die Tick-Größe des Symbols (in diesem Fall Null), die verwendet wird, um die Namen der Objekte neben den im Element-Array gespeicherten Kurswerten zu generieren. Rechteck- und Textobjekte werden erstellt, solange das entsprechende Preisvolumen im Array ungleich Null ist und die Objekte im Chart nicht vorhanden sind. Wenn ein Objekt bereits vorhanden ist, werden seine Attribute, wie Farbe, Text und Position, aktualisiert. Obwohl diese Rechtecke technisch als Linien funktionieren (da sie keine Höhe haben), wurde OBJ_RECTANGLE ursprünglich gewählt, um eine zukünftige Funktion zum Löschen aller Objekte dieses Typs beim Entfernen des Charts zu ermöglichen. Dieser allgemeine Löschmechanismus wurde zwar nie umgesetzt, aber die Verwendung von Rechtecken mit einer Höhe von Null wurde beibehalten. So wird die Zeile im Array, die dem Kaufgeschäft 104035 entspricht, bearbeitet. Da sein Volumen ungleich Null ist und das Objekt mit dem Namen „104035text“ noch nicht existiert, werden die zugehörigen Text- und Rechteckobjekte erstellt.
In der nächsten Minute wird ein Verkaufsgeschäft über zwei Lots abgeschlossen. Da die Kaufposition bereits das Volumen von einem Lot hat, führt dies zu einer Umkehrung der Position, sodass eine Verkaufsposition von einem Lot resultiert. MetaTrader fügt dieses Geschäft sofort zu den Historieneinträgen hinzu. Es gilt dieselbe Verarbeitungslogik wie zuvor, wobei die Auftragshistorie in einer Schleife durchlaufen wird. Der Deal mit dem Ticket=1352975 taucht innerhalb des gewählten Zeitraums wieder auf und wird an die Funktion AddValue() übergeben. Da die Funktion dieses Ticket nun in dem einzigen vorhandenen Array-Eintrag findet, beendet sie sich, ohne einen neuen Eintrag hinzuzufügen. Das nächste erkannte Handelsgeschäft ist vom Typ „INOUT“, und das einzige vorhandene Handelsgeschäft im Array hat seinen Element[0][1]-Wert in newVolume gespeichert, das dann auf Null gesetzt wird.
Das Transaktionsvolumen wird berechnet als HistoryDealGetDouble(ticket, DEAL_PRICE) - newVolume, und newVolume = 2 - 1 = 1. Folglich wird AddValue(103900, 1, 135370) nach der gleichen Logik ausgeführt. Die Funktion PlotRectangles() wird erneut ausgeführt, und nachdem das Array mit Sort() in aufsteigender Reihenfolge sortiert wurde, ist der erste Preis im Array nun 103900. Da im Chart keine Objekte für diesen Preis existieren, werden sie erstellt. Das zweite Array-Element (mit dem Preis 104035) hat seine Objekte bereits gezeichnet, sodass seine Attribute aktualisiert werden. In diesem Stadium enthält das Element-Array: {{103900,1,1356370}}, {104035,0,1352975}}.
Im weiteren Verlauf des Prozesses erscheint ein drittes Handelsgeschäfts, das als Ausstiegsgeschäft mit Preis=103700, Volumen=1 und Ticket=2193299 identifiziert wird. Der Exit-Deal löst die Funktion RemoveValue() mit diesen Parametern aus. RemoveValue() bricht ab, wenn es auf ein Volumen von Null oder eine bestehende Zeile mit demselben Ticket trifft. Da diese Bedingungen nicht erfüllt sind, sucht die Funktion mit ArrayBsearch() nach dem zu entfernenden Preis. Es handelt sich um einen binären Suchalgorithmus, der ein sortiertes Array erfordert (wie durch Sort() sichergestellt). Der Index, der 103700 am nächsten liegt, ist der erste Eintrag in der Matrix. Da das Volumen dieser Zeile ebenfalls eins ist, wird es auf Null gesetzt, was die Funktion RemoveRectangle() auslöst, die die mit dem Preis 103900 verbundenen grafischen Objekte entfernt. Anschließend fügt AddValue() die Zeile {103700,0,219299} ein, die durch Sort() unverändert bleibt. Die Position ist nun geschlossen. In diesem Stadium enthält das Element-Array: {{103700,0,219299}}, {103900,0,1356370}}, {104035,0,1352975}}.
Wenn eine Position vollständig geschlossen ist, wird die Variable numberOfPositions auf Null gesetzt, und wenn ClearRectangles() erfolgreich ausgeführt wurde, wird die Variable isClean auf true gesetzt. Das Array wird geleert und das Datum auf die aktuelle Zeit aktualisiert. Das bedeutet, dass für den neu festgelegten Zeitraum keine Aufträge zurückgegeben werden. Das System wartet auf ein neues Handelsgeschäft, um mit der Übergabe an das Array und der Verarbeitung der nachfolgenden Aktionen fortzufahren. Zu diesem Zeitpunkt ist das Element-Array leer: { }. Dadurch wird das System in einen Zustand versetzt, der dem zu Beginn dieses Beispiels beschriebenen Zustand ähnelt. Die gleiche Logik kann angewandt werden, um das Verhalten des Indikators bei nachfolgenden Handelsgeschäften zu verstehen. Im aktuellen Beispiel beginnt der Vorgang beim Preis 103690, wie in „7. Ein weiteres praktisches Beispiel“. Wenn man die einzelnen Schritte sorgfältig verfolgt, wird klar, warum das in diesem ersten Beispiel beschriebene Verhalten auftritt. Die Erklärung hängt mit den Preisen der Exit-Geschäfte zusammen und damit, wie der Algorithmus nacheinander die Zeilen entfernt, deren Preise denen der „DEAL_ENTRY_OUT“-Geschäfte am nächsten kommen.
8. Integration mit einem Expert Advisor für den Handel
Es gibt zwei Möglichkeiten, nutzerdefinierte Indikatoren wie diesen im Strategietester zu verwenden. Der erste Ansatz besteht darin, einen Expert Advisor (EA) oder einen anderen Indikator zu erstellen, der den nutzerdefinierten Indikator aufruft. Stellen Sie dazu sicher, dass sich die kompilierte Datei „Plotagem de Entradas Parciais.ex5“ im Ordner „Indicators“ befindet. Fügen Sie dann die folgenden Codezeilen in die OnInit()-Funktion des Aufrufers ein. Denken Sie daran, die globale Variable handlePlotagemEntradasParciais als Typ int zu deklarieren, bevor Sie dies tun:
iCustom(_Symbol,PERIOD_CURRENT,"Plotagem de Entradas Parciais"); //--- if the handle is not created if(handlePlotagemEntradasParciais ==INVALID_HANDLE) { //--- Print an error message and exit with an error code PrintFormat("Failed to create indicator handle for symbol %s/%s, error code %d", _Symbol, EnumToString(_Period), GetLastError()); //--- The indicator is terminated prematurely return(INIT_FAILED); }
Mit dem zweiten Ansatz entfällt die Notwendigkeit, diese Zeilen im EA zu ändern, sodass es eine bequemere Option für Tests ist. Laden Sie den Indikator einfach mit der Standardmethode in das Chart und speichern Sie die Vorlage unter dem Namen „Tester.tpl“ (überschreiben Sie gegebenenfalls eine vorhandene Datei mit demselben Namen). Dadurch wird sichergestellt, dass der Indikator jedes Mal, wenn der EA getestet wird, automatisch geladen wird. Beachten Sie, dass diese Methode nur relevant ist, wenn der visuelle Modus mit Chartanzeige im Strategietester aktiviert ist.
9. Schlussfolgerung
Wir haben einen nutzerdefinierten Indikator erstellt, der partielle Einträge darstellt, um neue Wege zur Erstellung und Nutzung von Indikatoren in MQL5 zu erkunden, einer der fortschrittlichsten und modernsten Programmiersprachen für MetaTrader 5, einer führenden Handelsplattform.
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/12576





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.