Einführung in MQL5 (Teil 26): Aufbau eines EAs mit Hilfe von Unterstützungs- und Widerstandszonen
Einführung
Willkommen zurück zu Teil 26 der Serie Einführung in MQL5! In diesem Artikel werden wir uns auf Unterstützungs- und Widerstandszonen konzentrieren, die zu den grundlegendsten Ideen der technischen Analyse gehören, und untersuchen, wie man einen EA erstellt, der auf der Grundlage dieser entscheidenden Kursniveaus handelt. Wichtige Handelsentscheidungen werden von Marktteilnehmern häufig an psychologischen Barrieren getroffen, die als Unterstützungs- und Widerstandszonen bekannt sind. Der Widerstand zeigt ein Niveau an, bei dem der Verkaufsdruck stark genug ist, um eine Aufwärtsbewegung zu stoppen, während die Unterstützung ein Niveau anzeigt, bei dem der Kaufdruck dazu neigt, den Verkaufsdruck zu überwinden und die Preise wieder ansteigen zu lassen.
In Teil 24 dieser Serie haben wir uns angeschaut, wie man manuell Unterstützungs- und Widerstandszonen mit Hilfe des Rechteck-Chartobjekts einrichten kann. So können Sie ein halbautomatisches Handelssystem erstellen, das auf die von Ihnen gezeichneten Zonen reagiert. Was aber, wenn Sie möchten, dass der EA automatisch, ohne menschliche Hilfe, jede Unterstützungs- und Widerstandszone auf dem Chart erkennt? In diesem Artikel wird speziell darauf eingegangen. Wie üblich werden wir die MQL5-Prinzipien in einer praktischen, einsteigerfreundlichen Weise mit einem projektbasierten Ansatz behandeln. Sie erfahren, wie Sie diese Zonen programmatisch identifizieren, die sie umgebenden Kursbewegungen verfolgen und einen EA erstellen können, der sinnvoll auf mögliche Umkehrungen reagiert.
Wie der EA funktioniert
In diesem Projekt erstellen wir einen EA, der automatisch nach Unterstützungs- und Widerstandszonen innerhalb einer bestimmten Anzahl von Balken sucht. Anstatt sich auf manuell eingezeichnete Zonen zu verlassen, analysiert der EA die jüngsten Kursbewegungen, um Bereiche zu erkennen, in denen der Markt wiederholt reagiert hat, indem er entweder nach oben abprallte (Unterstützung) oder nach unten umkehrte (Widerstand).
Unterstützung
Um jeden tiefen Umkehrpunkt zu finden, durchläuft der EA zunächst die angegebene Anzahl von Balken. Ein tiefer Umkehrpunkt ist eine Kerze, die ein kurzes Tief in der Kursbewegung anzeigt, wenn ihr Tiefstpreis niedriger ist als die der Kerzen, die direkt davor und danach kommen.
Nach der Identifizierung eines tiefen Umkehrpunkts ermittelt der EA den Tiefstwert zwischen dem Eröffnungs- und dem Schlusskurs der Kerze sowie den exakten Tiefstkurs der Kerze, die ihn erzeugt hat. Die mögliche Unterstützungszone wird durch diese beiden Werte definiert, obwohl dies noch nicht verifiziert wurde. Nach diesem tiefen Umkehrpunkt prüft der EA, ob sich in derselben Zone ein weiteres tiefer Umkehrpunkt gebildet hat. Das Minimum zwischen dem Eröffnungs- und dem Schlusskurs der Kerze, die den ersten tiefen Umkehrpunkt erzeugt hat, muss größer sein als der tiefe Umkehrpunkt. Diese Wiederholung deutet darauf hin, dass der Markt die Region erneut unter die Lupe genommen hat und ihre Bedeutung zunimmt.
Nachdem der EA diese Unterstützungszone identifiziert hat, bestätigt er, dass keine Kerze diese Zone unterschritten hat. Die Zone gilt als unzulässig und wird nicht berücksichtigt, wenn eine Kerze unterhalb der Zone schließt. Der EA wechselt zu einem niedrigeren Zeitrahmen, um nach einer Aufwärtsveränderung Ausschau zu halten, wenn sich die Zone stabilisiert hat. Wenn eine solche Strukturveränderung festgestellt wird, die darauf hindeutet, dass der Markt von Käufern übernommen wird und die Unterstützungszone stabil geblieben ist, wird ein Kaufgeschäft eingeleitet.

Widerstand
Um jeden hohen Umkehrpunkt zu finden, durchläuft der EA zunächst die gewählte Anzahl von Balken. Ein hoher Umkehrpunkt ist eine Kerze, die ein kurzes Hoch in der Kursbewegung anzeigt, wenn ihr Hoch höher ist als das der Kerzen, die direkt davor und danach kommen.
Sobald ein hoher Umkehrpunkt identifiziert wurde, protokolliert der EA den Höchstkurs der Kerze sowie das Maximum von Eröffnungs- und Schlusskurs. Obwohl es noch nicht verifiziert wurde, zeigen diese Zahlen die mögliche Widerstandszone an. Um festzustellen, ob sich innerhalb derselben Zone ein weiterer hoher Umkehrpunkt entwickelt hat, schaut der EA dann vom Zeitpunkt des Umkehrpunkts aus nach vorne. Der Abstand zwischen dem Eröffnungs- und dem Schlusskurs der Kerze, die der erste hohe Umkehrpunkt verursacht hat, muss kleiner sein als der zweite hohe Umkehrpunkt. Die wiederholte Ablehnung auf demselben Niveau deutet auf einen starken Verkaufsdruck hin, der das Potenzial dieses Bereichs als Barriere bestätigt.
Der EA prüft dann, ob keine Kerze über die angegebene Widerstandszone gebrochen ist. Die Zone gilt als ungültig und wird nicht beachtet, wenn eine Kerze oberhalb der Zone schließt. Der EA wechselt zu einem niedrigeren Zeitrahmen, um nach einer Abwärtsveränderung des Charakters Ausschau zu halten, sobald die Zone noch gültig ist. Der EA leitet ein Verkauf ein, wenn diese fallende Strukturverschiebung eintritt, da sie anzeigt, dass die Verkäufer die Kontrolle über dieses Widerstandsniveau zurückerlangen.

