Die "Price Action": Die Automatisierung der "Inside Bar"-Handelsstrategie

Dmitry Iglakov | 29 April, 2016

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. 1. Innenliegender Balken


Fig. 2. Das Layout eines innenliegenden Balkens

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

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

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:

  1. Setzen Sie einen Kaufstopp bei einer anstehenden Order etwas höher als das Hoch des Mutterbalkens (lediglich einige Punkte höher, zur Bestätigung).
  2. 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.
  3. Setzen Sie ein Gewinnmitnahmeniveau, welches sich knapp unterhalb der nächsten Widerstandslinie befindet.
Vergessen Sie dabei nicht, dass auf einen innenliegenden Balken entweder eine Trendumkehr oder die Fortsetzung eines Trends folgt – was bedeutet, dass wir ebenfalls eine Verkaufsstopp-Order benötigen werden.

Fig. 5. Das Setzen von Verkaufsstopps und Stopporders

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:

  1. Setzen Sie den Verkaufsstopp einer anstehenden Order knapp unterhalb des Tiefstpreises des Mutterbalkens (lediglich einige Punkte tiefer, zur Bestätigung).
  2. Setzen Sie ein Verlustbegrenzungsniveau oberhalb des Höchstpreises eines Mutterbalkens.
  3. 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

Fig. 6. Die Eingabeparameter für den Test

  1. Wählen Sie ein Symbol (in meinem Fall handelt es sich um CADJPY).
  2. 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.
  3. Setzen Sie als Zeitrahmen D1.
  4. Starten Sie den Test.
  5. Ü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

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


Fig. 9. Optimierungseinstellungen

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


Fig. 11. Chart der Testergebnisse

Fig. 11. Chart der Testergebnisse


Schlussfolgerung

  1. Wir haben einen Expert Advisor entwickelt, der mithilfe des Musters der sogenannten Innenliegenden Balken handelt und nun fertig für den Einsatz ist.
  2. Wir haben dabei sichergestellt, dass die Muster der Kursbewegungen funktionieren können – sogar ohne zusätzliche Filter für den Markteinstieg.
  3. Keinerlei Tricks (Wie etwa das System von Martingale oder die Durchschnittsbildung) kamen hierbei zum Einsatz.
  4. Die erlittenen Verluste wurden durch die korrekte Einstellung der Stopporders minimiert.
  5. 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.