
Einführung in MQL5 (Teil 16): Aufbau von Expert Advisors mit technischen Chart-Mustern
Einführung
Willkommen zurück zu Teil 16 der Serie Einführung in MQL5! Dieser Teil verspricht besonders interessant zu werden, da wir auf dem bisher Gelernten aufbauen und dabei wie üblich einen projektbasierten Ansatz verwenden. Gemeinsam arbeiten wir an einem praktischen Projekt, das technische Analysemuster und MQL5-Codierung kombiniert, um einen Expert Advisor zu erstellen, und helfen Ihnen, Ihre Fähigkeiten durch praktische Erfahrung zu vertiefen.
Wir werden uns auf das Muster Kopf-Schultern konzentrieren - ein beliebtes technisches Muster, das zur Identifizierung potenzieller Trendumkehrungen verwendet wird. Unser Projekt wird als Expert Advisor konzipiert sein, der dieses Muster automatisch erkennen und entsprechende Trades ausführen kann. Darüber hinaus dient er als Indikator, um die Formation Kopf-Schultern auf dem Chart visuell hervorzuheben, was es Ihnen erleichtert, das Muster in realen Handelsszenarien zu erkennen und zu verstehen.
In diesem Artikel erfahren Sie mehr darüber:
- Automatisierter Handel mit Chart-Mustern
- Wie man das Muster Kopf-Schultern identifiziert
- Programmgesteuertes Zeichnen von Umkehrpunkten
- Verwendung von Chart-Objekten in MQL5
- Einstieg, Stop Loss und Take Profit festlegen
- Vermeidung von Signalwiederholungen
1. Chart-Muster verstehen
Visuelle Formen auf Preis-Charts, die zur Vorhersage künftiger Marktbewegungen verwendet werden können, werden als Chart-Muster bezeichnet. Diese Trends, die häufig ein Indikator dafür sind, ob sich ein Trend fortsetzen oder umkehren wird, sind das Ergebnis des ständigen Kampfes zwischen Käufern und Verkäufern. Ein Muster Kopf-Schultern beispielsweise signalisiert in der Regel eine mögliche Umkehr von einem Aufwärtstrend zu einem Abwärtstrend, während ein Fahnenmuster während eines Aufwärtstrends häufig darauf hindeutet, dass sich der Trend wahrscheinlich fortsetzen wird. Wenn Sie Chart-Muster wie Dreiecke, Rechtecke und Doppelspitzen erkennen können, verbessert sich Ihre Fähigkeit, mögliche Handelschancen auf der Grundlage des vergangenen Kursverhaltens zu erkennen.
Analogie
Ähnlich wie Fußabdrücke im Sand sind Chart-Muster offensichtliche Hinweise, die durch den ständigen Konflikt zwischen Käufern und Verkäufern hinterlassen werden. Chart-Muster helfen Ihnen zu verstehen, was auf dem Markt passiert ist, und vorherzusagen, was als Nächstes passieren könnte, ähnlich wie Tierspuren einem erfahrenen Fährtenleser helfen können, zu erkennen, welches Tier vorbeigezogen ist und wohin es geht. Diese grafischen Muster auf den Kurs-Charts zeigen, wie sich die Marktteilnehmer kollektiv verhalten, und geben häufig Aufschluss darüber, ob sich der aktuelle Trend fortsetzen oder umkehren wird.
1.1. Kategorien von Mustern
Chart-Muster lassen sich im Allgemeinen in drei Hauptkategorien einteilen:
1.1.1. Umkehrmuster
Chart-Muster, die als Umkehrmuster bekannt sind, können genutzt werden, um mögliche Wendepunkte des Marktes zu erkennen. Sie deuten darauf hin, dass ein neuer Trend in die entgegengesetzte Richtung beginnt und dass der bestehende Trend möglicherweise endet. So kann ein Umkehrmuster beispielsweise darauf hindeuten, dass sich der Kurs auf einen Aufwärtstrend vorbereitet, wenn sich der Markt in einem Abwärtstrend befindet. Ebenso können diese Muster auf eine potenzielle Umkehr des Aufwärtstrends des Marktes hinweisen. Kopf und Schultern und Doppelboden sind typische Umkehrmuster.
Analogie
Umkehrmuster dienen als Indikatoren für eine mögliche Richtungsänderung des Marktes. Diese Muster deuten darauf hin, dass ein Trend, sei es ein Aufwärts- oder ein Abwärtstrend, nachlässt und sich umkehren könnte, ähnlich wie Fußabdrücke, die sich an einem Strand umdrehen, signalisieren, dass jemand die Richtung geändert hat. Sie helfen Händlern dabei, potenzielle Veränderungen in der Preisentwicklung zu erkennen, indem sie darauf hinweisen, wann Käufer oder Verkäufer beginnen, Macht auszuüben.
1.1.2. Fortsetzungsmuster
Chart-Muster, die als Fortsetzungsmuster bekannt sind, zeigen an, wann es am wahrscheinlichsten ist, dass der Markt seine derzeitige Richtung beibehält. Sie treten typischerweise in Zeiten der Konsolidierung oder bei kurzen Stopps in der Kursbewegung auf, bevor der Trend wieder einsetzt. So kann beispielsweise ein Fortsetzungsmuster in einem Aufwärtstrend darauf hindeuten, dass der Kurs nach einer kleinen Seitwärtsbewegung weiter steigt. In einem Abwärtstrend bedeutet dies, dass der Kurs nach der Pause wahrscheinlich weiter fallen wird. Rechtecke und Fahnen sind typische Muster für eine Fortsetzung.
Analogie
Ähnlich wie bei den Fußabdrücken machen die Fortsetzungsmuster eine kurze Pause, zeigen aber weiterhin in dieselbe Richtung. Stellen Sie sich vor, Sie folgen einer Person, die am Ufer entlang spaziert. Sie folgen einer kontinuierlichen Reihe von Schritten und stellen fest, dass die Abdrücke einen Moment innehalten - möglicherweise, um sich die Schnürsenkel zu binden oder sich umzusehen -, dann aber wieder in dieselbe Richtung weitergehen. Dies deutet darauf hin, dass sie nur eine kurze Pause eingelegt und ihre Meinung nicht geändert haben. In ähnlicher Weise deuten Fortsetzungsmuster darauf hin, dass der Markt für eine kurze Zeit pausiert, aber wahrscheinlich seinen derzeitigen Kurs fortsetzen wird. Diese Muster zeigen, dass sich das Momentum nicht umgekehrt hat und nur vorübergehend ruht, unabhängig davon, ob der Markt nach oben oder unten tendiert.
1.1.3. Neutrale Muster
Chart-Muster, die eine Konsolidierungsphase anzeigen, in der der Markt in jede Richtung ausbrechen kann, werden als neutrale Muster bezeichnet. Da keine Seite eindeutig dominiert, zeigen diese Muster ein Gleichgewicht zwischen Käufern und Verkäufern. Aus diesem Grund sind Händler gezwungen, auf einen bestätigten Ausbruch zu warten, bevor sie handeln, und der Kurs bewegt sich innerhalb einer engeren Spanne. Obwohl sie den Weg des Ausbruchs nicht vorhersagen können, helfen neutrale Muster den Händlern dabei, sich auf eine mögliche Bewegung vorzubereiten. Neutrale Muster, wie das symmetrische Dreieck, sind häufig zu sehen.
Analogie
Beim Handel sind neutrale Muster vergleichbar mit der Beobachtung von jemandem, der am Strand zögert und unsicher ist, was er als Nächstes tun soll. Neutrale Muster, bei denen sich Käufer und Verkäufer die Waage halten, spiegeln das Zögern des Marktes wider, so als könne man den nächsten Schritt nicht vorhersagen, solange er nicht feststeht. Obwohl es keine offensichtliche Tendenz nach oben oder unten gibt, deuten diese Muster darauf hin, dass ein Durchbruch in beide Richtungen erfolgen könnte.
2. Das Projekt einrichten
2.1. Wie der EA funktioniert
Der Expert Advisor (EA) in diesem Projekt ist so aufgebaut, dass er automatisch das Muster Kopf-Schultern auf dem Markt erkennt und Handelsgeschäfte auf der Grundlage dieser Struktur ausführt. Unabhängig davon, ob es sich um ein standardmäßiges oder ein Inverse Muster Kopf-Schultern handelt, erkennt der EA ein gültiges Muster, wählt den besten Einstiegspunkt und führt einen Handel in der erwarteten Ausbruchsrichtung aus.
Aber der EA ist noch nicht am Ende. Um das Muster auf dem Chart besser sichtbar und verständlich zu machen, werden wir auch grafische Objekte verwenden, um die linke Schulter, den Kopf und die rechte Schulter zu markieren. Diese visuellen Marker helfen dem Händler, das Muster zu bestätigen und verbessern die Klarheit bei der Überprüfung des Charts oder beim Backtesting der Strategie. Diese Methode bietet zusätzlich zur Automatisierung und Mustererkennung eine sichtbare Bestätigungsebene, die die Fehlersuche, das Lernen und sogar die Echtzeitüberwachung verbessern kann.
2.1.1. Logik für Kaufen
Um zu kaufen, erkennt der EA ein inverses Muster Kopf-Schultern, indem er sechs spezifische Umkehrpunkte in Folge erkennt:
- Umkehrpunkt Hoch (X): Ein anfängliches Hoch, das mit X gekennzeichnet ist.
- Umkehrpunkt Tief (A): Ein tieferes Tief nach X, gekennzeichnet mit A.
- Umkehrpunkt Hoch (B): Ein Rücksetzer, der ein niedrigeres Hoch als X aber höher als A bildet, wird mit B bezeichnet.
- Umkehrpunkt Tief (C): Ein tieferes Tief als A, das mit C bezeichnet wird - das ist der Kopf.
- Umkehrpunkt Hoch (D): Ein Umkehrpunkt Hoch, das ungefähr auf dem gleichen Niveau wie B liegt und mit D gekennzeichnet ist, bildet einen Teil der Nackenline.
- Umkehrpunkt Tief (E): Ein höheres Tief im Vergleich zu C und ungefähr auf dem gleichen Niveau wie A - das ist die zweite Schulter.
Sobald diese Struktur vorhanden ist:
- Der EA wartet auf eine Kerze, die über Punkt D (der Nackenline) schließt.
- Wenn dies der Fall ist, wird gekauft.
- Der Stop Loss (SL) wird auf das Tief von Punkt E gesetzt.
- Der Take Profit (TP) wird zunächst auf den Punkt X (dem ersten Umkehrpunkt Hoch) gesetzt.
Wenn jedoch der Abstand zwischen dem Einstiegspunkt und dem TP (X) weniger als 1x der Stop-Loss-Abstand beträgt, dann wird der EA X als Ziel ignorieren und setzt stattdessen ein festes Ziel von 1:3 Risiko-Ertrag basierend auf dem SL-Abstand. Dadurch wird sichergestellt, dass die Strategie ein minimales Risiko-Ertrags-Verhältnis beibehält und keine Handelsgeschäfte mit geringen Erträgen eingegangen werden, die das Risiko nicht wert sind.
2.1.1. Logik für Verkaufen
Um zu verkaufen, identifiziert der EA ein standardmäßiges Muster Kopf-Schultern, indem er sechs spezifische Umkehrpunkte in Folge erkennt:
- Umkehrpunkt Tief (X): Ein anfängliches Tief, gekennzeichnet mit X.
- Umkehrpunkt Hoch (A): Ein höheres Hoch nach X, gekennzeichnet mit A.
- Umkehrpunkt Tief (B): Ein Rücksetzer, der ein höheres Tief als X aber niedriger als A bildet, wird mit B bezeichnet.
- Umkehrpunkt Hoch (C): Ein höheres Hoch als A, das mit C bezeichnet wird - das ist der Kopf.
- Umkehrpunkt Tief (D): Ein Umkehrpunkt Tief, das ungefähr auf dem gleichen Niveau wie B liegt und mit D gekennzeichnet ist, bildet einen Teil der Nackenlinie.
- Umkehrpunkt Hoch (E): Ein niedrigeres Hoch im Vergleich zu C und ungefähr auf dem gleichen Niveau wie A - das ist die zweite Schulter.
Sobald diese Struktur bestätigt ist:
- Der EA wartet auf eine Kerze, die unter Punkt D (der Nackenlinie) schließt.
- Wenn dies geschieht, führt er einen Verkauf aus.
- Der Stop Loss (SL) wird auf dem Höchststand von Punkt E platziert.
- Der Take Profit (TP) wird zunächst auf den Punkt X (der erste tiefe Umkehrpunkt) gesetzt.
Wenn der Abstand vom Einstieg bis zum TP (X) weniger als ein Mal den Stop-Loss-Abstand beträgt, setzt der EA X als Ziel außer Kraft und wendet ein festes 1:3-Risiko-Ertrags-Ziel auf der Grundlage der SL-Größe an.
Anmerkung: Das Hauptziel der Handelsstrategie, die in diesem Projekt erforscht wird, besteht darin, Ihr Wissen über die MQL5-Programmierung zu erweitern, insbesondere über die Arbeit mit Chart-Mustern und die Erstellung nützlicher Expert Advisors. Es ist nicht dafür gedacht, mit echtem Geld oder für den Live-Handel verwendet zu werden. Bevor Sie eine Technik auf einem Live-Markt anwenden, sollten Sie immer einen umfassenden Backtest durchführen und sich von einem Finanzexperten beraten lassen.
3. Identifizierung von Muster Kopf-Schultern auf dem Chart
Ich denke, dass Sie die Idee der Chart-Muster inzwischen gut verstanden haben und genau wissen, was unser Expert Advisor (EA) leisten soll. Noch bevor der EA einen Handel tätigt, ist es wichtig, das Muster Kopf-Schultern auf dem Chart zu erkennen. Dies hilft Ihnen, Laufzeitfehler oder logische Probleme frühzeitig im Testprozess zu erkennen und zu bestätigen, dass die EA-Logik mit der realen Kursbewegung übereinstimmt.
In diesem Kapitel erfahren Sie, wie Sie die Kopf-Schultern-Struktur im Chart manuell hervorheben und validieren können, indem Sie verschiedene Chartkomponenten wie Trendlinien, Textbeschriftungen und Formen verwenden. Später im EA wird dies dazu beitragen, eine solide Grundlage für die Automatisierung der Erkennung zu schaffen.
3.1. Abrufen von Kerzen-Daten
Der erste Schritt besteht darin, Kerzen-Daten abzurufen, um das Muster Kopf-Schultern auf dem Chart zu lokalisieren. Sie beinhaltet Details zu den Eröffnungs-, Hoch-, Tief-, Zeit- und Schlusskursen der einzelnen Balken. Diese Werte sind von entscheidender Bedeutung, denn die Art und Weise, wie der Kurs über mehrere Kerzen hinweg schwankt, bestimmt die Struktur des Musters. Wir erheben diese Informationen jedoch nicht nur, um Trends zu erkennen. Außerdem soll er wie ein Indikator wirken, da wir einen Expert Advisor erstellen wollen, der diese Muster erkennen und eigenständig Handel treiben kann. Das bedeutet, dass es in der Lage sein muss, die Aufmerksamkeit auf frühere Muster Kopf-Schultern im Chart zu lenken, damit Sie sie erneut untersuchen und testen können.
Kurz gesagt, der EA, den wir entwickeln, wird zwei Funktionen haben: Er wird ein Handels-Bot sein, der Muster Kopf-Schultern erkennt und automatisch Handelsgeschäfte ausführt, und er wird auch ein Musterindikator sein, indem er ähnliche Strukturen in historischen Daten hervorhebt. Diese Doppelfunktionalität ermöglicht nicht nur den automatisierten Handel, sondern auch die visuelle Überprüfung von Signalen und die Untersuchung der Entwicklung und Performance des Musters in der Vergangenheit.
Beispiel:input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; // MA Time Frame input int bars_check = 1000; // Number of bars to check for swing points // Variable to store how many bars are available on the chart for the selected timeframe int rates_total; double open[]; // Array for opening prices double close[]; // Array for closing prices double low[]; // Array for lowest prices double high[]; // Array for highest prices datetime time[]; // Array for time (timestamps) of each bar //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- // Get the total number of bars available on the selected symbol and timeframe rates_total = Bars(_Symbol, timeframe); // Copy the open prices of the last 'rates_total' bars into the 'open' array CopyOpen(_Symbol, timeframe, 0, rates_total, open); // Copy the close prices of the last 'rates_total' bars into the 'close' array CopyClose(_Symbol, timeframe, 0, rates_total, close); // Copy the low prices of the last 'rates_total' bars into the 'low' array CopyLow(_Symbol, timeframe, 0, rates_total, low); // Copy the high prices of the last 'rates_total' bars into the 'high' array CopyHigh(_Symbol, timeframe, 0, rates_total, high); // Copy the time (timestamps) of the last 'rates_total' bars into the 'time' array CopyTime(_Symbol, timeframe, 0, rates_total, time); }
Erläuterung:
Zu Beginn der Funktion gibt es zwei nutzerdefinierte Eingabevariablen. Mit dem ersten, dem Zeitrahmen, kann der Nutzer den genauen Zeitraum auswählen, den der Expert Advisor (EA) verwenden soll. PERIOD_CURRENT ist die Standardeinstellung. Der EA verwendet also denselben Zeitrahmen wie der Chart, mit dem er verknüpft ist. Dank dieser Flexibilität können Sie mehrere Zeiträume untersuchen, ohne den Code zu ändern. Der EA wird durch den zweiten Parameter, bars_check, angewiesen, wie viele historische Kerzen (oder Balken) er bei der Untersuchung des Preisverhaltens betrachten soll. Der EA wird nach möglichen Musterstrukturen in den letzten 1000 Kerzen suchen, da er in diesem Fall auf 1000 eingestellt ist.
Der Code deklariert nach den Eingabedefinitionen einige Arrays und eine Variable zur Aufnahme von Marktdaten. Die Gesamtzahl der Balken (Kerzen), die für das ausgewählte Symbol und den ausgewählten Zeitrahmen verfügbar sind, wird in der Variablen rates_total gespeichert. Die zugehörigen Kursdaten jeder Kerze werden in Arrays wie open[], close[], low[] und high[] gespeichert. Wir können auch die genaue Zeit jeder Kerze bestimmen, indem wir die Zeitstempel für jeden Balken verwenden, die in dem Array time[] gespeichert sind. Da sie dem EA die Informationen liefern, die er benötigt, um das Chart zu untersuchen und Muster wie Kopf und Schultern zu finden, sind diese Arrays von entscheidender Bedeutung.
Bei diesem Projekt müssen wir Kerzen-Daten manuell mit Funktionen wie CopyOpen(), CopyHigh() und anderen replizieren, da es als Expert Advisor (EA) und nicht als nutzerdefinierter Indikator konzipiert ist. Wenn es sich um einen Indikator handelt, der die Methode OnCalculate() verwendet, werden diese Informationen bereits automatisch über die Funktionsparameter bereitgestellt, sodass wir uns die Mühe ersparen, sie zu kopieren.
Drei gängige MQL5-Funktionen - OnInit(), OnDeinit() und OnTick() - sind ebenfalls in der Struktur des EA enthalten. Wenn der EA geladen wird, wird die Methode OnInit() einmal aufgerufen. Er gibt einfach INIT_SUCCEEDED zurück und signalisiert damit, dass der EA für die Ausführung vorbereitet ist. Die Funktion OnDeinit(), die noch keine Aufräumlogik hat, wird aufgerufen, wenn das Terminal heruntergefahren oder der EA entfernt wird.
Die Funktion OnTick(), die jedes Mal ausgeführt wird, wenn eine neue Kursaktualisierung (Tick) stattfindet, ist der Ort, an dem die eigentliche Aktivität stattfindet. Die Funktion Bars() ermittelt zunächst die Anzahl der Balken, die derzeit auf dem Chart innerhalb dieser Funktion zugänglich sind. Die Preis- und Zeitdaten werden dann mit fünf Kopierfunktionen in die entsprechenden Arrays geladen: Die Eröffnungskurse werden mit CopyOpen() dem Array open[] zugewiesen, die Schlusskurse mit CopyClose() idem Array close[], die Hochs und Tiefs werden mit CopyLow() bzw. CopyHigh() gespeichert, und der Zeitstempel jeder Kerze wird mit CopyTime() gespeichert. Dieses Setup ist unerlässlich, denn es bereitet alle historischen Daten vor, die der EA für die Suche nach Chart-Mustern und die Untersuchung der Marktaktivität verwenden wird.
3.2. Identifizierung von Schwankungen
Nachdem wir erfolgreich die historischen Kerzen-Daten gesammelt haben, müssen wir die wichtigen Umkehrpunkte - X, A, B, C, D und E - finden, die die Kopf-Schultern- oder umgekehrte Muster Kopf-Schulternstruktur bilden. Der EA muss diese Schwankungen genau erkennen, um legitime Chart-Muster zu bestimmen, die die Wendepunkte in der Kursbewegung darstellen. Der EA hilft dabei, das Muster Schritt für Schritt abzubilden, indem er die wichtigsten Umkehrungen durch die Untersuchung der Höchst- und Tiefstwerte über die gewählte Anzahl von Balken identifiziert.
Beispiel://+------------------------------------------------------------------+ //| FUNCTION FOR SWING LOW | //+------------------------------------------------------------------+ bool IsSwingLow(const double &low_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(low_price[index] > low_price[index - i] || low_price[index] > low_price[index + i]) return false; } return true; } //+------------------------------------------------------------------+ //| FUNCTION FOR SWING HIGH | //+------------------------------------------------------------------+ bool IsSwingHigh(const double &high_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(high_price[index] < high_price[index - i] || high_price[index] < high_price[index + i]) return false; // If the current high is not the highest, return false. } return true; }
Erläuterung:
Wir verwenden zwei Funktionen, IsSwingLow() und IsSwingHigh(), um Kursschwingungspunkte zu bestimmen. Diese Merkmale bestimmen, ob eine bestimmte Kerze im Verhältnis zu ihren benachbarten Kerzen ein hoher Umkehrpunkt oder ein tiefer Umkehrpunkt bildet. Je nach Rückblickswert garantiert die Funktion, dass das Tief der aktuellen Kerze niedriger ist als die Tiefs einer vorher festgelegten Anzahl von Kerzen vor und nach ihr im Falle eines tiefen Umkehrpunktes. Ebenso wird bei einem hohen Umkehrpunkt überprüft, ob das Hoch der aktuellen Kerze größer ist als die Höchststände der umliegenden Kerzen. Da diese Idee bereits in Teil 14 dieser Serie ausführlich behandelt wurde, werden wir hier nicht zu sehr ins Detail gehen.
3.2.1. Identifizierung von XABCDE
Die Bedeutung der genauen Bestimmung der primären Umkehrpunkt - X, A, B, C und D - zur Erkennung des Muster Kopf-Schulterns sowohl in Kauf- als auch in Verkaufssituationen wird in diesem Aufsatz hervorgehoben. Diese Punkte stehen für signifikante Hochs und Tiefs, die das Muster beeinflussen und die Handelsaktionen des Expert Advisors steuern.
Beispiel:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- // Get the total number of bars available on the selected symbol and timeframe rates_total = Bars(_Symbol, timeframe); // Copy the open prices of the last 'rates_total' bars into the 'open' array CopyOpen(_Symbol, timeframe, 0, rates_total, open); // Copy the close prices of the last 'rates_total' bars into the 'close' array CopyClose(_Symbol, timeframe, 0, rates_total, close); // Copy the low prices of the last 'rates_total' bars into the 'low' array CopyLow(_Symbol, timeframe, 0, rates_total, low); // Copy the high prices of the last 'rates_total' bars into the 'high' array CopyHigh(_Symbol, timeframe, 0, rates_total, high); // Copy the time (timestamps) of the last 'rates_total' bars into the 'time' array CopyTime(_Symbol, timeframe, 0, rates_total, time); //FOR SELL if(show_sell) { if(rates_total >= bars_check) { for(int z = 7; z <= 10; z++) { for(int i = rates_total - bars_check; i < rates_total - z; i++) { if(IsSwingLow(low, i, z)) { // If a swing low is found, store its price, time, and create a name for the objects to mark the X. X = low[i]; // Price of the swing low (X). X_time = time[i]; // Time of the swing low (X). X_letter = StringFormat("X%d", i); // Unique name for the text label object. for(int j = i; j < rates_total - z; j++) { if(IsSwingHigh(high, j, z) && time[j] > X_time) { A = high[j]; // Price of the swing high (A). A_time = time[j]; // Time of the swing high (A) A_letter = StringFormat("A%d", j); // Unique name for the text label object for(int k = j; k < rates_total - z; k++) { if(IsSwingLow(low, k, z) && time[k] > A_time) { B = low[k]; // Price of the swing low (B). B_time = time[k]; // Time of the swing low (B). B_letter = StringFormat("B%d", k); // Unique name for the text label object. for(int l = k ; l < rates_total - z; l++) { if(IsSwingHigh(high, l, z) && time[l] > B_time) { C = high[l]; // Price of the swing high (C). C_time = time[l]; // Time of the swing high (C). C_letter = StringFormat("C%d", l); // Unique name for the text label object. for(int m = l; m < rates_total - z; m++) { if(IsSwingLow(low, m, z) && time[m] > C_time) { D = low[m]; // Price of the swing low (D). D_time = time[m]; // Time of the swing low (D). D_letter = StringFormat("D%d", m); // Unique name for the text label object. for(int n = m ; n < rates_total - (z/2) - 1; n++) { if(IsSwingHigh(high, n, (z/2)) && time[n] > D_time) { E = high[n]; // Price of the swing low (B). E_time = time[n]; // Time of the swing low (B). E_letter = StringFormat("E%d", n); // Unique name for the text label object. break; } } break; } } break; } } break; } } break; } } } } } } } }Erläuterung:
//X double X; // Price of the swing low (X). datetime X_time; // Time of the swing low (X). string X_letter; // Unique name for the text label object. //A double A; // Price of the swing high (A). datetime A_time; // Time of the swing high (A). string A_letter; // Unique name for the text label object. //B double B; // Price of the swing low (B). datetime B_time; // Time of the swing low (B). string B_letter; // Unique name for the text label object. //C double C; // Price of the swing low (B). datetime C_time; // Time of the swing low (B). string C_letter; // Unique name for the text label object. //D double D; // Price of the swing low (B). datetime D_time; // Time of the swing low (B). string D_letter; // Unique name for the text label object. //E double E; // Price of the swing low (B). datetime E_time; // Time of the swing low (B). string E_letter; // Unique name for the text label object.
In diesem Code werden drei verschiedene Arten von Variablen verwendet, um jeden der wichtigsten Umkehrpunkte des Musters darzustellen: X, A, B, C, D und E. Das genaue Preisniveau dieses Umkehrpunktes wird zunächst in einer Variablen vom Typ double gespeichert. double A; wird der Preis des hohe Umkehrpunkte mit der Bezeichnung A zugewiesen, während Double X. den Preis des tiefen Umkehrpunkts mit der Bezeichnung X erhält. Jeder Umkehrpunkt verwendet eine Datetime-Variable, um neben dem Preis auch den Zeitpunkt seines Auftretens festzuhalten. Auf diese Weise kann der EA die Umkehrpunkte genau in chronologischer Reihenfolge auf dem Chart anordnen. Mit datetime X_time; wird zum Beispiel der Zeitpunkt des tiefen Umkehrpunktes X und mit datetime A_time; der Zeitpunkt des hohen Umkehrpunktes A erfasst.
Schließlich wird mit Hilfe einer String-Variable für jeden Schwingungspunkt ein eindeutige Kennzeichung erzeugt. Um die Positionen der einzelnen Umkehrpunkte visuell zu kennzeichnen, werden diese Beschriftungen - z. B. X_Buchstabe oder A_Buchstabe - zur Konstruktion von Textobjekten im Chart verwendet. Der EA ist besser in der Lage, diese Punkte zu organisieren und anzuzeigen, sodass die Händler das sich entwickelnde Muster dank dieses Beschriftungssystems erkennen können. Preis, Zeit und Etikett sind die drei Informationen, die der EA verwendet, um jeden Umkehrpunkt so anzuordnen, dass er das Muster Kopf-Schultern auf dem Chart korrekt identifizieren und grafisch darstellen kann. Die Erkennung von Mustern und die Platzierung von leicht interpretierbaren visuellen Hinweisen für Händler hängen beide von dieser methodischen Technik ab.
if(show_sell) { if(rates_total >= bars_check) { for(int z = 7; z <= 10; z++) { for(int i = rates_total - bars_check; i < rates_total - z; i++) { if(IsSwingLow(low, i, z)) { // If a swing low is found, store its price, time, and create a name for the objects to mark the X. X = low[i]; // Price of the swing low (X). X_time = time[i]; // Time of the swing low (X). X_letter = StringFormat("X%d", i); // Unique name for the text label object. for(int j = i; j < rates_total - z; j++) { if(IsSwingHigh(high, j, z) && time[j] > X_time) { A = high[j]; // Price of the swing high (A). A_time = time[j]; // Time of the swing high (A) A_letter = StringFormat("A%d", j); // Unique name for the text label object for(int k = j; k < rates_total - z; k++) { if(IsSwingLow(low, k, z) && time[k] > A_time) { B = low[k]; // Price of the swing low (B). B_time = time[k]; // Time of the swing low (B). B_letter = StringFormat("B%d", k); // Unique name for the text label object. for(int l = k ; l < rates_total - z; l++) { if(IsSwingHigh(high, l, z) && time[l] > B_time) { C = high[l]; // Price of the swing high (C). C_time = time[l]; // Time of the swing high (C). C_letter = StringFormat("C%d", l); // Unique name for the text label object. for(int m = l; m < rates_total - z; m++) { if(IsSwingLow(low, m, z) && time[m] > C_time) { D = low[m]; // Price of the swing low (D). D_time = time[m]; // Time of the swing low (D). D_letter = StringFormat("D%d", m); // Unique name for the text label object. for(int n = m ; n < rates_total - (z/2) - 1; n++) { if(IsSwingHigh(high, n, (z/2)) && time[n] > D_time) { E = high[n]; // Price of the swing low (B). E_time = time[n]; // Time of the swing low (B). E_letter = StringFormat("E%d", n); // Unique name for the text label object. ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); break; } } break; } } break; } } break; } } break; } } } } } } }
Ausgabe:
Erläuterung:
Um festzustellen, ob das Programm nun so konfiguriert ist, dass es Verkaufsmuster erkennt, ermittelt der Code zunächst, ob die Variable show_sell wahr ist. Wenn die Erkennung von Verkaufsmustern nicht erforderlich ist, werden durch dieses einfache bedingte Tor sinnlose Berechnungen verhindert. Als Nächstes wird geprüft, ob die Gesamtzahl der Balken im Chart (rates_total) die Mindestschwelle bars_check überschreitet oder erreicht. Dies garantiert, dass genügend frühere Daten für eine genaue Mustererkennung vorhanden sind.
Die Variable z wird in der Regel als Fenstergröße oder Rückblickzeit für die Erkennung von Umkehrpunkten verwendet und in der äußersten Schleife über einen begrenzten Wertebereich iteriert. Die Technik zielt darauf ab, die Flexibilität und Präzision der Schwingungserkennung zu verbessern, indem mit mehreren Rückblickperioden experimentiert wird, die zwischen z = 7 und z = 10 liegen. Diese Schleife ermöglicht es dem Algorithmus, nach Mustern mit leicht unterschiedlichen Auflösungen oder Empfindlichkeiten zu suchen.
Von rates_total - bars_check bis rates_total - z durchläuft die anschließende for-Schleife die jüngsten Balken im Chart. Dieser Bereich konzentriert sich darauf, wo mögliche Muster für die aktuelle Preisaktion relevanter sind, indem der Suchbereich auf die jüngsten Balken begrenzt wird. Die Funktion IsSwingLow(low, i, z) wird in dieser Schleife verwendet, um nach einem Schwungtief zu suchen und festzustellen, ob der Balken an der Position i ein lokales Minimum auf der Grundlage des Rückblickfensters z ist.
Wenn ein tiefer Umkehrpunkt an der Position i erkannt wird, verwendet der Code StringFormat("X%d", i), um eine eindeutige Zeichenkette mit dem Namen X_letter zu erzeugen, speichert den Preis in der Variablen X und den Zeitstempel in X_time. Dank dieser Kennzeichnung kann der EA diesen Punkt auf dem Chart visuell leichter hervorheben und ihn für eine spätere Bearbeitung eindeutig identifizieren. Das Muster Kopf-Schultern beginnt mit diesem Punkt X als Referenz.
Um den nächste hohen Umkehrpunkt A zu bestimmen, der nach der Zeit X eintritt, startet der Code eine weitere verschachtelte Schleife, die bei i beginnt. Um die für das Muster erforderliche zeitliche Abfolge einzuhalten, wird mit IsSwingHigh(high, j, z) ermittelt, ob der Balken bei j ein hoher Umkehrpunkt ist, und es wird sichergestellt, dass die Zeit time[j] strikt größer als X_time ist. Der Preis, die Zeit und die Bezeichnung für A werden ähnlich wie bei X dokumentiert, wenn ein legitimer hoher Umkehrpunkt entdeckt wird.
Die folgenden Punkte, B, C, D und E, werden nacheinander durch diese verschachtelte Schleifenstruktur identifiziert. Durch Iteration der Balken wird jeder Umkehrpunkt lokalisiert, wobei überprüft wird, ob es sich um einen legitimen tiefen oder hohen Umkehrpunkt handelt und ob sein Zeitstempel strikt größer ist als der des vorangegangenen Punktes. Der Code erstellt eine eigene Zeichenkette und speichert den Preis und die Dauer für jeden bestätigten Umkehrpunkt. Die Musterpunkte werden durch diese strenge sequentielle Prüfung in der richtigen Reihenfolge gehalten.
Die innerste Schleife verwendet ein etwas engeres Rückblickfenster (z/2), um den Punkt E, das letzte Hoch des Musters, zu suchen. Dank dieser Diskrepanz kann der Algorithmus die Erkennungsempfindlichkeit für den letzten Punkt anpassen. Wenn E gefunden wird, verlässt der Code sofort die Schleife, um unnötige zusätzliche Suchvorgänge zu vermeiden und die Effizienz zu erhöhen. Anschließend ordnet es seinen Preis, seine Zeit und sein Label zu.
Das Muster Kopf-Schultern wird während dieses Prozesses dank der verschachtelten Schleifen und Zeitkontrollen genau in der richtigen Reihenfolge der Umkehrpunkte erkannt. Die Verwendung von eindeutigen Bezeichnungen wie "X%d" oder "A%d" ermöglicht es dem EA, Text oder grafische Elemente auf dem Chart zu generieren und zu steuern, sodass der Händler eine visuelle Darstellung des Musters erhält. Dank dieser methodisch strukturierten Vorgehensweise ist der Computer in der Lage, komplizierte Preisaktionsmuster zuverlässig zu erkennen und für Handelsentscheidungen zu nutzen.
Der Zweck des Codebeispiels bestand darin, die sechs entscheidenden Umkehrpunkte - X, A, B, C, D und E - zu identifizieren, die für die Erkennung eines Muster Kopf-Schulterns erforderlich sind. Die derzeitige Implementierung wendet jedoch noch nicht die genauen logischen Bedingungen an, die für die Validierung der Kopf-Schultern-Struktur erforderlich sind, sondern bestimmt diese Umschlagspunkte lediglich auf der Grundlage der Kursausschläge und ihrer zeitlichen Abfolge. Der Algorithmus sammelt die Preise, Zeiten und Bezeichnungen dieser Punkte, aber er überprüft nicht, ob sie wirklich das charakteristische Muster bilden.
Um die Gültigkeit eines Kopf und Schulter-Verkaufsmusters zu überprüfen, werden mehrere wichtige, auf der Preisstruktur basierende Kriterien herangezogen. A muss höher als X sein, B muss in der Mitte liegen (höher als X, aber niedriger als A), und C, der Kopf, muss höher als B sein. Die Spitze der rechten Schulter wird durch den Punkt E gebildet, der sich mit dem Punkt A deckt, während der Tiefpunkt der rechten Schulter durch den Punkt D dargestellt wird, der sich in der Nähe von Punkt B befindet.
Beispiel:
input color txt_clr = clrBlue; // Texts color //X double X; // Price of the swing low (X). datetime X_time; // Time of the swing low (X). string X_letter; // Unique name for the text label object. int x_a_bars; int x_lowest_index; double x_a_ll; datetime x_a_ll_t; //A double A; // Price of the swing high (A). datetime A_time; // Time of the swing high (A). string A_letter; // Unique name for the text label object. int a_b_bars; int a_highest_index; double a_b_hh; datetime a_b_hh_t; string A_zone; double A_low; //B double B; // Price of the swing low (B). datetime B_time; // Time of the swing low (B). string B_letter; // Unique name for the text label object. int b_c_bars; int b_lowest_index; double b_c_ll; datetime b_c_ll_t; string B_zone; double B_high; //C double C; // Price of the swing low (B). datetime C_time; // Time of the swing low (B). string C_letter; // Unique name for the text label object. int c_d_bars; int c_highest_index; double c_d_hh; datetime c_d_hh_t; //D double D; // Price of the swing low (B). datetime D_time; // Time of the swing low (B). string D_letter; // Unique name for the text label object. int d_e_bars; int d_lowest_index; double d_e_ll; datetime d_e_ll_t; double D_3bar_high; //E double E; // Price of the swing low (B). datetime E_time; // Time of the swing low (B). string E_letter; // Unique name for the text label object. double E_3bar_low; string xa; // Unique name for the trendline for XA. string ab; // Unique name for the trendline for AB. string bc; // Unique name for the trendline for BC. string cd; // Unique name for the trendline for CD. string de; // Unique name for the trendline for DE. string ex; // Unique name for the trendline for EX. //FOR SELL if(show_sell) { if(rates_total >= bars_check) { for(int z = 7; z <= 10; z++) { for(int i = rates_total - bars_check; i < rates_total - z; i++) { if(IsSwingLow(low, i, z)) { // If a swing low is found, store its price, time, and create a name for the objects to mark the X. X = low[i]; // Price of the swing low (X). X_time = time[i]; // Time of the swing low (X). X_letter = StringFormat("X%d", i); // Unique name for the text label object. for(int j = i; j < rates_total - z; j++) { if(IsSwingHigh(high, j, z) && time[j] > X_time) { A = high[j]; // Price of the swing high (A). A_time = time[j]; // Time of the swing high (A) A_letter = StringFormat("A%d", j); // Unique name for the text label object for(int k = j; k < rates_total - z; k++) { if(IsSwingLow(low, k, z) && time[k] > A_time) { B = low[k]; // Price of the swing low (B). B_time = time[k]; // Time of the swing low (B). B_letter = StringFormat("B%d", k); // Unique name for the text label object. for(int l = k ; l < rates_total - z; l++) { if(IsSwingHigh(high, l, z) && time[l] > B_time) { C = high[l]; // Price of the swing high (C). C_time = time[l]; // Time of the swing high (C). C_letter = StringFormat("C%d", l); // Unique name for the text label object. for(int m = l; m < rates_total - z; m++) { if(IsSwingLow(low, m, z) && time[m] > C_time) { D = low[m]; // Price of the swing low (D). D_time = time[m]; // Time of the swing low (D). D_letter = StringFormat("D%d", m); // Unique name for the text label object. for(int n = m ; n < rates_total - (z/2) - 1; n++) { if(IsSwingHigh(high, n, (z/2)) && time[n] > D_time) { E = high[n]; // Price of the swing high (E). E_time = time[n]; // Time of the swing high (E). E_letter = StringFormat("E%d", n); // Unique name for the text label object. d_e_bars = Bars(_Symbol, PERIOD_CURRENT, D_time, E_time); // Count the number of bars between D and E d_lowest_index = ArrayMinimum(low, m, d_e_bars); // Find the index of the lowest low in the range d_e_ll = low[d_lowest_index]; // Store the lowest low (D - E lowest point) d_e_ll_t = time[d_lowest_index]; // Store the corresponding time D_3bar_high = high[d_lowest_index - 3]; // The high price of the third bar before the bar that formed D c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time,d_e_ll_t); // Count the number of bars between C and V c_highest_index = ArrayMaximum(high,l,c_d_bars); // Find the index of the highest high in the range c_d_hh = high[c_highest_index]; // Store the lowest high (C - D lowest point) c_d_hh_t = time[c_highest_index]; // Store the corresponding time b_c_bars = Bars(_Symbol, PERIOD_CURRENT, B_time, c_d_hh_t); // Count the number of bars between B and C b_lowest_index = ArrayMinimum(low, k, b_c_bars); // Find the index of the lowest low in the range b_c_ll = low[b_lowest_index]; // Store the lowest low B - C lowest point) b_c_ll_t = time[b_lowest_index]; // Store the corresponding time B_high = high[b_lowest_index]; // The high price of the bar that formed swing low D a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time,b_c_ll_t); // Count the number of bars between A and B a_highest_index = ArrayMaximum(high,j,a_b_bars); // Find the index of the highest high in the range a_b_hh = high[a_highest_index]; // Store the lowest low A - B lowest point) a_b_hh_t = time[a_highest_index]; // Store the corresponding time A_low = low[a_highest_index]; x_a_bars = Bars(_Symbol, PERIOD_CURRENT, X_time, a_b_hh_t); // Count the number of bars between C and D x_lowest_index = ArrayMinimum(low, i, x_a_bars); // Find the index of the lowest low in the range x_a_ll = low[x_lowest_index]; // Store the lowest low (C - D lowest point) x_a_ll_t = time[x_lowest_index]; // Store the corresponding time for C - D E_3bar_low = low[n - 3]; // The LOW price of the third bar before the bar that formed E if(a_b_hh > x_a_ll && b_c_ll < a_b_hh && b_c_ll > x_a_ll && c_d_hh > a_b_hh && E < c_d_hh && d_e_ll > x_a_ll && d_e_ll <= B_high && D_3bar_high >= B_high && E > A_low && E_3bar_low < a_b_hh) { ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); xa = StringFormat("XA line%d", i); ab = StringFormat("AB line%d", i); bc = StringFormat("BC line%d", i); cd = StringFormat("CD line%d", i); de = StringFormat("DE line%d", i); ex = StringFormat("EX line%d", i); ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,x_a_ll_t,x_a_ll); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,a_b_hh_t,a_b_hh); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,b_c_ll_t,b_c_ll); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,c_d_hh_t,c_d_hh); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,d_e_ll_t,d_e_ll); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id, xa,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); ObjectSetInteger(chart_id,xa,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,xa,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, xa, OBJPROP_BACK, true); ObjectCreate(chart_id, ab,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); ObjectSetInteger(chart_id,ab,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ab,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ab, OBJPROP_BACK, true); ObjectCreate(chart_id, bc,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); ObjectSetInteger(chart_id,bc,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,bc,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, bc, OBJPROP_BACK, true); ObjectCreate(chart_id, cd,OBJ_TREND,0,c_d_hh_t,c_d_hh,d_e_ll_t,d_e_ll); ObjectSetInteger(chart_id,cd,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,cd,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, cd, OBJPROP_BACK, true); ObjectCreate(chart_id, de,OBJ_TREND,0,d_e_ll_t,d_e_ll,E_time,E); ObjectSetInteger(chart_id,de,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,de,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, de, OBJPROP_BACK, true); ObjectCreate(chart_id, ex,OBJ_TREND,0,E_time,E,time[n+(z/2)],x_a_ll); ObjectSetInteger(chart_id,ex,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ex,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ex, OBJPROP_BACK, true); A_zone = StringFormat("A ZONEe%d", i); B_zone = StringFormat("B ZONEe%d", i); ObjectCreate(chart_id,A_zone,OBJ_RECTANGLE,0,a_b_hh_t,a_b_hh,E_time,A_low); ObjectCreate(chart_id,B_zone,OBJ_RECTANGLE,0,b_c_ll_t,b_c_ll,d_e_ll_t,B_high); } break; } } break; } } break; } } break; } } break; } } } } } } }
Ausgabe:
Erläuterung:
Der Code enthält Variablendeklarationen, die zum Speichern wichtiger Informationen über die Struktur und die Komponenten eines nutzerdefinierten XABCDE-Musters in der Preisaktion verwendet werden. Jede Variable spielt eine spezifische Rolle bei der Identifizierung und Visualisierung der Hochs und Tiefs, die das Muster ausmachen, sowie bei der Beschriftung und Zeichnung der Struktur auf dem Chart. Die erste Gruppe von Variablen bezieht sich auf das Segment von Punkt X bis A. x_a_bars enthält die Anzahl der Balken zwischen diesen beiden Punkten. x_lowest_index speichert den Index des niedrigsten Preisbalkens in diesem Segment, während x_a_ll den tatsächlichen niedrigsten Preis (das „tiefere Tief“) und x_a_ll_t den entsprechenden Zeitpunkt des Auftretens dieses Tiefs speichert.
Die Strecke von A nach B wird von der folgenden Gruppe bearbeitet. Die Anzahl der Balken in diesem Abschnitt ist a_b_bars. Der Index des höchsten Balkens wird durch a_highest_index identifiziert, während das tatsächliche Hoch oder „höheres Hoch“ in a_b_hh gespeichert wird, wobei a_b_hh_t den Zeitpunkt des Ereignisses festhält. Diese unterstützen die Idee, dass Punkt B ein höheres Tief und Punkt A ein hoher Umkehrpunkt ist. Die Variablen b_c_bars, b_lowest_index, b_c_ll und b_c_ll_t erfassen dann die Anzahl der Balken, den niedrigsten Index, den niedrigsten Preis und den Zeitpunkt dieses Preises für den Abschnitt von B nach C. Dies dient der Validierung des nachfolgenden unteren Tiefpunkts der Struktur.
Die String-Variablen A_zone und B_zone werden wahrscheinlich verwendet, um eindeutige Objektnamen für die Erstellung rechteckiger Zonen in der Nähe der Positionen A und B zu speichern. Die Kursniveaus A_low und B_high, die als visuelle Hinweise oder Entscheidungsbereiche auf dem Chart dienen, definieren die unteren und oberen Grenzen dieser Zonen. Ähnlich wie die vorangegangenen Variablen speichern d_e_bars, d_lowest_index, d_e_ll und d_e_ll_t die Anzahl der Balken, den Index, den Preis und die Zeitdaten für das Segment von D bis E, was bei der Lokalisierung des letzten Schenkels des Musters hilfreich ist.
D_3bar_high und E_3bar_low werden verwendet, um das höchste Hoch in der Nähe von Punkt D und das tiefste Tief in der Nähe von Punkt E zu speichern, die typischerweise aus 3-Bar-Strukturen berechnet werden. Diese helfen dabei, die Echtheit der Umkehrpunkte zu überprüfen und Fehlalarme zu reduzieren. Schließlich sind die String-IDs für die Trendlinien, die zwischen den einzelnen Wendepunkten des Musters erstellt werden - von X nach A, A nach B usw. - die Variablen xa, ab, bc, cd, de und ex. Diese Zeichenketten garantieren, dass jedes Trendlinienobjekt einen eindeutigen Namen hat, was eine präzise und harmonische grafische Darstellung des gesamten Musters im Chart ermöglicht.
Untersuchung der Kursbewegungen zwischen den sechs entscheidenden Punkten, die mit den Buchstaben X, A, B, C, D und E gekennzeichnet sind. Es wird angenommen, dass diese Punkte den Hoch- und Tiefpunkten entsprechen, die besondere strukturelle Beziehungen schaffen. Der erste Schritt des Skripts ist die Suche nach dem niedrigsten Tiefpunkt (d_e_ll) zwischen den Punkten D und E. Anschließend werden die Uhrzeit und ein Referenzhoch (D_3bar_high) ermittelt, das drei Balken vor diesem Tief liegt. In ähnlicher Weise findet sie den höchsten Wert (c_d_hh) zwischen den Punkten C und d_e_ll. Er sammelt dann alle relevanten hohen und tiefen Umkehrpunkte zusammen mit den entsprechenden Zeitstempeln und wiederholt den Prozess rückwärts durch die Zeit bis zum Punkt X. Auf diese Weise verwendet der Code die Balkenanalyse, um die gesamte X-A-B-C-D-E-Schwungstruktur aufzubauen.
Zwischen zwei Zeitstempeln wird die Anzahl der Kerzen mit Hilfe der Funktion Bars() gezählt. Mit Hilfe von ArrayMaximum() und ArrayMinimum() können bestimmte Bereiche zwischen den Umkehrpunkten getrennt werden, sodass der Code Hochs und Tiefs innerhalb dieser Bereiche untersuchen kann. Um den höchsten oder niedrigsten Wert zu ermitteln, suchen diese Funktionen eine bestimmte Anzahl von Balken ab einem bestimmten Offset (i, j, k, usw.) ab. Dies hilft bei der Lokalisierung von Schwenkpunkten. ArrayMaximum(high, l, c_d_bars) zum Beispiel findet den höchsten Wert zwischen C und D, was den Punkt C ergibt. Der Punkt X wird erreicht, indem die Argumentation in der gesamten Struktur wiederholt wird.
Die strukturelle Beziehung zwischen den Punkten wird durch Auswertung einer Reihe von Bedingungen überprüft. Diese Kriterien vergleichen die Höchst- und Tiefstwerte der Segmente, d. h. es wird festgestellt, ob Punkt A höher ist als Punkt X, ob Punkt B niedriger ist als A, aber immer noch höher als X, ob Punkt C höher ist als A und so weiter. Damit wird vor der Darstellung der Kursbewegung bestätigt, ob sie tatsächlich das erwartete Muster bildet. E > A_low und E_3bar_low < a_b_hh sind Beispiele für Vergleiche, die garantieren, dass sich das E in einer legitimen Position in Bezug auf den Rest der Struktur befindet.
Die Methode verwendet ObjectCreate(), um die erkannten Punkte im Chart mit Textbeschriftungen („X“, „A“, „B“ usw.) und Trendlinien, die sie verbinden, grafisch zu kennzeichnen, sobald das Muster alle Anforderungen erfüllt. Diese Trendlinien verwenden OBJ_TREND-Objekte, um die XA-, AB-, BC-, CD-, DE- und EX-Schenkel des Musters zu zeichnen, und OBJ_TEXT-Objekte, um die Punkte zu kennzeichnen. Die Lesbarkeit wird durch Farben, Linienbreite und visuelle Überlagerung (über OBJPROP_BACK) verbessert.
Schließlich hebt der Code die A-Zone und die B-Zone, zwei entscheidende Preiszonen, durch Rechtecke hervor. Die A-Zone reicht vom Hoch des Punktes A bis zum Tief des Punktes E, während die B-Zone vom Tief des Punktes B bis zum Hoch des Punktes D reicht. Bei Handelsentscheidungen wie Einstieg, Stopps oder Ziele werden diese Rechtecke wahrscheinlich als visuelle Referenz verwendet, um Reaktionen oder Zusammenflüsse innerhalb bestimmter Regionen zu erkennen. Dank dieser Anzeige können Händler komplizierte Muster, die das Programm automatisch findet, leichter verstehen.
3.2.2. Hervorheben der Musterstruktur mit Dreiecksformen
Das Zeichnen von Dreiecken zur Hervorhebung der Struktur des Musters, insbesondere bei Formationen wie Kopf und Schultern, folgt, nachdem wir alle wichtigen Umkehrpunkte (X, A, B, C, D und E) lokalisiert und beschriftet haben. Ein Muster Kopf-Schultern, bei dem die Linie nicht unter die Nackenlinie fällt, wird visuell durch das XAB-Dreieck dargestellt, das X, A und B miteinander verbindet.
Das BCD-Dreieck, das B, C und D verbindet und die zweite Welle der Struktur betont, ist der nächste Schritt in dieser Methode. Das DEX-Dreieck, das die Form visuell vervollständigt, verbindet D, E und X. Diese Dreiecksformen dienen als visuelle Hilfe und ermöglichen es Händlern, wichtige Wendepunkte und Mustergeometrien schneller zu erkennen, ohne den Chart mit Linien zu überfrachten.
Beispiel:
input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; // MA Time Frame input int bars_check = 1000; // Number of bars to check for swing points input bool show_sell = true; // Display sell signals input bool show_buy = true; // Display buy signals input color txt_clr = clrBlue; // Texts color input color head_clr = clrCornflowerBlue; // Head color input color shoulder_clr = clrLightSeaGreen; // Shoulder color
if(a_b_hh > x_a_ll && b_c_ll < a_b_hh && b_c_ll > x_a_ll && c_d_hh > a_b_hh && E < c_d_hh && d_e_ll > x_a_ll && d_e_ll <= B_high && D_3bar_high >= B_high && E > A_low && E_3bar_low < a_b_hh) { ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); xa = StringFormat("XA line%d", i); ab = StringFormat("AB line%d", i); bc = StringFormat("BC line%d", i); cd = StringFormat("CD line%d", i); de = StringFormat("DE line%d", i); ex = StringFormat("EX line%d", i); ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,x_a_ll_t,x_a_ll); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,a_b_hh_t,a_b_hh); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,b_c_ll_t,b_c_ll); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,c_d_hh_t,c_d_hh); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,d_e_ll_t,d_e_ll); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id, xa,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); ObjectSetInteger(chart_id,xa,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,xa,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, xa, OBJPROP_BACK, true); ObjectCreate(chart_id, ab,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); ObjectSetInteger(chart_id,ab,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ab,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ab, OBJPROP_BACK, true); ObjectCreate(chart_id, bc,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); ObjectSetInteger(chart_id,bc,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,bc,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, bc, OBJPROP_BACK, true); ObjectCreate(chart_id, cd,OBJ_TREND,0,c_d_hh_t,c_d_hh,d_e_ll_t,d_e_ll); ObjectSetInteger(chart_id,cd,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,cd,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, cd, OBJPROP_BACK, true); ObjectCreate(chart_id, de,OBJ_TREND,0,d_e_ll_t,d_e_ll,E_time,E); ObjectSetInteger(chart_id,de,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,de,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, de, OBJPROP_BACK, true); ObjectCreate(chart_id, ex,OBJ_TREND,0,E_time,E,time[n+(z/2)],x_a_ll); ObjectSetInteger(chart_id,ex,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ex,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ex, OBJPROP_BACK, true); A_zone = StringFormat("A ZONEe%d", i); B_zone = StringFormat("B ZONEe%d", i); ObjectCreate(chart_id,A_zone,OBJ_RECTANGLE,0,a_b_hh_t,a_b_hh,E_time,A_low); ObjectCreate(chart_id,B_zone,OBJ_RECTANGLE,0,b_c_ll_t,b_c_ll,d_e_ll_t,B_high); xa_line_t = ObjectGetTimeByValue(chart_id,xa,b_c_ll,0); ex_line_t = ObjectGetTimeByValue(chart_id,ex,d_e_ll,0); X_A_B = StringFormat("XAB %d", i); ObjectCreate(chart_id,X_A_B,OBJ_TRIANGLE,0,xa_line_t,b_c_ll,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); ObjectSetInteger(chart_id, X_A_B, OBJPROP_FILL, true); ObjectSetInteger(chart_id, X_A_B, OBJPROP_BACK, true); ObjectSetInteger(chart_id, X_A_B, OBJPROP_COLOR, shoulder_clr); B_C_D = StringFormat("BCD %d", i); ObjectCreate(chart_id, B_C_D, OBJ_TRIANGLE, 0, b_c_ll_t, b_c_ll, c_d_hh_t, c_d_hh, d_e_ll_t, d_e_ll); ObjectSetInteger(chart_id, B_C_D, OBJPROP_COLOR, head_clr); ObjectSetInteger(chart_id, B_C_D, OBJPROP_FILL, true); ObjectSetInteger(chart_id, B_C_D, OBJPROP_BACK, true); D_E_X = StringFormat("DEX %d", i); ObjectCreate(chart_id, D_E_X, OBJ_TRIANGLE, 0, d_e_ll_t, d_e_ll, E_time, E, ex_line_t, d_e_ll); ObjectSetInteger(chart_id, D_E_X, OBJPROP_COLOR, shoulder_clr); ObjectSetInteger(chart_id, D_E_X, OBJPROP_FILL, true); ObjectSetInteger(chart_id, D_E_X, OBJPROP_BACK, true); }
Ausgabe:
Erläuterung:
Dieser Abschnitt des Codes konzentriert sich auf die Verwendung von Dreiecken und Rechtecken zur grafischen Darstellung von Musterstrukturen, insbesondere XAB, BCD und DEX, auf dem MetaTrader 5 Chart. Um dynamische Namen für die zu erzeugenden Dreiecksobjekte zu erhalten, werden drei String-Variablen - X_A_B, B_C_D und D_E_X - deklariert. Bestimmte Zeitkoordinaten werden mithilfe von zwei Datetime-Variablen (xa_line_t und ex_line_t) abgerufen, um Teile der Dreiecksformen an den entsprechenden Stellen im Chart zu verankern.
Um das Verständnis des Händlers zu verbessern, beginnt der Code mit der Einrichtung zweier rechteckiger Bereiche, die „A ZONE“ und „B ZONE“ genannt werden. Diese Rechtecke, die wichtige Bereiche der Preisstruktur hervorheben, werden mit ObjectCreate() erstellt. Die A-Zone erstreckt sich bis zum Punkt E, vom Hoch zwischen den Punkten A und B (a_b_hh) bis zum Tief bei Punkt A (A_low). In ähnlicher Weise erstreckt sich die B-Zone von der tiefsten Position (b_c_ll) zwischen den Punkten B und C bis zum höchsten Punkt (B_high) und endet an der Zeitkoordinate des Schenkels D nach E.
Im folgenden Abschnitt wird ObjectGetTimeByValue() aufgerufen, um die Zeitkoordinaten zu bestimmen, die zur Verankerung von Teilen der XAB- und DEX-Dreiecke erforderlich sind. Diese Funktion stellt sicher, dass die visuellen Markierungen den Preisniveaus entsprechen, die sie hervorheben sollen, indem sie nach einem bestimmten Preiswert entlang des Weges eines Objekts sucht und die entsprechende Zeit zurückgibt.
Dann wird jedes Dreieck als Muster separater Schenkel dargestellt. Obwohl das XAB-Dreieck nicht den gesamten Schenkel verbindet, zeigt es die erste Umkehrpunktstruktur an. Um visuelle Unordnung zu vermeiden und sich auf die Struktur zu konzentrieren, wird die Aufmerksamkeit nur auf die wichtigen Wendepunkte gelenkt, die Schultern ähneln. Ähnlich verhält es sich mit dem BCD-Dreieck, das einen Tiefpunkt (B), einen Höchststand (C) und ein Retracement (D) miteinander verbindet und den Hauptkopf des Musters hervorhebt. Das DEX-Dreieck, das den Rückschwung darstellt, der die ursprüngliche Schulter widerspiegelt, vervollständigt schließlich den Rahmen.
Eigenschaften wie OBJPROP_FILL und OBJPROP_BACK werden verwendet, um alle drei Dreiecke mit Farbe zu füllen und sie hinter anderen Chartelementen zu platzieren. Händler können das Muster aufgrund der verwendeten Farben, die in Variablen wie shoulder_clr und head_clr enthalten sind, leichter auf einen Blick erkennen. Um viele Instanzen dieser Muster in ein und demselben Chart behandeln und erkennen zu können, wird der Index i in die Benennung der einzelnen Elemente aufgenommen.
3.2.3. Angabe von Einstiegspunkt, Stop-Loss und Take-Profit
In der nächsten Phase werden die Handelsparameter festgelegt, darunter der Einstiegspunkt, der Stop-Loss (SL) und der Take-Profit (TP), nachdem die XAB-, BCD- und DEX-Strukturen mit Dreiecken markiert wurden, wobei die Kopf-Schultern-Form betont wird. Diese Komponenten sind notwendig, um das erkannte Muster in eine umfassende Handelsstrategie zu verwandeln. Wenn eine Kerze unter dem Punkt D schließt, ist der Einstieg erfolgt. Dies deutet darauf hin, dass der Kurs die Nackenlinie abgelehnt haben könnte und sich in die vom Muster vorhergesagte Richtung bewegt. Der Handel wird nun als den Regeln gemäß angesehen, und die Ausführung ist möglich.
Knapp über Punkt E wird der Stop-Loss gesetzt. Die Platzierung der SL an dieser Stelle trägt dazu bei, den Handel abzusichern, falls das Muster scheitert und der Kurs unerwartet umkehrt, da E das letztehoher Umkehrpunkt ist, bevor das Muster abgeschlossen wird. Außerdem wird das Setup vernünftig gehalten, indem der Handel nur dann für ungültig erklärt wird, wenn das Muster verletzt wird. Da der Punkt X, der Ausgangspunkt des Musters, ein zuverlässiges Referenzniveau ist, auf dem der Kurs zuvor eine Umkehr vollzogen hat, wird der Take-Profit ursprünglich dort platziert. Der TP wird jedoch weiter gestreckt, um ein Minimum von 1:2 zu erreichen, wenn der Abstand vom Einstieg bis X kein Risiko-Ertrags-Verhältnis (RRR) von mindestens 1:1 ergibt. Ein Schlüsselelement jeder nachhaltigen Handelsstrategie ist es, sicherzustellen, dass der Handel ein günstiges Ertragspotenzial im Verhältnis zum riskierten Betrag aufweist.
Beispiel:int n_bars; int n_bars_2; string sl_t; string tp_t; double sl_price; double tp_price;
for(int o = n; o < rates_total - 1; o++) { if(close[o] < d_e_ll && time[o] >= time[n+(z/2)]) { n_bars = Bars(_Symbol,PERIOD_CURRENT,x_a_ll_t, E_time); n_bars_2 = Bars(_Symbol,PERIOD_CURRENT,time[n+(z/2)], time[o]); if(n_bars_2 <= n_bars) { double sl_zone = MathAbs(E - close[o]); double tp_zone = MathAbs(close[o] - x_a_ll); bool no_cross = false; for(int p = n + (z/2); p < o; p++) { if(close[p] < d_e_ll) { no_cross = true; break; } } if(no_cross == false) { if(tp_zone >= sl_zone) { string loss_zone = StringFormat("Loss %d", i); ObjectCreate(chart_id,loss_zone,OBJ_RECTANGLE,0,E_time,E,time[o],close[o]); ObjectSetInteger(chart_id, loss_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_COLOR, lz_clr); string sell_object = StringFormat("Sell Object%d", i); ObjectCreate(chart_id,sell_object,OBJ_ARROW_SELL,0,time[o],close[o]); string win_zone = StringFormat("Win %d", i); ObjectCreate(chart_id,win_zone,OBJ_RECTANGLE,0,E_time,close[o],time[o],x_a_ll); ObjectSetInteger(chart_id, win_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_COLOR, wz_clr); sl_price = E; tp_price = x_a_ll; string sl_d_s = DoubleToString(sl_price,_Digits); string tp_d_s = DoubleToString(tp_price,_Digits); sl_t = StringFormat("sl %d", i); tp_t = StringFormat("tp %d", i); ObjectCreate(chart_id,sl_t,OBJ_TEXT,0,time[o],sl_price); ObjectSetString(chart_id,sl_t,OBJPROP_TEXT,"SL - " + sl_d_s); ObjectSetInteger(chart_id,sl_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,sl_t,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,tp_t,OBJ_TEXT,0,time[o],x_a_ll); ObjectSetString(chart_id,tp_t,OBJPROP_TEXT,"TP - " + tp_d_s); ObjectSetInteger(chart_id,tp_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,tp_t,OBJPROP_COLOR,txt_clr); } if(tp_zone < sl_zone) { string loss_zone = StringFormat("Loss %d", i); ObjectCreate(chart_id,loss_zone,OBJ_RECTANGLE,0,E_time,E,time[o],close[o]); ObjectSetInteger(chart_id, loss_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_COLOR, lz_clr); string sell_object = StringFormat("Sell Object%d", i); ObjectCreate(chart_id,sell_object,OBJ_ARROW_SELL,0,time[o],close[o]); double n_tp = MathAbs(close[o] - (sl_zone * 2)); string win_zone = StringFormat("Win %d", i); ObjectCreate(chart_id,win_zone,OBJ_RECTANGLE,0,E_time,close[o],time[o],n_tp); ObjectSetInteger(chart_id, win_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_COLOR, wz_clr); sl_price = E; tp_price = n_tp; string sl_d_s = DoubleToString(sl_price,_Digits); string tp_d_s = DoubleToString(tp_price,_Digits); sl_t = StringFormat("sl %d", i); tp_t = StringFormat("tp %d", i); ObjectCreate(chart_id,sl_t,OBJ_TEXT,0,time[o],sl_price);; ObjectSetString(chart_id,sl_t,OBJPROP_TEXT,"SL - " + sl_d_s); ObjectSetInteger(chart_id,sl_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,sl_t,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,tp_t,OBJ_TEXT,0,time[o],tp_price); ObjectSetString(chart_id,tp_t,OBJPROP_TEXT,"TP - " + tp_d_s); ObjectSetInteger(chart_id,tp_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,tp_t,OBJPROP_COLOR,txt_clr); } } } break; } }
Ausgabe:
Erläuterung:
Die Logik in diesem Bereich des Codes konzentriert sich auf die Bestimmung einer legitimen Handelseinstellung unter Verwendung der Kopf-Schultern-Struktur, die zuvor hervorgehoben wurde. Anschließend werden grafische Objekte verwendet, um die Einstiegsposition, den Stop Loss (SL) und den Take Profit (TP) auf dem Chart grafisch darzustellen. Die Anzahl der Kerzen zwischen signifikanten Punkten wird berechnet und mit zwei ganzzahligen Variablen, n_bars und n_bars_2, verglichen. Auf diese Weise lässt sich feststellen, ob der aktuelle Kursverlauf noch innerhalb des akzeptablen Fensters für das Setup liegt. Während sl_price und tp_price die jeweiligen Preisniveaus speichern, werden die Zeichenketten sl_t und tp_t zur dynamischen Benennung der Textobjekte SL und TP verwendet.
Ab dem Abschlusspunkt (n) des Musters beginnt die Hauptlogik in einer Schleife, die die Balken durchläuft. Eine Kerze, die unterhalb der Nackenlinie (Punkt D) schließt und einen möglichen Einstieg anzeigt, wird durch die Bedingung if (close[o] < d_e_ll && time[o] >= time[n+(z/2)]) gesucht. Ist diese Bedingung erfüllt, wird die Anzahl der Balken zwischen den Punkten X und E (n_bars) und zwischen dem Mittelpunkt des Musters und der aktuellen Kerze (n_bars_2) bestimmt. Auf diese Weise ist gewährleistet, dass der Handel innerhalb eines angemessenen Zeitraums gültig ist.
Der Code vergleicht dann den Einstiegskurs mit den Punkten E bzw. X, um die Höhe des möglichen Stop-Loss (sl_zone) und des Take-Profits (tp_zone) zu bestimmen. Um auszuschließen, dass es sich bei diesem Eintrag um den ersten Ausbruch handelt, wird zusätzlich eine Schleife durchgeführt, um sicherzustellen, dass keine frühere Kerze vor der jetzigen unter Punkt D geschlossen hat. Das Skript wird fortgesetzt, wenn diese Prüfung erfolgreich ist.
Um die Stop-Loss- und Take-Profit-Zonen auf dem Chart visuell darzustellen, verwendet der Code OBJ_RECTANGLE, um grafische Rechtecke zu erzeugen, wenn der potenzielle Gewinn (TP) größer oder gleich dem Risiko (SL) ist. Außerdem befindet sich in der Nähe des Eingangs ein Verkaufspfeil (OBJ_ARROW_SELL). Die Variablen sl_price und tp_price enthalten die tatsächlichen SL- und TP-Kurswerte. Die Beschriftungen werden mit OBJ_TEXT erstellt, um diese Ebenen auf dem Chart durch die Wahl von Farbe und Schriftart hervorzuheben. Um ein günstigeres RRR von mindestens 1:2 zu erreichen, berechnet das Skript eine neue TP-Zone, die dreimal so groß ist wie der SL-Abstand, wenn das Risiko-Ertrags-Verhältnis weniger als 1:1 beträgt (d. h. TP ist kleiner als SL). Dann werden für diese alternative Konfiguration die gleichen grafischen Objekte erstellt und geändert.
4. Ausführen von Handelsgeschäften auf der Grundlage des Musters
Unser Ziel in diesem Teil ist es, mehr zu tun, als nur Handelssituationen zu erkennen und darzustellen. In diesem Abschnitt geht es darum, den Handel auf der Grundlage des identifizierten Musters tatsächlich durchzuführen, während sich der vorherige Teil auf die Markierung der Einstiegs-, Stop-Loss- (SL) und Take-Profit-Niveaus (TP) auf dem Chart konzentrierte. Der EA sollte automatisch ein Handelsgeschäft einleiten, wenn die Voraussetzungen erfüllt sind, z. B. wenn der Preis unter Punkt D für einen Verkauf schließt. Der Take-Profit sollte auf den Punkt X gesetzt oder für ein Risiko-Ertrags-Verhältnis von mindestens 1:2 modifiziert werden, und der Stop-Loss sollte auf den Punkt E gesetzt werden. Durch diesen Schritt wird der EA von einem visuellen Tool in ein vollständig automatisiertes System umgewandelt, das Trades ohne die Notwendigkeit menschlicher Beteiligung eingeben und verwalten kann.
Beispiel:
#include <Trade/Trade.mqh> CTrade trade; int MagicNumber = 5122025; datetime lastTradeBarTime = 0; double ask_price; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- trade.SetExpertMagicNumber(MagicNumber); //--- return(INIT_SUCCEEDED); }
ask_price = ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); datetime currentBarTime = iTime(_Symbol, timeframe, 0); //FOR SELL if(show_sell) { if(rates_total >= bars_check) { for(int z = 7; z <= 10; z++) { for(int i = rates_total - bars_check; i < rates_total - z; i++) { if(IsSwingLow(low, i, z)) { // If a swing low is found, store its price, time, and create a name for the objects to mark the X. X = low[i]; // Price of the swing low (X). X_time = time[i]; // Time of the swing low (X). X_letter = StringFormat("X%d", i); // Unique name for the text label object. for(int j = i; j < rates_total - z; j++) { if(IsSwingHigh(high, j, z) && time[j] > X_time) { A = high[j]; // Price of the swing high (A). A_time = time[j]; // Time of the swing high (A) A_letter = StringFormat("A%d", j); // Unique name for the text label object for(int k = j; k < rates_total - z; k++) { if(IsSwingLow(low, k, z) && time[k] > A_time) { B = low[k]; // Price of the swing low (B). B_time = time[k]; // Time of the swing low (B). B_letter = StringFormat("B%d", k); // Unique name for the text label object. for(int l = k ; l < rates_total - z; l++) { if(IsSwingHigh(high, l, z) && time[l] > B_time) { C = high[l]; // Price of the swing high (C). C_time = time[l]; // Time of the swing high (C). C_letter = StringFormat("C%d", l); // Unique name for the text label object. for(int m = l; m < rates_total - z; m++) { if(IsSwingLow(low, m, z) && time[m] > C_time) { D = low[m]; // Price of the swing low (D). D_time = time[m]; // Time of the swing low (D). D_letter = StringFormat("D%d", m); // Unique name for the text label object. for(int n = m ; n < rates_total - (z/2) - 1; n++) { if(IsSwingHigh(high, n, (z/2)) && time[n] > D_time) { E = high[n]; // Price of the swing high (E). E_time = time[n]; // Time of the swing high (E). E_letter = StringFormat("E%d", n); // Unique name for the text label object. d_e_bars = Bars(_Symbol, PERIOD_CURRENT, D_time, E_time); // Count the number of bars between D and E d_lowest_index = ArrayMinimum(low, m, d_e_bars); // Find the index of the lowest low in the range d_e_ll = low[d_lowest_index]; // Store the lowest low (D - E lowest point) d_e_ll_t = time[d_lowest_index]; // Store the corresponding time D_3bar_high = high[d_lowest_index - 3]; // The high price of the third bar before the bar that formed D c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time,d_e_ll_t); // Count the number of bars between C and V c_highest_index = ArrayMaximum(high,l,c_d_bars); // Find the index of the highest high in the range c_d_hh = high[c_highest_index]; // Store the lowest high (C - D lowest point) c_d_hh_t = time[c_highest_index]; // Store the corresponding time b_c_bars = Bars(_Symbol, PERIOD_CURRENT, B_time, c_d_hh_t); // Count the number of bars between B and C b_lowest_index = ArrayMinimum(low, k, b_c_bars); // Find the index of the lowest low in the range b_c_ll = low[b_lowest_index]; // Store the lowest low B - C lowest point) b_c_ll_t = time[b_lowest_index]; // Store the corresponding time B_high = high[b_lowest_index]; // The high price of the bar that formed swing low D a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time,b_c_ll_t); // Count the number of bars between A and B a_highest_index = ArrayMaximum(high,j,a_b_bars); // Find the index of the highest high in the range a_b_hh = high[a_highest_index]; // Store the lowest low A - B lowest point) a_b_hh_t = time[a_highest_index]; // Store the corresponding time A_low = low[a_highest_index]; x_a_bars = Bars(_Symbol, PERIOD_CURRENT, X_time, a_b_hh_t); // Count the number of bars between C and D x_lowest_index = ArrayMinimum(low, i, x_a_bars); // Find the index of the lowest low in the range x_a_ll = low[x_lowest_index]; // Store the lowest low (C - D lowest point) x_a_ll_t = time[x_lowest_index]; // Store the corresponding time for C - D E_3bar_low = low[n - 3]; // The LOW price of the third bar before the bar that formed E if(a_b_hh > x_a_ll && b_c_ll < a_b_hh && b_c_ll > x_a_ll && c_d_hh > a_b_hh && E < c_d_hh && d_e_ll > x_a_ll && d_e_ll <= B_high && D_3bar_high >= B_high && E > A_low && E_3bar_low < a_b_hh) { ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,X_time,X); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,A_time,A); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,B_time,B); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,C_time,C); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,D_time,D); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); xa = StringFormat("XA line%d", i); ab = StringFormat("AB line%d", i); bc = StringFormat("BC line%d", i); cd = StringFormat("CD line%d", i); de = StringFormat("DE line%d", i); ex = StringFormat("EX line%d", i); ObjectCreate(chart_id,X_letter,OBJ_TEXT,0,x_a_ll_t,x_a_ll); ObjectSetString(chart_id,X_letter,OBJPROP_TEXT,"X"); ObjectSetInteger(chart_id,X_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,A_letter,OBJ_TEXT,0,a_b_hh_t,a_b_hh); ObjectSetString(chart_id,A_letter,OBJPROP_TEXT,"A"); ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,B_letter,OBJ_TEXT,0,b_c_ll_t,b_c_ll); ObjectSetString(chart_id,B_letter,OBJPROP_TEXT,"B"); ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,C_letter,OBJ_TEXT,0,c_d_hh_t,c_d_hh); ObjectSetString(chart_id,C_letter,OBJPROP_TEXT,"C"); ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,D_letter,OBJ_TEXT,0,d_e_ll_t,d_e_ll); ObjectSetString(chart_id,D_letter,OBJPROP_TEXT,"D"); ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,E_letter,OBJ_TEXT,0,E_time,E); ObjectSetString(chart_id,E_letter,OBJPROP_TEXT,"E"); ObjectSetInteger(chart_id,E_letter,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id, xa,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); ObjectSetInteger(chart_id,xa,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,xa,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, xa, OBJPROP_BACK, true); ObjectCreate(chart_id, ab,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); ObjectSetInteger(chart_id,ab,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ab,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ab, OBJPROP_BACK, true); ObjectCreate(chart_id, bc,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); ObjectSetInteger(chart_id,bc,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,bc,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, bc, OBJPROP_BACK, true); ObjectCreate(chart_id, cd,OBJ_TREND,0,c_d_hh_t,c_d_hh,d_e_ll_t,d_e_ll); ObjectSetInteger(chart_id,cd,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,cd,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, cd, OBJPROP_BACK, true); ObjectCreate(chart_id, de,OBJ_TREND,0,d_e_ll_t,d_e_ll,E_time,E); ObjectSetInteger(chart_id,de,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,de,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, de, OBJPROP_BACK, true); ObjectCreate(chart_id, ex,OBJ_TREND,0,E_time,E,time[n+(z/2)],x_a_ll); ObjectSetInteger(chart_id,ex,OBJPROP_WIDTH,3); ObjectSetInteger(chart_id,ex,OBJPROP_COLOR,clrSaddleBrown); ObjectSetInteger(chart_id, ex, OBJPROP_BACK, true); A_zone = StringFormat("A ZONEe%d", i); B_zone = StringFormat("B ZONEe%d", i); ObjectCreate(chart_id,A_zone,OBJ_RECTANGLE,0,a_b_hh_t,a_b_hh,E_time,A_low); ObjectCreate(chart_id,B_zone,OBJ_RECTANGLE,0,b_c_ll_t,b_c_ll,d_e_ll_t,B_high); xa_line_t = ObjectGetTimeByValue(chart_id,xa,b_c_ll,0); ex_line_t = ObjectGetTimeByValue(chart_id,ex,d_e_ll,0); X_A_B = StringFormat("XAB %d", i); ObjectCreate(chart_id,X_A_B,OBJ_TRIANGLE,0,xa_line_t,b_c_ll,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); ObjectSetInteger(chart_id, X_A_B, OBJPROP_FILL, true); ObjectSetInteger(chart_id, X_A_B, OBJPROP_BACK, true); ObjectSetInteger(chart_id, X_A_B, OBJPROP_COLOR, shoulder_clr); B_C_D = StringFormat("BCD %d", i); ObjectCreate(chart_id, B_C_D, OBJ_TRIANGLE, 0, b_c_ll_t, b_c_ll, c_d_hh_t, c_d_hh, d_e_ll_t, d_e_ll); ObjectSetInteger(chart_id, B_C_D, OBJPROP_COLOR, head_clr); ObjectSetInteger(chart_id, B_C_D, OBJPROP_FILL, true); ObjectSetInteger(chart_id, B_C_D, OBJPROP_BACK, true); D_E_X = StringFormat("DEX %d", i); ObjectCreate(chart_id, D_E_X, OBJ_TRIANGLE, 0, d_e_ll_t, d_e_ll, E_time, E, ex_line_t, d_e_ll); ObjectSetInteger(chart_id, D_E_X, OBJPROP_COLOR, shoulder_clr); ObjectSetInteger(chart_id, D_E_X, OBJPROP_FILL, true); ObjectSetInteger(chart_id, D_E_X, OBJPROP_BACK, true); for(int o = n; o < rates_total - 1; o++) { if(close[o] < d_e_ll && time[o] >= time[n+(z/2)]) { n_bars = Bars(_Symbol,PERIOD_CURRENT,x_a_ll_t, E_time); n_bars_2 = Bars(_Symbol,PERIOD_CURRENT,time[n+(z/2)], time[o]); if(n_bars_2 <= n_bars) { double sl_zone = MathAbs(E - close[o]); double tp_zone = MathAbs(close[o] - x_a_ll); bool no_cross = false; for(int p = n + (z/2); p < o; p++) { if(close[p] < d_e_ll) { no_cross = true; break; } } if(no_cross == false) { if(tp_zone >= sl_zone) { string loss_zone = StringFormat("Loss %d", i); ObjectCreate(chart_id,loss_zone,OBJ_RECTANGLE,0,E_time,E,time[o],close[o]); ObjectSetInteger(chart_id, loss_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_COLOR, lz_clr); string sell_object = StringFormat("Sell Object%d", i); ObjectCreate(chart_id,sell_object,OBJ_ARROW_SELL,0,time[o],close[o]); string win_zone = StringFormat("Win %d", i); ObjectCreate(chart_id,win_zone,OBJ_RECTANGLE,0,E_time,close[o],time[o],x_a_ll); ObjectSetInteger(chart_id, win_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_COLOR, wz_clr); sl_price = E; tp_price = x_a_ll; string sl_d_s = DoubleToString(sl_price,_Digits); string tp_d_s = DoubleToString(tp_price,_Digits); sl_t = StringFormat("sl %d", i); tp_t = StringFormat("tp %d", i); ObjectCreate(chart_id,sl_t,OBJ_TEXT,0,time[o],sl_price); ObjectSetString(chart_id,sl_t,OBJPROP_TEXT,"SL - " + sl_d_s); ObjectSetInteger(chart_id,sl_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,sl_t,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,tp_t,OBJ_TEXT,0,time[o],x_a_ll); ObjectSetString(chart_id,tp_t,OBJPROP_TEXT,"TP - " + tp_d_s); ObjectSetInteger(chart_id,tp_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,tp_t,OBJPROP_COLOR,txt_clr); } if(tp_zone < sl_zone) { string loss_zone = StringFormat("Loss %d", i); ObjectCreate(chart_id,loss_zone,OBJ_RECTANGLE,0,E_time,E,time[o],close[o]); ObjectSetInteger(chart_id, loss_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, loss_zone, OBJPROP_COLOR, lz_clr); string sell_object = StringFormat("Sell Object%d", i); ObjectCreate(chart_id,sell_object,OBJ_ARROW_SELL,0,time[o],close[o]); double n_tp = MathAbs(close[o] - (sl_zone * 3)); string win_zone = StringFormat("Win %d", i); ObjectCreate(chart_id,win_zone,OBJ_RECTANGLE,0,E_time,close[o],time[o],n_tp); ObjectSetInteger(chart_id, win_zone, OBJPROP_FILL, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_BACK, true); ObjectSetInteger(chart_id, win_zone, OBJPROP_COLOR, wz_clr); sl_price = E; tp_price = n_tp; string sl_d_s = DoubleToString(sl_price,_Digits); string tp_d_s = DoubleToString(tp_price,_Digits); sl_t = StringFormat("sl %d", i); tp_t = StringFormat("tp %d", i); ObjectCreate(chart_id,sl_t,OBJ_TEXT,0,time[o],sl_price);; ObjectSetString(chart_id,sl_t,OBJPROP_TEXT,"SL - " + sl_d_s); ObjectSetInteger(chart_id,sl_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,sl_t,OBJPROP_COLOR,txt_clr); ObjectCreate(chart_id,tp_t,OBJ_TEXT,0,time[o],tp_price); ObjectSetString(chart_id,tp_t,OBJPROP_TEXT,"TP - " + tp_d_s); ObjectSetInteger(chart_id,tp_t,OBJPROP_FONTSIZE,8); ObjectSetInteger(chart_id,tp_t,OBJPROP_COLOR,txt_clr); } if(time[o] == time[rates_total-2] && currentBarTime != lastTradeBarTime) { trade.Sell(lot_size,_Symbol,ask_price, sl_price,tp_price); lastTradeBarTime = currentBarTime; } } } break; } } } break; } } break; } } break; } } break; } } break; } } } } } } }
Ausgabe:
Erläuterung:
Dieser Codeblock verwaltet die Handelsausführung mithilfe der in MQL5 integrierten Klasse CTrade, die Handelsaufgaben wie das Platzieren, Bearbeiten und Schließen von Aufträgen rationalisiert. Die Handelsbibliothek, die den Zugriff auf die Klasse CTrade ermöglicht, wird am Anfang mit #include <Trade/Trade.mqh> eingebunden. Als Nächstes wird eine Instanz dieser Klasse mit CTrade trade; erstellt, und int MagicNumber = 5122025; wird verwendet, um eine eindeutige Identifikation für die von diesem Expert Advisor (EA) getätigten Trades zu definieren. Die MagicNumber ist von entscheidender Bedeutung, da sie dabei hilft, die von diesem EA getätigten Trades von denen zu unterscheiden, die manuell oder von anderen EAs getätigt wurden. Trade wird verwendet, um seine MagicNumber zu setzen; SetExpertMagicNumber;.
SymbolInfoDouble(_Symbol, SYMBOL_ASK); wird verwendet, um die Variable ask_price mit dem aktuellen Briefkurs des Symbols zu initialisieren. Ein Verkaufsauftrag würde zu diesem Preis ausgeführt werden. Der Code verwendet dann time[o] == time[rates_total-2], um festzustellen, ob der aktuelle Balken der jüngste ist. Zusätzlich wird die Bedingung currentBarTime!= lastTradeBarTime verwendet, um zu bestätigen, dass auf dem aktuellen Balken noch kein Handel stattgefunden hat. Dank dieser Prüfung kann der EA nicht mehr als einen Auftrag zum selben Balken erteilen.
Der EA verwendet die Transaktion, um einen Verkaufsauftrag zu erteilen, wenn beide Voraussetzungen erfüllt sind. Die Funktion sell(). Ask_price ist der Einstiegskurs, sl_price ist das Stop-Loss-Niveau, tp_price ist das Take-Profit-Niveau, lot_size ist die Anzahl der zu handelnden Lots und _Symbol ist das aktuelle Handelssymbol (z. B. EURUSD). Der EA fügt den Wert von currentBarTime zur Variable lastTradeBarTime hinzu, nachdem die Transaktion erfolgreich platziert wurde. Dieses Update ist wichtig, da es sicherstellt, dass nur ein Handel pro legitimer Musterindikation durchgeführt wird, indem es den EA daran hindert, mehrere Transaktionen auf der Grundlage desselben Balkens durchzuführen.
Es ist wichtig, sich daran zu erinnern, dass die gleiche Argumentation, die verwendet wird, um ein Verkaufs-Setup zu identifizieren und anzuzeigen, auch verwendet werden kann, um ein Kauf-Setup zu identifizieren und anzuzeigen, indem man in jeder Phase einfach die umgekehrte Vorgehensweise durchführt. Die Kaufstrategie würde darauf warten, dass eine Kerze über der Nackenlinie (Punkt D) und nicht darunter schließt. Danach würde der Take-Profit am höchsten Punkt (X) und der Stop-Loss am niedrigsten Punkt (E) positioniert werden. Das Verhältnis von Risiko zu Rendite, die visuellen Anhaltspunkte und die Bedingungen sind dieselben, sie werden lediglich für eine Aufwärtsstruktur gespiegelt. Der Quellcode, der dem Beitrag beiliegt, wird diese Logik für jeden, der sie weiter untersuchen oder verändern möchte, vollständig implementieren.
Schlussfolgerung
In diesem Artikel haben wir untersucht, wie man einen Expert Advisor (EA) in MQL5 erstellt, der technische Chart-Muster - insbesondere das Head and Shoulders-Muster - identifiziert und darauf basierend handelt. Wir begannen mit der Erkennung und Markierung wichtiger Umkehrpunkte und verwendeten dann grafische Hilfsmittel wie Dreiecke und Rechtecke, um die XAB-, BCD- und DEX-Strukturen visuell darzustellen. Anschließend legten wir klare Handelsparameter fest, einschließlich des Einstiegspunkts, des Stop-Loss- und des Take-Profit-Niveaus, und stellten sicher, dass das Risiko-Ertrags-Verhältnis logischen Standards entsprach. Schließlich haben wir eine Handelsausführungslogik implementiert, die echte Aufträge auf der Grundlage bestätigter Signale platziert, wodurch der EA vollständig automatisiert wird.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18147
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.





- 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.
Danke, das ist der Grund, warum ich Ihre Artikel immer mit Spannung erwarte. Sehr erklärend!
Du bist großartig, Israel! Ich übersetze deine Artikel regelmäßig ins Spanische, und es ist immer ein Vergnügen, daran zu arbeiten.
Mach weiter so mit deiner fantastischen Arbeit! ❤️
Du bist großartig, Israel! Ich übersetze Ihre Artikel regelmäßig ins Spanische, und es ist immer eine wahre Freude, daran zu arbeiten.
Machen Sie weiter so! ❤️
Hallo, Miguel.
Vielen Dank für deine netten Worte, das bedeutet mir sehr viel ❤️
Ich bin kein Programmierer, also hat es eine Weile gedauert, bis ich das verstanden habe, aber die Art und Weise, wie es aufgeschlüsselt wurde, und der schrittweise Prozess haben mir Motivation gegeben. 💯
Hallo Daniels.
Schön, das von dir zu hören! ❤️