Erkennen der ersten tiefen Umkehrpunkts
Die Suche nach der Unterstützungszone wird unser nächster Schritt sein, da wir nun ein besseres Verständnis des Projekts haben. Der erste Schritt in diesem Prozess besteht darin, mehrere wichtige Tiefs auf dem Chart zu finden. Diese tiefen Umkehrpunkte weisen auf mögliche Regionen hin, in denen Kaufdruck herrschen könnte, da sie die Punkte anzeigen, an denen der Markt seine Abwärtsbewegung kurzzeitig stoppte und wieder nach oben drehte. Der EA ist in der Lage, mögliche Unterstützungszonen zu erkennen, die anschließend als Einstiegspunkte für Aufwärtssetups dienen könnten, indem er diese tiefen Umkehrpunkte erkennt.
Zunächst müssen wir die entsprechenden Kerzendaten duplizieren. Als Nächstes legen wir fest, nach wie vielen Balken der EA suchen soll, um potenzielle Unterstützungs- und Widerstandszonen zu identifizieren. Anschließend wird eine Funktion entwickelt, die die Höchst- und Tiefststände innerhalb des ausgewählten Bereichs ermittelt. Dieses Merkmal dient als Grundlage für das Aufspüren wichtiger Kurswendepunkte, die erforderlich sind, um vertrauenswürdige Unterstützungs- und Widerstandsebenen zu bestimmen.
Beispiel:input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME double open[]; double close[]; double low[]; double high[]; datetime time[]; int bars_check = 200; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); } //+------------------------------------------------------------------+ //| 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:
Der Nutzer kann den Zeitrahmen für die Suche nach Widerstands- und Unterstützungszonen auswählen. Die Arrays enthalten die Daten der Kerzen. Gemäß der Option bars_check wird der EA bei der Suche nach Umkehrpunkten 200 Kerzen berücksichtigen. Für jede Kerze im Chart werden die Preis- und Zeitdaten vom Programm kopiert. _Symbol, das erste Argument, weist den EA an, die Daten des Vermögenswertes des Charts abzurufen. Timeframe ist der zweite Parameter, der den vom Nutzer gewählten Zeitrahmen angibt. Der Nutzer kann jeden gewünschten Zeitraum für die Analyse angeben, da er als Eingabe definiert ist. Der nächste Parameter, von dem aus das Kopieren der Daten beginnen soll, ist der, für den wir die Funktion TimeCurrent() verwendet haben.
Da diese Funktion die aktuelle Serverzeit zurückgibt, beginnt der EA mit dem Kopieren der Daten der letzten Kerze. Um herauszufinden, wie viele Kerzen der EA kopieren soll, verwenden Sie das Argument bars_check. Hier wird angegeben, dass der EA die Informationen der letzten 200 Balken ab dem aktuellen Zeitpunkt abrufen wird. Der EA kann die Daten für eine weitere Analyse zusammenstellen, indem er das letzte Argument verwendet, das das Array (open, close, low, high oder time) angibt, in dem die kopierten Daten gespeichert werden sollen.
Für die Funktion IsSwingLow() sind drei Argumente erforderlich. Der niedrige Preis jeder Kerze ist in einem Array mit der Bezeichnung low_price[] enthalten, das der erste Parameter ist. Die aktuell analysierte Kerze wird durch den zweiten Parameter, den Index, angegeben. Die Anzahl der Kerzen, die vor und nach der aktuellen Kerze verglichen werden sollen, wird durch den dritten Parameter, Lookback, bestimmt. Eine Schleife innerhalb der Funktion vergleicht den Tiefstkurs der aktuellen Kerze mit den Tiefstkursen der benachbarten Kerzen, die von 1 bis zum Rückblickswert laufen. Die Funktion gibt den Wert false zurück und zeigt damit an, dass das aktuelle Tief kein tiefer Umkehrpunkt ist, wenn es höher ist als eines der benachbarten Tiefs. Die Funktion gibt „true“ zurück und zeigt damit an, dass es sich um einen legitimen tiefen Umkehrpunkt handelt, wenn es im Vergleich zu allen benachbarten Kerzen das niedrigste bleibt.
Dies ist das Gegenteil von dem, wie die Funktion IsSwingHigh() arbeitet. Um festzustellen, ob der Höchststand der aktuellen Kerze höher ist als die Hochs der benachbarten Kerzen innerhalb des angegebenen Rückblickbereichs, wird das Array high_price[] verwendet. Das aktuelle Hoch gibt false zurück, wenn es niedriger ist als ein benachbartes Er wird als hoher Umkehrpunkt identifiziert, wenn es andernfalls true liefert.
Nach dem Kopieren der Kerzendaten folgt die Suche nach jedem tiefen Umkehrpunkt im Chart. Diese tiefen Umkehrpunkte sind Stellen, an denen der Kurs kurzzeitig wieder nach oben drehte, wodurch mögliche Unterstützungszonen entstehen. Unsere Unterstützungszonen werden anhand jedes erkannten tiefen Umkehrpunkts als erster Referenzpunkt erstellt. Der EA prüft dann diese Zonen, indem er nach weiteren Berührungen und Reaktionen innerhalb derselben Preisspanne sucht.
Beispiel:input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME double open[]; double close[]; double low[]; double high[]; datetime time[]; int bars_check = 200; double first_sup_price; double first_sup_min_body_price; datetime first_sup_time; string support_object; ulong chart_id = ChartID(); int total_symbol_bars; int z = 7; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- ObjectsDeleteAll(chart_id); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); total_symbol_bars = Bars(_Symbol, timeframe); if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); } } } } //+------------------------------------------------------------------+ //| 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; }
Ausgabe:

