
Die "Price Action": Die Automatisierung der "Inside Bar"-Handelsstrategie
Einführung
Alle Devisenhändler kommen früher oder später mit der Technik der sogenannten „Price Action“ in Berührung. Dies ist nicht nur eine bloße Technik zur Chartanalyse, sondern ein Gesamtsystem zur Bestimmung der Richtung, in welcher sich die Kurse in Zukunft entwickeln werden. In diesem Artikel werden wir uns das Muster der innenliegenden Balken detailliert ansehen, und anschließend einen Expert Advisor (EA) für die Nachverfolgung der innenliegenden Balken kreieren, der auch in dazu in der Lage ist, Trades auf der Grundlage dieses Musters einzugehen.
Über die „Price Action“
Die „Price Action“ ist eine Methode zur Erkennung von Kursbewegungen, die nicht auf Indikatoren beruht, sondern stattdessen sowohl einfache als auch komplexe Muster verwendet, und die als zusätzliches Hilfsmittel auch Chartelemente mit einbezieht (horizontale und vertikale Linien sowie Trendlinien, Fibonacci-Niveaus, Unterstützungsniveaus und Widerstandsniveaus, etc.).
Auf den ersten Blick mag diese Methode ziemlich kompliziert erscheinen, aber das ist tatsächlich nicht der Fall. Von Jahr zu Jahr wird diese Methode immer beliebter, weil ihre Vorteile auf der Hand liegen, und zwar vor allem im Vergleich mit solchen Methoden, die mit technischen Indikatoren arbeiten.
„Inside Bar“
Eine sogenannte „Inside Bar“ (im Folgenden als „innenliegender Balken“ bezeichnet) ist ein Balken, dessen Körper und Dochte sich vollständig innerhalb des Bereichs des vorhergehenden Balken (Mutterbalken) befinden. Das Hoch des innenliegenden Balkens liegt tiefer und das Tief des innenliegenden Balkens liegt höher als die korrespondierenden Werte des Mutterbalkens. Der Mutterbalken und der innenliegende Balken bilden dabei zusammengenommen ein potentielles Einstiegssignal aus.
Hierbei handelt es sich um ein doppeldeutiges Muster, weil es nämlich einerseits eine Trendumkehr signalisieren kann – oder aber andererseits die Fortsetzung eines Trends.
Fig. 1. Innenliegender Balken
Fig. 2. Das Layout eines innenliegenden Balkens
Die Regeln für innenliegende Balken :- Das Muster der innenliegenden Balken ist bei größeren Zeiträumen signifikant, wie etwa bei H4 oder D1.
- Das Muster kann entweder eine Trendumkehr oder die Fortsetzung eines Trends ankündigen.
- Zur präziseren Bestimmung von Einstiegspunkten können weitere grafische Werkzeuge zum Einsatz kommen, inklusive von Trendlinien, Unterstützungslinien und Widerstandslinien, Fibonacci-Niveaus, anderer Muster für die Kursbewegung, etc.
- Verwenden Sie Anstehende Orders, um einen vorzeitigen oder falschen Markteinstieg zu vermeiden.
- Verwenden Sie keinerlei innenliegende Balken, die wiederholt in einer Marktflaute auftauchen, als Einstiegssignale.
Fig. 3. Definition des echten innenliegenden Balkens bei GBPUSD D1
Mit diesem Wissen im Hinterkopf werden wir nun versuchen, einen echten innenliegenden Balken zu finden. Auf dem obigen Chart können wir erkennen, dass ein bullenhafter Balken gebildet wurde, nachdem es zuvor zu einer steilen Abwärtsbewegung gekommen war. Allerdings befindet sich dieser Balken vollständig innerhalb der Grenzen des vorhergehenden Balkens. Das Muster wird durch die Tatsache bestätigt, dass es bei einem Unterstützungsniveau gebildet wurde. Die dritte Bestätigung ist die Tatsache, dass wir es hier mit keiner Marktflaute zu tun haben. Weil das Muster also all unsere Bedingungen erfüllt, kann man es als echt betrachten.
Die Definition von Einstiegspunkten und das Setzen von Stopporders
Wir haben jetzt also einen echten innenliegenden Balken auf dem Chart gefunden (Fig. 3). Wie sollten wir nun auf den Markt eintreten, und wo sollten wir unsere Stopporders platzieren? Lassen Sie uns mal einen Blick auf die Fig. 4 werfen.
Fig. 4. Das Setzen von Kaufstopps und Stopporders
Zunächst sollten wir uns einmal die Regeln für das Setzen von Stoppniveaus überlegen, indem wir das obige Beispiel heranziehen:
- Setzen Sie einen Kaufstopp bei einer anstehenden Order etwas höher als das Hoch des Mutterbalkens (lediglich einige Punkte höher, zur Bestätigung).
- Setzen Sie eine Verlustbegrenzungsorder unterhalb eines Unterstützungsniveaus, das zugleich unterhalb des Tiefstpreises des Mutterbalkens liegt. Dies stellt eine zusätzliche Vorsichtsmaßnahme für den Fall dar, dass eine anstehende Order ausgelöst wird und der Preis das Unterstützungsniveau erreicht, nur um kurz darauf wieder zurückzuprallen und sich im späteren Verlauf in die richtige Richtung zu entwickeln.
- Setzen Sie ein Gewinnmitnahmeniveau, welches sich knapp unterhalb der nächsten Widerstandslinie befindet.
Fig. 5. Das Setzen von Verkaufsstopps und Stopporders
Zunächst sollten wir die Regeln beachten, welche für das Setzen von Stoppniveaus gelten, die wir dem obigen Beispiel entnehmen können:
- Setzen Sie den Verkaufsstopp einer anstehenden Order knapp unterhalb des Tiefstpreises des Mutterbalkens (lediglich einige Punkte tiefer, zur Bestätigung).
- Setzen Sie ein Verlustbegrenzungsniveau oberhalb des Höchstpreises eines Mutterbalkens.
- Setzen Sie ein Gewinnmitnahme-Niveau knapp oberhalb der nächsten Unterstützungslinie.
Die Entwicklung eines Expert Advisors basierend auf dem Handel mit innenliegenden Balken
Jetzt, da wir sämtliche Regeln für die Erkennung eines echten innenliegenden Balkens, den Markteintritt und das Setzen von Stopporders kennen, können wir endlich den geeigneten Expert Advisor implementieren, der auf der Grundlage der innenliegenden Balken handeln wird.
Öffnen Sie den MetaEditor aus dem Terminal von MetaTrader 4 heraus, und erstellen Sie einen neuen Expert Advisor (ich glaube, dass ich Ihnen diesen Vorgang nicht näher zu erläutern brauche, weil diese Webseite bereits mehr als genug Informationen darüber bereithält, wie man einen Expert Advisor erstellt). Sämtliche Parameter werden zu diesem Zeitpunkt noch leer gelassen. Sie können ihnen beliebige Namen geben. Der daraus resultierende Code wird wie folgt aussehen :
//+------------------------------------------------------------------+ //| InsideBar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Die Umwandlung des Musters in einen MQL4-Algorithmus
Nach der Erstellung des EA müssen wir einen innenliegenden Balken identifizieren, nachdem eine Kerze abgeschlossen wurde. Um dies zu tun führen wir neue Variablen ein und ordnen ihnen bestimmte Werte zu. Siehe den untenstehenden Code:
//+------------------------------------------------------------------+ //| InsideBar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict double open1,//first candle Open price open2, //second candle Open price close1, //first candle Close price close2, //second candle Close price low1, //first candle Low price low2, //second candle Low price high1, //first candle High price high2; //second candle High price //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- define prices of the necessary bars open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); } //+------------------------------------------------------------------+
Lassen Sie uns einmal den beispielhaften Fall annehmen, dass ein Mutterbalken bärenhaft ist (Balken 2), während ein innenliegender Balken bullenhaft ist (Balken 1). I werden eine Anzahl von Bedingungen zum Funktionskörper von OnTick() hinzufügen:
void OnTick() { //--- define prices of the necessary bars open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //--- if the second bar is bearish, while the first one is bullish if(open2>close2 && //the second bar is bullish close1>open1 && //the first bar is bearish high2>high1 && //the bar 2 High exceeds the first one's High open2>close1 && //the second bar's Open exceeds the first bar's Close low2<low1) //the second bar's Low is lower than the first bar's Low { //--- we have listed all the conditions defining that the first bar is completely within the second one } }
- Die Erstellung individualisierbarer Variablen: Stopporders, Slippage, Orderablaufzeit, die magische EA-Zahl, und die Losgröße. Verlustbegrenzungsorders können hierbei weggelassen werden, weil diese nämlich gemäß der Regeln für innenliegende Balken definiert werden.
- Geben Sie lokale Variablen ein, um das Aussehen der Variablen zu normalisieren.
- Stopporders werden in einer gewissen Entfernung von den Werten der Balkenpreise gesetzt. Um dies zu implementieren, fügen Sie die Variable Interval hinzu, welche für das Intervall zwischen dem Höchst- und Tiefst-Preisen von Balken und Stopporderniveaus verantwortlich ist, sowie für die Niveaus von anstehenden Orders.
- Fügen Sie die Variable timeBarInside hinzu, um die erneute Eröffnung einer Order infolge dieses Musters zu verhindern.
- Fügen Sie die Variable bar2size, um sicherzustellen, dass ein Mutterbalken auch groß genug ist – was ein gutes Zeichen dafür darstellt, dass die aktuelle Marktsituation keine Flaute ist.
Als Ergebnis davon erhalten wir den folgenden Code:
//+------------------------------------------------------------------+ //| InsideBar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict extern int interval = 20; //Interval extern double lot = 0.1; //Lot Size extern int TP = 300; //Take Profit extern int magic = 555124; //Magic number extern int slippage = 2; //Slippage extern int ExpDate = 48; //Expiration Hour Order extern int bar2size = 800; //Bar 2 Size double buyPrice,//define BuyStop price buyTP, //Take Profit BuyStop buySL, //Stop Loss BuyStop sellPrice, //define SellStop price sellTP, //Take Profit SellStop sellSL; //Stop Loss SellStop double open1,//first candle Open price open2, //second candle Open price close1, //first candle Close price close2, //second candle Close price low1, //first candle Low price low2, //second candle Low price high1, //first candle High price high2; //second candle High price datetime _ExpDate=0; //local variable to define a pending order expiration time double _bar2size; datetime timeBarInside; //time of the bar, at which inside bar orders were opened, to avoid re-opening //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { double _bid = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //define a lower price double _ask = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define an upper price double _point = MarketInfo(Symbol(), MODE_POINT); //--- define prices of the necessary bars open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //--- _bar2size=NormalizeDouble(((high2-low2)/_point),0); //--- if the second bar is bearish, while the first one is bullish if(timeBarInside!=iTime(Symbol(),Period(),1) && //no orders have been opened at this pattern yet _bar2size>bar2size && //the second bar is big enough, so the market is not flat open2>close2 && //the second bar is bullish close1>open1 && //the first bar is bearish high2>high1 && //the bar 2 High exceeds the first one's High open2>close1 && //the second bar's Open exceeds the first one's Close low2<low1) //the second bar's Low is lower than the first one's Low { //--- we have listed all the conditions defining that the first bar is completely within the second one timeBarInside=iTime(Symbol(),Period(),1); //indicate that orders are already placed on this pattern } } //+------------------------------------------------------------------+
Die Festlegung von Stopporderniveaus
Jetzt, da alle Vorbereitungen abgeschlossen sind, müssen wir lediglich noch die Stopporderniveaus und die Orderpreise definieren. Vergessen Sie ebenfalls nicht die Berechnung der Orderablaufzeit.
Lassen Sie uns den folgenden Code zum Körper der Funktion OnTick () hinzufügen :
buyPrice=NormalizeDouble(high2+interval*_point,Digits); //define an order price considering the interval buySL=NormalizeDouble(low2-interval*_point,Digits); //define a stop loss considering the interval buyTP=NormalizeDouble(buyPrice+TP*_point,Digits); //define a take profit _ExpDate=TimeCurrent()+ExpDate*60*60; //a pending order expiration time calculation sellPrice=NormalizeDouble(low2-interval*_point,Digits); sellSL=NormalizeDouble(high2+interval*_point,Digits); sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
Die Korrektur von Ausführungsfehlern
Falls Sie sich jemals mit der Entwicklung von Expert Advisors beschäftigt haben, dann wissen Sie wahrscheinlich, dass es beim Schließen und der Einstellung von Orders oftmals zu Fehlern kommt, unter anderem bei der Wartezeit, falschen Stopps etc. Um solche Fehler zu eliminieren, sollten wir eine separate Funktion schreiben, die über einen kleinen eingebauten Identifikator für die häufigsten Fehler verfügt.
//+----------------------------------------------------------------------------------------------------------------------+ //| The function opens or sets an order | //| symbol - symbol, at which a deal is performed. | //| cmd - a deal (may be equal to any of the deal values). | //| volume - amount of lots. | //| price - Open price. | //| slippage - maximum price deviation for market buy or sell orders. | //| stoploss - position close price when an unprofitability level is reached (0 if there is no unprofitability level).| //| takeprofit - position close price when a profitability level is reached (0 if there is no profitability level). | //| comment - order comment. The last part of comment can be changed by the trade server. | //| magic - order magic number. It can be used as a user-defined ID. | //| expiration - pending order expiration time. | //| arrow_color - open arrow color on a chart. If the parameter is absent or equal to CLR_NONE, | //| the open arrow is not displayed on a chart. | //+----------------------------------------------------------------------------------------------------------------------+ int OrderOpenF(string OO_symbol, int OO_cmd, double OO_volume, double OO_price, int OO_slippage, double OO_stoploss, double OO_takeprofit, string OO_comment, int OO_magic, datetime OO_expiration, color OO_arrow_color) { int result = -1; //result of opening an order int Error = 0; //error when opening an order int attempt = 0; //amount of performed attempts int attemptMax = 3; //maximum amount of attempts bool exit_loop = false; //exit the loop string lang=TerminalInfoString(TERMINAL_LANGUAGE); //trading terminal language, for defining the language of the messages double stopllvl=NormalizeDouble(MarketInfo(OO_symbol,MODE_STOPLEVEL)*MarketInfo(OO_symbol,MODE_POINT),Digits); //minimum stop loss/ take profit level, in points //the module provides safe order opening. //--- check stop orders for buying if(OO_cmd==OP_BUY || OO_cmd==OP_BUYLIMIT || OO_cmd==OP_BUYSTOP) { double tp = (OO_takeprofit - OO_price)/MarketInfo(OO_symbol, MODE_POINT); double sl = (OO_price - OO_stoploss)/MarketInfo(OO_symbol, MODE_POINT); if(tp>0 && tp<=stopllvl) { OO_takeprofit=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT); } if(sl>0 && sl<=stopllvl) { OO_stoploss=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT)); } } //--- check stop orders for selling if(OO_cmd==OP_SELL || OO_cmd==OP_SELLLIMIT || OO_cmd==OP_SELLSTOP) { double tp = (OO_price - OO_takeprofit)/MarketInfo(OO_symbol, MODE_POINT); double sl = (OO_stoploss - OO_price)/MarketInfo(OO_symbol, MODE_POINT); if(tp>0 && tp<=stopllvl) { OO_takeprofit=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT)); } if(sl>0 && sl<=stopllvl) { OO_stoploss=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT); } } //--- while loop while(!exit_loop) { result=OrderSend(OO_symbol,OO_cmd,OO_volume,OO_price,OO_slippage,OO_stoploss,OO_takeprofit,OO_comment,OO_magic,OO_expiration,OO_arrow_color); //attempt to open an order using the specified parameters //--- if there is an error when opening an order if(result<0) { Error = GetLastError(); //assign a code to an error switch(Error) //error enumeration { //order closing error enumeration and an attempt to fix them case 2: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt Sleep(3000); //3 seconds of delay RefreshRates(); break; //exit switch } if(attempt==attemptMax) { attempt=0; //reset the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 3: RefreshRates(); exit_loop = true; //exit while break; //exit switch case 4: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt Sleep(3000); //3 seconds of delay RefreshRates(); break; //exit switch } if(attempt==attemptMax) { attempt = 0; //reset the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 5: exit_loop = true; //exit while break; //exit switch case 6: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt Sleep(5000); //3 seconds of delay break; //exit switch } if(attempt==attemptMax) { attempt = 0; //reset the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 8: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt Sleep(7000); //3 seconds of delay break; //exit switch } if(attempt==attemptMax) { attempt = 0; //reset the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 64: exit_loop = true; //exit while break; //exit switch case 65: exit_loop = true; //exit while break; //exit switch case 128: Sleep(3000); RefreshRates(); continue; //exit switch case 129: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt Sleep(3000); //3 seconds of delay RefreshRates(); break; //exit switch } if(attempt==attemptMax) { attempt = 0; //reset the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 130: exit_loop=true; //exit while break; case 131: exit_loop = true; //exit while break; //exit switch case 132: Sleep(10000); //sleep for 10 seconds RefreshRates(); //update data //exit_loop = true; //exit while break; //exit switch case 133: exit_loop=true; //exit while break; //exit switch case 134: exit_loop=true; //exit while break; //exit switch case 135: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt RefreshRates(); break; //exit switch } if(attempt==attemptMax) { attempt = 0; //set the number of attempts to zero exit_loop = true; //exit while break; //exit switch } case 136: if(attempt<attemptMax) { attempt=attempt+1; //define one more attempt RefreshRates(); break; //exit switch } if(attempt==attemptMax) { attempt = 0; //set the amount of attempts to zero exit_loop = true; //exit while break; //exit switch } case 137: if(attempt<attemptMax) { attempt=attempt+1; Sleep(2000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 138: if(attempt<attemptMax) { attempt=attempt+1; Sleep(1000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 139: exit_loop=true; break; case 141: Sleep(5000); exit_loop=true; break; case 145: exit_loop=true; break; case 146: if(attempt<attemptMax) { attempt=attempt+1; Sleep(2000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 147: if(attempt<attemptMax) { attempt=attempt+1; OO_expiration=0; break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 148: exit_loop=true; break; default: Print("Error: ",Error); exit_loop=true; //exit while break; //other options } } //--- if no errors detected else { if(lang == "Russian") {Print("Ордер успешно открыт. ", result);} if(lang == "English") {Print("The order is successfully opened.", result);} Error = 0; //reset the error code to zero break; //exit while //errorCount =0; //reset the amount of attempts to zero } } return(result); } //+------------------------------------------------------------------+
Als Ergebnis erhalten wir den folgenden Code:
//+------------------------------------------------------------------+ //| InsideBar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict extern int interval = 20; //Interval extern double lot = 0.1; //Lot Size extern int TP = 300; //Take Profit extern int magic = 555124; //Magic number extern int slippage = 2; //Slippage extern int ExpDate = 48; //Expiration Hour Order extern int bar2size = 800; //Bar 2 Size double buyPrice,//define BuyStop price buyTP, //Take Profit BuyStop buySL, //Stop Loss BuyStop sellPrice, //define SellStop price sellTP, //Take Profit SellStop sellSL; //Stop Loss SellStop double open1,//first candle Open price open2, //second candle Open price close1, //first candle Close price close2, //second candle Close price low1, //first candle Low price low2, //second candle Low price high1, //first candle High price high2; //second candle High price datetime _ExpDate=0; //local variable to define a pending order expiration time double _bar2size; datetime timeBarInside; //time of the bar, at which inside bar orders were opened, to avoid re-opening //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { double _bid = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //define a lower price double _ask = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define an upper price double _point = MarketInfo(Symbol(), MODE_POINT); //--- define prices of the necessary bars open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //--- _bar2size=NormalizeDouble(((high2-low2)/_point),0); //--- if the second bar is bearish, while the first one is bullish if(timeBarInside!=iTime(Symbol(),Period(),1) && //no orders have been opened at this pattern yet _bar2size>bar2size && //the second bar is big enough, so the market is not flat open2>close2 && //the second bar is bullish close1>open1 && //the first bar is bearish high2>high1 && //the bar 2 High exceeds the first one's High open2>close1 && //the second bar's Open exceeds the first one's Close low2<low1) //the second bar's Low is lower than the first one's Low { buyPrice=NormalizeDouble(high2+interval*_point,Digits); //define an order price considering the interval buySL=NormalizeDouble(low2-interval*_point,Digits); //define a stop loss considering the interval buyTP=NormalizeDouble(buyPrice+TP*_point,Digits); //define a take profit _ExpDate=TimeCurrent()+ExpDate*60*60; //pending order expiration time calculation sellPrice=NormalizeDouble(low2-interval*_point,Digits); sellSL=NormalizeDouble(high2+interval*_point,Digits); sellTP=NormalizeDouble(sellPrice-TP*_point,Digits); OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue); OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue); //--- we have listed all the conditions defining that the first bar is completely within the second one timeBarInside=iTime(Symbol(),Period(),1); //indicate that orders are already placed on this pattern } } //+------------------------------------------------------------------+
Jetzt wollen wir die Kompilierung durchführen und das Logbuch auf Fehlermeldungen überprüfen.
Die Überprüfung des Expert Advisors
Jetzt ist es an der Zeit, unseren Expert Advisor zu überprüfen. Wir wollen hierzu den Strategietester starten und die Eingabeparameter festlegen. Ich habe die Parameter wie folgt spezifiziert :
Fig. 6. Die Eingabeparameter für den Test
- Wählen Sie ein Symbol (in meinem Fall handelt es sich um CADJPY).
- Stellen Sie sicher, dass der Modus „Jeder Tick“ aktiviert wurde, und legen Sie fest, dass der Test mithilfe von Daten aus der Chronik durchgeführt werden soll. Ich habe hierzu das gesamte Jahr von 2014 ausgewählt.
- Setzen Sie als Zeitrahmen D1.
- Starten Sie den Test.
- Überprüfen Sie das Logbuch, nachdem der Test absolviert wurde. Wie wir sehen können, sind bei dem Prozess keinerlei Ausführungsfehler aufgetreten.
Untenstehend ist das EA-Testjournal zu sehen:
Fig. 7. Expert Advisor Testjournal
Stellen Sie sicher, dass keine Fehler aufgetreten sind und optimieren Sie den EA.
Die Optimierung
Ich habe die folgenden Parameter zur Optimierung ausgewählt :
Fig. 8. Optimierungsparameter
Fig. 9. Optimierungseinstellungen
Dadurch haben wir jetzt einen Roboter erhalten, der für den Einsatz bereit ist.
Die Optimierung und die Testergebnisse
Fig. 10. Testergebnisse
Fig. 11. Chart der Testergebnisse
Schlussfolgerung
- Wir haben einen Expert Advisor entwickelt, der mithilfe des Musters der sogenannten Innenliegenden Balken handelt und nun fertig für den Einsatz ist.
- Wir haben dabei sichergestellt, dass die Muster der Kursbewegungen funktionieren können – sogar ohne zusätzliche Filter für den Markteinstieg.
- Keinerlei Tricks (Wie etwa das System von Martingale oder die Durchschnittsbildung) kamen hierbei zum Einsatz.
- Die erlittenen Verluste wurden durch die korrekte Einstellung der Stopporders minimiert.
- Es wurden keinerlei technische Indikatoren verwendet. Der EA basiert lediglich auf der Analyse eines „nackten“ Charts.
Vielen Dank für Ihre Aufmerksamkeit – ich hoffe, dass Sie diesen Artikel als hilfreich empfanden.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1771





- 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.