Erläuterung:
Jeder tiefer Umkehrpunkt, den wir finden, besitzt grundlegende Informationen, die wir durch die Definition von Variablen bewahren, um wichtige Merkmale zu erhalten. Er zeichnet den tatsächlichen Tiefstpreis der Kerze auf, speichert die Zeit, zu der der tiefe Umkehrpunkt auftrat, und stellt die untere Begrenzung des Kerzenkörpers als den kleineren Wert zwischen dem Eröffnungs- und dem Schlusskurs dar.
Wir zeichnen wichtige Informationen zu jedem Tiefpunkt auf, wie z. B. den Zeitpunkt des Ereignisses, die untere Grenze des Kerzenkörpers und den tatsächlichen Tiefstkurs. Zur Verwaltung der grafischen Objekte wird die ID des Charts abgerufen, und es wird eine Variable erstellt, um den Namen des Rechteckobjekts zu speichern, das die Unterstützungszone darstellt. Mit einer Rückblickzeit von sieben Kerzen werden echte Tiefs identifiziert. Nachdem der Computer festgestellt hat, dass mindestens 200 Kerzen auf dem Chart vorhanden sind, geht er die Daten der siebten Kerze durch.
Die Funktion für die tiefen Umkehrpunkte wird vom Programm innerhalb der Schleife verwendet, um festzustellen, ob jede Kerze ein tiefes Umkehrmuster bildet. Tritt ein solcher Fall ein, protokolliert die Software den Zeitstempel der Kerze, den Tiefstpreis und den kleineren Wert zwischen dem Eröffnungs- und dem Schlusskurs. Danach wird das Wort „SUPPORT“ mit der tatsächlichen Supportpreis kombiniert, um der Supportzone einen unverwechselbaren Namen zu geben.
Indem er jede Kerze daraufhin untersucht, ob ihr Tiefststand niedriger ist als die Tiefststände der sieben vorangegangenen und nachfolgenden Kerzen, erkennt der Computer automatisch die Tiefststände des Umkehrpunkts. Wenn ein tiefer Umkehrpunkt identifiziert wird, wird der genaue Zeitpunkt der Kerze zur Bildung der Unterstützungszone notiert, zusammen mit dem niedrigsten Preis und dem kleineren Wert zwischen dem Eröffnungs- und dem Schlusskurs. Diese Zone wird dann auf dem Chart durch ein Rechteck dargestellt, das mit Farbe und Füllung stilisiert ist und sich vom Tiefpunkt des Umkehrpunkts bis zum aktuellen Zeitpunkt erstreckt. Durch die Kombination des Wortes „SUPPORT“ mit dem Preis erhält jede Unterstützungszone einen eindeutigen Namen, der die Überwachung und Darstellung im Chart erleichtert.
Ein Rechteck, das den Zeitraum zwischen dem Kurs des tiefen Umkehrpunkts und dem unteren Rand seines Körpers vom Zeitpunkt des tiefen Umkehrpunkts bis zur aktuellen Kerze überspannt, wird vom Programm verwendet, um die Unterstützungszonen auf dem Chart grafisch darzustellen.
Identifizierung des zweiten tiefen Umkehrpunkts
Im nächsten Schritt wird geprüft, ob sich innerhalb der Zone, die zuvor durch das erste tiefen Umkehrpunkt markiert wurde, ein weiterer tiefer Umkehrpunkt gebildet hat. Dies unterstützt die Authentizität und Robustheit der Unterstützungszone. Ab dem Moment des ersten tiefen Umkehrpunkts achtet der EA auf das Auftauchen eines zweiten tiefen Umkehrpunkts, dessen Tiefstkurs noch innerhalb der Grenzen der zuvor festgelegten Unterstützungszone liegt, d.h. zwischen dem Tiefstkurs der ersten Umkehrkerze und ihrem Mindestkörperkurs. Wenn dieses Bedürfnis befriedigt ist, hat der Markt wiederholt dasselbe Preisniveau respektiert, was die Unterstützungszone stärkt und ihre Zuverlässigkeit für mögliche Kaufsituationen erhöht.
Beispiel:double second_sup_price; datetime second_sup_time; string first_low_txt; string second_low_txt;
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); total_symbol_bars = Bars(_Symbol, timeframe); if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); break; } } } } } }
Ausgabe:

Erläuterung:
Wir beobachten die Zeit und den Preis, bevor wir nach einem zweiten Tiefpunkt suchen, und wir markieren beide Tiefpunkte auf dem Chart, um sie einfach zu erkennen. Anschließend wird mit einer for-Schleife nach einem zweiten Tiefpunkt gesucht, der auf den ersten folgt. Eine Kerze nach dem ersten tiefen Umkehrpunkt oder i + 1 beginnt die Schleife mit der Überprüfung und setzt sich über die verbleibenden Takte fort. Die Funktion des tiefen Umkehrpunkts wertet jede Kerze innerhalb der Schleife aus, um zu sehen, ob sie ein weiteres tiefes Umkehrmuster erzeugt.
Das Programm ermittelt gleichzeitig, ob das Tief des zweiten tiefen Umkehrpunkts innerhalb der ersten Unterstützungszone oder zwischen dem Tiefstkurs des ersten tiefen Umkehrpunkts und dem kleinsten Preis des Körpers liegt. Das Programm bestätigt, dass sich ein zweites legitimes Tief innerhalb der Unterstützungszone entwickelt hat, indem es den Preis und die Zeit des neuen tiefen Umkehrpunkts aufzeichnet, wenn diese Kriterien erfüllt sind.
Um die Unterstützungszone nur dann zu zeichnen, wenn beide tiefen Umkehrpunkte denselben Bereich bestätigen, sollten wir das Rechteckobjekt, das wir zuvor konstruiert haben, nun in diese Schleife verlagern. Damit ist gewährleistet, dass die Zone lediglich eine validierte Unterstützungsebene ist und nicht zu früh eingezeichnet wird.
Identifizierung des Ausbruchs aus der Unterstützungszone
Die zwei Tiefs, die wir bisher gefunden haben, haben sich um dieselbe Preisspanne gedreht, was eine mögliche Unterstützungsregion zu sein scheint. Aber nicht alle Zonen mit zwei Umkehrungen sind für unseren Ansatz geeignet. Die Zonen, in denen der Markt zweimal das Niveau eingehalten hat, ohne es zu unterschreiten, sind die einzigen, die wir beibehalten wollen. Um dies zu gewährleisten, müssen wir alle Zonen ausschließen, die zuvor einen Ausbruch erlebt haben. Indem der Schwerpunkt des EA auf robuste und aktive Unterstützungszonen beschränkt wird, in denen der Preis eindeutig Respekt und Ablehnung gezeigt hat, wird dieser Schritt die Genauigkeit zukünftiger Handelssignale verbessern.
Beispiel:double second_sup_price; datetime second_sup_time; string first_low_txt; string second_low_txt; int sup_bars; int sup_min_low_index; double sup_min_low_price;
if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); } break; } } } } }
Ausgabe:

Erläuterung:
Um festzustellen, ob der Markt die festgelegte Unterstützungszone unterschritten hat oder ob die Zone noch gültig ist, werden in diesem Abschnitt der Erklärung drei Variablen eingeführt. Die erste Variable zählt die Anzahl der Kerzen, die zwischen dem ersten Umkehrpunkt und dem jetzigen Zeitpunkt erstellt wurden. Dies hilft bei der Definition des Bereichs von Balken, die untersucht werden, um die Unterstützungszone zu bestätigen oder nach einem möglichen Ausbruch zu suchen.
Das Programm bestimmt dann, welche Kerze in diesem Bereich den niedrigsten Preis hat, was den Punkt angibt, an dem es die größte Abwärtsbewegung seit dem ersten tiefen Umkehrpunkt gegeben hat. Der tatsächliche Preiswert an diesem niedrigsten Punkt wird dann ermittelt und für eine spätere Untersuchung gespeichert.
Danach wird ein Kriterium angewandt, um festzustellen, ob der Markt die Unterstützungszone unterschritten oder respektiert hat. Die Unterstützungszone gilt als legitim, und es wird davon ausgegangen, dass der Markt dieses Niveau beibehält, wenn der niedrigste festgestellte Preis über oder gleich dem Preis des ersten tiefen Umkehrpunkts bleibt. In diesem Fall wird der Unterstützungsbereich physisch auf dem Chart dargestellt, indem grafische Komponenten wie Rechtecke, Linien oder Etiketten gezeichnet werden. Ein Ausbruch wird angezeigt, wenn der niedrigste Kurs unter das ursprüngliche Unterstützungsniveau fällt; in diesem Fall werden keine grafischen Objekte angezeigt, da die Zone nicht mehr gültig ist.
Aufwärtsveränderung des Charakters erkennen
Nach der Bestätigung einer gültigen Unterstützungszone besteht die nächste Phase darin, eine Aufwärtsveränderung des Charakters zu erkennen. Der Markt hat diese Unterstützungszone zweimal abgelehnt, was auf eine Kaufaktivität hindeutet, und sie wurde an diesem Punkt bereits durch zwei Tiefststände definiert. Eine Zone, die zweimal abgelehnt wurde, reicht jedoch nicht aus, um eine mögliche Aufwärtsbewegung festzustellen; wir müssen auch eine spürbare Veränderung der Marktstruktur feststellen.
Wir warten dafür auf eine weitere Rückkehr des Marktes in die Unterstützungszone. Wir beginnen mit der Suche nach einem Aufwärtsmuster (CHOCH), wenn der Kurs in diese Zone zurückkehrt. In diesem Muster spiegelt sich ein Wechsel von einem Abwärts- zu einem Aufwärtsmomentum wider. In diesem Fall muss das Muster eine Reihe von Marktstrukturpunkten bilden, darunter ein Hoch, ein Tief, ein tieferes Hoch und ein tieferes Tief. Wir warten auf eine Kerze, die das untere Hoch durchbricht und über diesem schließt, sobald sich das untere Tief gebildet hat. Dieser Ausbruch deutet auf einen Richtungswechsel hin und bestätigt, dass die Käufer das Kommando übernommen haben.
Die Handelsausführungsperiode ist der untere Zeitrahmen, in dem die Zeichenänderung festgestellt wird. Der untere Zeitrahmen wird verwendet, um den Einstieg zu bestätigen, indem eine Aufwärtsveränderung innerhalb oder in der Nähe der Unterstützungs- und Widerstandszonen identifiziert wird, die zuerst auf einem höheren Zeitrahmen identifiziert wurden. Durch die Verwendung von mehreren Zeitrahmen werden genaue und rechtzeitige Transaktionseinträge gewährleistet.
Identifizierung von tieferen Tiefs und tieferen Hochs
Wir beginnen unsere Untersuchung mit dem jüngsten Balken im Chart, da wir die jüngste Veränderung des Charakters feststellen wollen. Dies bedeutet, dass wir zuerst nach dem unteren Tiefpunkt suchen sollten, d. h. dem letzten Punkt, an dem der Kurs ein neues Tief erreicht hat. Als Nächstes wird das untere Hoch, dann das Tief und schließlich das Hoch bestimmt.
Beispiel:
input ENUM_TIMEFRAMES timeframe = PERIOD_M30; //SUPPORT AND RESISTANCE TIMEFRAME input ENUM_TIMEFRAMES exe_timeframe = PERIOD_M5; //EXECUTION TIMEFRAME
double exe_open[]; double exe_close[]; double exe_low[]; double exe_high[]; datetime exe_time[]; int exe_total_symbol_bars; double lower_high; datetime lower_high_time; double lower_low; datetime lower_low_time; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- ArraySetAsSeries(exe_close,true); ArraySetAsSeries(exe_open,true); ArraySetAsSeries(exe_high,true); ArraySetAsSeries(exe_low,true); ArraySetAsSeries(exe_time,true); //--- return(INIT_SUCCEEDED); }
CopyOpen(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_open); CopyClose(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_close); CopyLow(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_low); CopyHigh(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_high); CopyTime(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_time);
if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); exe_total_symbol_bars = Bars(_Symbol, exe_timeframe); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingLow(exe_low, k, 3)) { lower_low = exe_low[k]; lower_low_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingHigh(exe_high,l,3)) { lower_high = exe_high[l]; lower_high_time = exe_time[l]; break; } } break; } } } } break; } } } } }
Erläuterung:
In diesem Programmbereich steht die Aufbereitung und Analyse von Daten für die Handelsabwicklung auf Basis des Change of Character (CHoCH) im Vordergrund. Das Ausführungsfenster, das in diesem Fall eine kürzere Dauer hat als das 5-Minuten-Chart, wird zuerst definiert. Um genauere Marktbewegungen zu erfassen, erfolgen die tatsächlichen Bestätigungen für den Einstieg in den Handel in einer niedrigeren Periode, auch wenn die Unterstützungs- und Widerstandszonen in höheren Zeitrahmen, z. B. im Tages- oder Wochenchart, angezeigt werden.
Danach werden Arrays erstellt, die die Preis- und Zeitdaten der Kerzen des Ausführungszeitrahmens enthalten. Diese Arrays sind für die Strukturanalyse unverzichtbar, da sie dem EA einen präzisen Bezug zu den Hochs, Tiefs, Eröffnungen und Schließungen der einzelnen Kerzen geben. Neben dem Preis und dem Zeitpunkt des letzten niedrigeren Hochs und des letzten niedrigeren Tiefs gibt es weitere Variablen, die die Gesamtzahl der zugänglichen Kerzen angeben.
Das Programm prüft zunächst, ob für den gewählten Zeitraum genügend Kerzen vorhanden sind, um eine sinnvolle Analyse durchzuführen, bevor es fortfährt. Es sucht nach Tiefstständen, indem es jede Kerze nach der Bestätigung durchgeht. Wenn das Tief der aktuellen Kerze unter dem Tief einiger Kerzen davor und danach liegt, handelt es sich nachweislich um einen tiefen Umkehrpunkt, der auf einen lokalen Tiefpunkt des Marktes hinweist. Das tiefe Tief ist der Preis und der Zeitpunkt des tiefen Umkehrpunkts, wenn ein solches entdeckt wird.
Nach der Identifizierung eines tieferen Tiefs sucht die Software nach dem darauf folgenden hohen Umkehrpunkten. Wenn das Hoch einer Kerze die Hochs der benachbarten Kerzen übersteigt, was auf eine vorübergehende Spitze hindeutet, handelt es sich nachweislich um ein hohen Umkehrpunkt. Nach der Identifizierung des unteren Tiefs und des unteren Hochs ist die Analysephase beendet, und der EA ist bereit, die Marktstruktur auf mögliche Abwärts- oder Aufwärtsveränderungen zu prüfen.
Identifizierung von Tiefs und Hochs
Die Ermittlung des neuen Tiefs und des darauf folgenden neuen Hochs ist der nächste Schritt nach der Bestimmung des unteren Tiefs und des unteren Hochs. In dieser Phase wird sichergestellt, dass die Marktstruktur korrekt aufgebaut ist, um eine rechtmäßige Zeichenänderung zu validieren. Der Markt befand sich zuvor in einem Rückgang, als das tiefere Hoch über dem tieferen Tief lag.
Um eine Abschwächung der Abwärtsbewegung anzuzeigen, sollte das neu gebildete Tief zwischen den beiden liegen, d.h. unterhalb des tieferen Hochs, aber oberhalb des tieferen Tiefs. Der Markt hat sein Momentum von abwärts zu aufwärts geändert, was auf den Beginn einer möglichen Aufwärtswende hindeutet, wenn das nachfolgende Hoch, das zum höheren Hoch wird, über allen vorherigen Hochs und Tiefs liegt.
Beispiel:
double low_l; datetime low_time; double high_h; datetime high_time;
for(int m = l; m < bars_check-3; m++) { if(IsSwingLow(exe_low, m, 3)) { low_l = exe_low[m]; low_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingHigh(exe_high,n,3)) { high_h = exe_high[n]; high_time = exe_time[n]; break; } } break; }
Erläuterung:
Dieser Teil der Software verwendet eine Reihe von Kriterien, um die nächsten signifikanten Umkehrpunkte zu identifizieren, die eine Aufwärtsveränderung des Charakters unterstützen. Diese bestehen aus dem neu ermittelten Tiefst- und Höchstkurs und der Uhrzeit. Durch die Überwachung dieser Parameter kann der EA feststellen, ob die Marktstruktur von einem fallenden zu einem steigenden Trend gewechselt hat.
Das Programm sucht die letzten Kerzen nach einem neuen Tiefpunkt ab, bevor es diese Stellen identifiziert. Nach der Erkennung des neuen Tiefs wird schnell nach dem nächsten hohen Umkehrpunkt gesucht und dessen Preis und Zeitpunkt notiert. Das Auffinden des neuen hohen Umkehrpunkts und die Speicherung seiner Details vervollständigen die Identifizierung der entscheidenden Umkehrsequenz, die zur Bewertung der strukturellen Veränderung erforderlich ist.
Wenn eine Aufwärtskerze oberhalb des zuvor gebildeten tieferen Hochs schließt, bestätigt dies eine Aufwärtsänderung des Charakters. Dieses Ereignis beendet im Wesentlichen die rückläufige Phase und zeigt an, dass die Käufer die Kontrolle übernommen haben. Eine mögliche Trendumkehr und der Beginn einer neuen Aufwärtsstruktur werden durch die Bildung höherer Hochs und höherer Tiefs auf dem Markt angezeigt.
Beispiel:
datetime start_choch_time;if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; start_choch_time = time[j+z]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); exe_total_symbol_bars = Bars(_Symbol, exe_timeframe); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingLow(exe_low, k, 3)) { lower_low = exe_low[k]; lower_low_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingHigh(exe_high,l,3)) { lower_high = exe_high[l]; lower_high_time = exe_time[l]; for(int m = l; m < bars_check-3; m++) { if(IsSwingLow(exe_low, m, 3)) { low_l = exe_low[m]; low_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingHigh(exe_high,n,3)) { high_h = exe_high[n]; high_time = exe_time[n]; for(int o = k; o > 0; o--) { if(exe_close[o] > lower_high && exe_open[o] < lower_high) { if(lower_high > lower_low && low_l < lower_high && low_l > lower_low && high_h > low_l && high_h > lower_high && lower_low <= first_sup_min_body_price && lower_low >= first_sup_price && high_time > start_choch_time) { ObjectCreate(chart_id,"LLLH",OBJ_TREND,0,lower_low_time,lower_low,lower_high_time,lower_high); ObjectSetInteger(chart_id,"LLLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LLLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LHL",OBJ_TREND,0,lower_high_time,lower_high,low_time,low_l); ObjectSetInteger(chart_id,"LHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LH",OBJ_TREND,0,low_time,low_l,high_time,high_h); ObjectSetInteger(chart_id,"LH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"S Cross Line",OBJ_TREND,0,lower_high_time,lower_high,exe_time[o],lower_high); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_WIDTH,2); } break; } } break; } } break; } } break; } } break; } } } } break; } } } } }

Erläuterung:
In diesem Teil wird zunächst ein Referenzpunkt festgelegt, der den geeigneten Zeitpunkt für den Beginn der Analyse der Änderung des Charakters (CHOCH) angibt. Dies garantiert, dass das Programm nach der Überprüfung der aktuellsten Unterstützungszone nur noch nach strukturellen Änderungen sucht.
Das Programm durchsucht dann die Kerzen in umgekehrter Reihenfolge, um eine Kerze zu finden, die über dem unteren Hoch schließt und den Beginn eines Stimmungsumschwungs nach oben anzeigt. Ein starkes Indiz für einen Durchbruch und eine mögliche Marktumkehr ist eine Kerze, die oberhalb des tieferen Hochs schließt und unterhalb davon eröffnet.
Nachdem das Programm eine solche Kerze gefunden hat, führt es eine Reihe von Überprüfungen durch, um sicherzustellen, dass die Änderung des Charakters gültig ist. Der EA verbindet die wichtigsten Umkehrpunkte (tieferes Tief, tieferes Hoch, neues Tief und höheres Hoch) auf dem Chart, um die Struktur grafisch darzustellen, nachdem alle diese Anforderungen erfüllt sind. Darüber hinaus wird die Aufmerksamkeit auf die Ausbruchskerze gelenkt, die oberhalb des unteren Hochs geschlossen hat, was darauf hindeutet, dass die Käufer wieder die Kontrolle über den Markt übernommen haben, und als letzte Bestätigung eines Aufwärts-Charakters dient.
Durchführung des Handels
Im letzten Abschnitt der Logik, der der Handelsdurchführung gewidmet ist, werden alle früheren Bestätigungen zusammengeführt, um ein mögliches Handels-Setup zu erstellen. Der Code stellt nun fest, ob jede der festgelegten Voraussetzungen für einen Wechsel zu einem Aufwärts-Charakter (CHoCH) erfüllt ist. Die Software markiert dann die Struktur auf dem Chart und ist nach der Bestätigung bereit, das Geschäft auszuführen.
Beispiel:
#include <Trade/Trade.mqh>
CTrade trade;
input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME input ENUM_TIMEFRAMES exe_timeframe = PERIOD_M30; //EXECUTION TIMEFRAME input double lot_size = 0.2; // Lot Size input double RRR = 3; //RRR double ask_price; double take_profit; datetime lastTradeBarTime = 0;
datetime currentBarTime = iTime(_Symbol, exe_timeframe, 0); ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
for(int o = k; o > 0; o--) { if(exe_close[o] > lower_high && exe_open[o] < lower_high) { if(lower_high > lower_low && low_l < lower_high && low_l > lower_low && high_h > low_l && high_h > lower_high && lower_low <= first_sup_min_body_price && lower_low >= first_sup_price && high_time > start_choch_time) { ObjectCreate(chart_id,"LLLH",OBJ_TREND,0,lower_low_time,lower_low,lower_high_time,lower_high); ObjectSetInteger(chart_id,"LLLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LLLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LHL",OBJ_TREND,0,lower_high_time,lower_high,low_time,low_l); ObjectSetInteger(chart_id,"LHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LH",OBJ_TREND,0,low_time,low_l,high_time,high_h); ObjectSetInteger(chart_id,"LH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"S Cross Line",OBJ_TREND,0,lower_high_time,lower_high,exe_time[o],lower_high); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_WIDTH,2); if(exe_time[1] == exe_time[o] && currentBarTime != lastTradeBarTime) { take_profit = MathAbs(ask_price + ((ask_price - lower_low) * RRR)); trade.Buy(lot_size,_Symbol,ask_price,lower_low,take_profit); lastTradeBarTime = currentBarTime; } } break; } }
Ausgabe:

Erläuterung:
Nach der Verifizierung eines Wechsels zu einem Aufwärts-Charakter (CHoCH) wird in diesem Abschnitt der Handelsaufbau und das Ausführungsverfahren beschrieben. Damit das System automatisch Kaufaufträge erteilen kann, wenn alle Handelsanforderungen erfüllt sind, muss es zunächst die Handelsaktivitäten aktivieren. Die Parameter der Transaktion werden durch eine Reihe von Eingaben definiert, darunter die Losgröße für jeden Handel, die Zeitrahmen für die Erkennung von Unterstützungen und Widerständen und die Ausführung sowie das Risiko-Ertrags-Verhältnis (RRR), das den gewünschten Gewinn im Verhältnis zum Risiko festlegt.
Um sicherzustellen, dass er nur einmal pro Kerze reagiert, überwacht der Algorithmus auch den aktuellen Marktpreis und die Kerzenzeit. Dadurch wird verhindert, dass Personen mehr als einmal in dieselbe Kneipe gehen. Das Programm prüft, ob alle Parameter übereinstimmen, bevor es einen Handel platziert, wie z. B. der voraussichtliche Zeitpunkt der Kerze und das Fehlen von vorherigen Handelsgeschäften auf diesem Balken. Auf der Grundlage der RRR bestimmt es nach der Bestätigung das Take-Profit-Level, setzt den Stop-Loss auf das untere Tief und leitet automatisch einen Kaufhandel ein. Dadurch wird gewährleistet, dass die Handelseinträge diszipliniert und konsistent sind und auf etablierten Marktmechanismen und nicht auf willkürlichen Einschätzungen beruhen.
Identifizierung der Widerstandszone
Die Widerstandszone, die genau das Gegenteil der Unterstützungszone ist, muss ebenfalls bestimmt werden. Hohe Umkehrpunkte werden zur Identifizierung der Widerstandszone verwendet, während tiefe Umkehrpunkt zur Identifizierung der Unterstützungszone verwendet werden. Anders ausgedrückt: Wir suchen nach Orten, an denen der Markt eine Aufwärtsbewegung abgelehnt hat, und nicht nach Bereichen, in denen er eine Abwärtsbewegung abgelehnt hat.
Die gleiche Logik, die eine Unterstützung bestimmt, bestimmt auch eine Widerstandszone, aber das Gegenteil ist der Fall. Bevor wir die Zone um einen hohen Umkehrpunkt herum definieren, müssen wir zunächst das Hoch identifizieren. Der nächste Schritt nach der Bestimmung des ersten Hochs und der Markierung dieses Hochs ist die Beurteilung, ob sich ein zweites Hoch innerhalb der gleichen Widerstandszone entwickelt hat. Der Preis hat diesen Bereich zweimal getestet und zurückgewiesen, was seine Gültigkeit als Widerstandszone beweist, wenn der Markt ein zweiter hoher Umkehrpunkt innerhalb der hervorgehobenen Zone erreicht.
Es könnte dem Markt schwer fallen, diese Widerstandszone zu durchbrechen, und er könnte sogar noch weiter zurückfallen, was eine mögliche Verkaufsgelegenheit darstellt. Wir müssen jedoch auf eine Abwärtsveränderung des Charakters warten, um zu überprüfen, ob sich tatsächlich ein fallendes Setup entwickelt. Infolgedessen muss der Markt anfangen, niedrigere Hochs und niedrigere Tiefs anstelle von höheren Hochs und Tiefs zu produzieren. Das letzte Anzeichen dafür, dass die Verkäufer die Kontrolle übernommen haben und eine Abwärtsbewegung einsetzen könnte, ist diese rückläufige Entwicklung, die innerhalb oder in der Nähe der Widerstandszone stattfindet.
Beispiel:
double first_res_price; double first_res_max_body_price; datetime first_res_time; double second_res_price; datetime second_res_time; string resistance_object; int res_bars; int res_max_high_index; double res_max_high_price; string first_high_txt; string second_high_txt; double higher_high; datetime higher_high_time; double higher_low; datetime higher_low_time;
//RESISTANCE for(int i = z ; i < bars_check - z; i++) { if(IsSwingHigh(high, i, z)) { first_res_price = high[i]; first_res_max_body_price = MathMax(close[i], open[i]); first_res_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingHigh(high, j, z) && high[j] >= first_res_max_body_price && high[j] <= first_res_price) { second_res_price = high[j]; second_res_time = time[j]; start_choch_time = time[j+z]; resistance_object = StringFormat("RESISTANCE %f",first_res_price); res_bars = Bars(_Symbol,timeframe,first_res_time,TimeCurrent()); res_max_high_index = ArrayMaximum(high,i,res_bars); res_max_high_price = high[res_max_high_index]; if(res_max_high_price <= first_res_price) { ObjectCreate(chart_id,resistance_object,OBJ_RECTANGLE,0,first_res_time,first_res_price,TimeCurrent(),first_res_max_body_price); ObjectSetInteger(chart_id,resistance_object,OBJPROP_COLOR,clrGreen); ObjectSetInteger(chart_id,resistance_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,resistance_object,OBJPROP_FILL,true); first_high_txt = StringFormat("FIRST HIGH%d",i); ObjectCreate(chart_id,first_high_txt,OBJ_TEXT,0,first_res_time,first_res_price); ObjectSetString(chart_id,first_high_txt,OBJPROP_TEXT,"1"); second_high_txt = StringFormat("SECOND HIGH%d",i); ObjectCreate(chart_id,second_high_txt,OBJ_TEXT,0,second_res_time,second_res_price); ObjectSetString(chart_id,second_high_txt,OBJPROP_TEXT,"2"); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingHigh(exe_high, k, 3)) { higher_high = exe_high[k]; higher_high_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingLow(exe_low,l,3)) { higher_low = exe_low[l]; higher_low_time = exe_time[l]; for(int m = l; m < bars_check-3; m++) { if(IsSwingHigh(exe_high, m, 3)) { high_h = exe_high[m]; high_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingLow(exe_low,n,3)) { low_l = exe_low[n]; low_time = exe_time[n]; for(int o = k; o > 0; o--) { if(exe_close[o] < higher_low && exe_open[o] > higher_low) { if(higher_low < higher_high && high_h > higher_low && high_h < higher_high && low_l < high_h && low_l < higher_low && higher_high >= first_res_max_body_price && higher_high <= first_res_price && low_time > start_choch_time) { ObjectCreate(chart_id,"HHHL",OBJ_TREND,0,higher_high_time,higher_high,higher_low_time,higher_low); ObjectSetInteger(chart_id,"HHHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HHHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"HLH",OBJ_TREND,0,higher_low_time,higher_low,high_time,high_h); ObjectSetInteger(chart_id,"HLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"HL",OBJ_TREND,0,high_time,high_h,low_time,low_l); ObjectSetInteger(chart_id,"HL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"R Cross Line",OBJ_TREND,0,higher_low_time,higher_low,exe_time[o],higher_low); ObjectSetInteger(chart_id,"R Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"R Cross Line",OBJPROP_WIDTH,2); if(exe_time[1] == exe_time[o] && currentBarTime != lastTradeBarTime) { take_profit = MathAbs(ask_price - ((high_h - ask_price) * RRR)); trade.Sell(lot_size,_Symbol,ask_price,higher_high,take_profit); lastTradeBarTime = currentBarTime; } } break; } } break; } } break; } } break; } } break; } } } } break; } } } }
Ausgabe:

Erläuterung:
Der erste Schritt zur Bestimmung der Widerstandszone ist das Auffinden bemerkenswerter hoher Umkehrpunkte auf dem Chart, indem man die Kerzen durchläuft. Der erste Schritt besteht darin, einen hohen Umkehrpunkt ausfindig zu machen und sein Hoch, den höheren der beiden Eröffnungs- und Schlusskurse sowie den Zeitpunkt seiner Entstehung zu notieren. Das Programm sucht nach der Erkennung des ersten Hochs nach einem zweiten Hoch, das in die Zone fällt, die das erste Hoch definiert.
Der Markt hat diese Region zweimal getestet und ihre Gültigkeit als Widerstandszone mit seinem zweiten hohen Umkehrpunkt bestätigt. Bevor das visuelle Rechteck für den Widerstandsbereich auf dem Chart gezeichnet wird, ermittelt der Computer den höchsten Kurs zwischen den beiden Höchstständen, um sicherzustellen, dass keine Kerze die Zone durchbrochen hat. Um die beiden Orte zu identifizieren, aus denen die Zone besteht, verwendet das Programm Textobjekte, um den ersten und den zweiten Hochpunkt des Umkehrpunkts zu bezeichnen.
Das Programm sucht dann nach einem Abwärtswechsel des Charakters zur Handelsbestätigung, nachdem es die Widerstandszone festgestellt hat. Er sucht nach einer Preisaktionssequenz mit einem höheren Hoch, gefolgt von einem höheren Tief, dann einem niedrigeren Hoch und einem niedrigeren Tief, wodurch ein Abwärtsmuster entsteht, wobei eine niedrigere Periode für die Ausführung vorgesehen ist. Die Anwendung erstellt Trendlinien, die die relevanten Höchst- und Tiefstwerte zur Visualisierung miteinander verbinden, und notiert sie zusammen mit ihren Zeitstempeln.
Wenn eine Abwärtskerze unter dem höheren Tief des Musters schließt, dient dies als letzte Bestätigung. Der EA bestimmt Take-Profit, indem er den Abstand zwischen dem Einstiegskurs und dem Höchststand des Musters mit dem Risiko-Ertrags-Verhältnis multipliziert und dann eine Verkaufstransaktion ausführt, wenn diese Bedingung mit der Widerstandszone zusammenfällt. Durch den Vergleich der aktuellen Zeit des Balkens mit dem zuletzt getätigten Handel garantiert die Methode, dass jede Kerze nur einen Handel enthält. Bei dieser Methode werden automatisch Widerstandszonen identifiziert, die anhand von Preisaktionsmustern verifiziert werden, und Handelsgeschäfte werden nur ausgeführt, wenn alle Anforderungen erfüllt sind.
Anmerkung:
Die Strategie dieses Artikels ist vollständig projektbasiert und soll den Lesern MQL5 durch reale, praktische Anwendung vermitteln. Es handelt sich nicht um eine garantierte Methode, um im Live-Handel Gewinne zu erzielen.
Schlussfolgerung
Der von uns entwickelte EA identifiziert Unterstützungs- und Widerstandszonen, indem er hohe und tiefe Umkehrpunkte erkennt, die mindestens zweimal getestet wurden, um sicherzustellen, dass die Zonen signifikant sind. Anschließend wird auf einem niedrigeren Zeitrahmen auf steigende oder fallende Kurse geachtet, um die richtigen Einstiegspunkte zu bestätigen. Durch die Kombination der Erkennung von Zonen mit höherem Zeitrahmen mit der Preisaktion mit niedrigerem Zeitrahmen kann der EA automatisch Handelsgeschäfte mit definierten Stop-Loss- und Take-Profit-Levels ausführen.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/20021
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.
Wie man Code in CodeBase veröffentlicht: Ein praktischer Leitfaden
Arbitrage-Handel im Forex: Ein einfacher synthetischer Market-Maker-Bot für den Einstieg
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Neuroboids Optimierungsalgorithmus (NOA)
- 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.