Der MQL5-Assistent: Wie man einem EA beibringt, einen bedingten Auftrag (Pending Order) eines beliebigen Preises zu platzieren

Vladimir Karputov | 27 Juni, 2016

Einleitung

Ein Expert Advisor der mithilfe des MQL5-Assistenten erstellt wurde, kann lediglich bedingte Aufträge öffnen, die einen gewissen Abstand zum aktuellen Kurs aufweisen. Das bedeutet, dass der EA neue Parameter zur Berechnung benötigt, sobald sich die Marktsituation infolge von Marktschwankungen ändert.

Dies ist für die meisten Handelssysteme mehr als nur unpraktisch. In den meisten Fällen wird das Kursniveau von bedingten Aufträgen dynamisch durch ein Handelssystem bestimmt. Hierdurch ist der Abstand zum aktuellen Kursniveau ständigen Änderungen unterworfen. In diesem Artikel werden wir uns damit beschäftigen, wie es gelingt, einen Expert Advisor unter Zuhilfenahme des MQL5-Assistenten so zu modifizieren, dass er bedingte Aufträge unabhängig des aktuellen Kurses öffnen kann.


1. Der Mechanismus, um bedingte Aufträge mit einem durch den MQL5-Assistenten erstellten EA zu öffnen

Ein generierter EA dürfte ungefähr den unten befindlichen Code in seinem jeweiligen Header aufweisen:

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string             Expert_Title="ExpertMySignalEnvelopes.mq5";      // Document name
ulong                    Expert_MagicNumber        =3915;        // 
bool                     Expert_EveryTick          =false;       // 
//--- inputs for main signal
input int                Signal_ThresholdOpen      =10;          // Signal threshold value to open [0...100]
input int                Signal_ThresholdClose     =10;          // Signal threshold value to close [0...100]
input double             Signal_PriceLevel         =0.0;         // Price level to execute a deal
input double             Signal_StopLevel          =85.0;        // Stop Loss level (in points)
input double             Signal_TakeLevel          =195.0;       // Take Profit level (in points)
input int                Signal_Expiration         =0;           // Expiration of pending orders (in bars)
input int                Signal_Envelopes_PeriodMA =13;          // Envelopes(13,0,MODE_SMA,...) Period of averaging
input int                Signal_Envelopes_Shift    =0;           // Envelopes(13,0,MODE_SMA,...) Time shift
input ENUM_MA_METHOD     Signal_Envelopes_Method   =MODE_SMA;    // Envelopes(13,0,MODE_SMA,...) Method of averaging
input ENUM_APPLIED_PRICE Signal_Envelopes_Applied  =PRICE_CLOSE; // Envelopes(13,0,MODE_SMA,...) Prices series
input double             Signal_Envelopes_Deviation=0.2;         // Envelopes(13,0,MODE_SMA,...) Deviation
input double             Signal_Envelopes_Weight   =1.0;         // Envelopes(13,0,MODE_SMA,...) Weight [0...1.0]
//--- inputs for money
input double             Money_FixLot_Percent      =10.0;        // Percent
input double             Money_FixLot_Lots         =0.1;         // Fixed volume
//+------------------------------------------------------------------+

Beachten Sie an dieser Stelle auf jeden Fall den Parameter Signal_PriceLevel. Als Standardeinstellung ist dieser Parameter des EA wie folgt eingestellt: Signal_PriceLevel=0. Er kennzeichnet die Abstand zum aktuellen Kurs. Falls er 0 beträgt, so wird ein Auftrag zum gegenwärtigen Börsenkurs geöffnet werden. Um einen bedingten Auftrag zu öffnen, sollten Sie den Parameter Signal_PriceLevel mit einem Wert versehen, der ungleich 0 ist (Der Wert für Signal_PriceLevel kann im Übrigen positiv als auch negativ sein.)

Im Normalfall ist der Wert von Signal_PriceLevel eine verhältnismäßig große Zahl. Der Unterschied zwischen einem negativen und positiven Wert wird unten dargestellt.

Signal_PriceLevel=-50:

Abb. 1 Signal_PriceLevel=-50

Abb. 1 Signal_PriceLevel=-50

Signal_PriceLevel=50:

Abb. 2 Signal_PriceLevel=50

Abb. 2 Signal_PriceLevel=50

Falls also gilt, Signal_PriceLevel=-50, so wir ein bedingter Auftrag zu einem weniger vielversprechenden Kurs geöffnet werden, wohingegen Signal_PriceLevel=50 zur Öffnung von Aufträgen während eines Kurses führt, der profitabler als der aktuelle ist.

Diese Version des EAs öffnet Sell Stop- wie auch Buy Stop-Aufträge.


2. Wo speichern wir unsere Daten über den Abstand zum Kurs, um einen bedingten Auftrag zu öffnen?

Werfen wir zunächst einen Blick auf unten befindliche Abbildung und wenden wir uns danach den Kommentaren zu:

Abb. 3 Speicherung der Daten über den Abstand zum aktuellen Kurs.

Abb. 3 Speicherung der Daten über den Abstand zum aktuellen Kurs.

Interpretation der obigen Abbildung:

Unter Expert Advisor verstehen wir einen EA, der mittels des MQL5-Assistenten generiert wurde.

Auf diese Weise wird der Signal_PriceLevel-Parameter, in dem der Abstand zum aktuellen Preis gespeichert wird und der im Expert Advisor deklariert wurde, an das Signal-Objekt der Klasse CExpertSignal weitergegeben.

Die Klasse CExpertSignal speichert den Wert des Abstands zum aktuellen Preis in der Variable m_price_level, die mittels eines geschützten Klassenbereichs deklariert wurde:

class CExpertSignal : public CExpertBase
  {
protected:
   //--- variables
   double            m_base_price;     // base price for detection of level of entering (and/or exit?)
   //--- variables for working with additional filters
   CArrayObj         m_filters;        // array of additional filters (maximum number of fileter is 64)
   //--- Adjusted parameters
   double            m_weight;         // "weight" of a signal in a combined filter
   int               m_patterns_usage; // bit mask of  using of the market models of signals
   int               m_general;        // index of the "main" signal (-1 - no)
   long              m_ignore;         // bit mask of "ignoring" the additional filter
   long              m_invert;         // bit mask of "inverting" the additional filter
   int               m_threshold_open; // threshold value for opening
   int               m_threshold_close;// threshold level for closing
   double            m_price_level;    // level of placing a pending orders relatively to the base price
   double            m_stop_level;     // level of placing of the "stop loss" order relatively to the open price
   double            m_take_level;     // level of placing of the "take profit" order relatively to the open price
   int               m_expiration;     // time of expiration of a pending order in bars


3. Struktur eines vom MQL5-Assistenten erstellen EAs

Der Expert Advisor besitzt verschiedene Blocks, die unterschiedliche Funktionsweisen aufweisen.


Abb. 4 Struktur des Expert Advisors 

Abb. 4 Struktur des Expert Advisors

Interpretation der obigen Abbildung:


4. EA-Blöcke, die sich für eine Modifikation eignen

Wie Sie der Struktur des Expert Advisors (der vom MQL5-Assistenten erstellt worden ist) entnehmen können, gibt es sogenannte Basisklassenblöcke. Basisklassen sind Teil der Standard-Library.

Die Klassen sind an sich Erweiterungen anderer Basisklassen, die wiederum aus einer oder mehrerer Basisklassen bestehen. Unten finden wir die ersten spärlichen Zeilen Code zweier Klassen - CExpert und CExpertSignal:

//+------------------------------------------------------------------+
//|                                                       Expert.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
#include "ExpertTrade.mqh"
#include "ExpertSignal.mqh"
#include "ExpertMoney.mqh"
#include "ExpertTrailing.mqh"
//+------------------------------------------------------------------+
.
.
.
class CExpert : public CExpertBase

und

//+------------------------------------------------------------------+
//|                                                 ExpertSignal.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
.
.
.
class CExpertSignal : public CExpertBase

Ich plädiere an dieser Stelle ausdrücklich gegen eine Modifizierung der Basisklassen:

  1. Wenn MetaEditor aktualisiert wird, werden alle Änderungen, die Sie an den Basisklassen vornehmen, überschrieben und die Basisklassen werden in ihren ursprünglichen Zustand zurückversetzt.
  2. In diesem Fall wäre eine Vererbung wohl angemessener. Allerdings müssten Sie dann die GESAMTE Standard-Library modifizieren.

Stattdessen wäre es wahrscheinlich das Beste, einfach den Block des Expert Advisors und der Handelssignalgeneratormodule zu modifizieren. Vor allem da unser Handelssystem bereits ein modifiziertes Modul benutzen wird: den Handelsignalgenerator des Envelopes-Indikators.

Damit ist es also entschieden: Wir werden einige Modifizierungen an den Blöcken des EAs als auch an dem des Handelssignalgenerators vornehmen.


5. Die Durchführungslogik

Der Pointer wird vom EA an den Handelssignalgenerator weitergereicht.

Zu diesem Zwecke müssen wir eine zusätzliche Variable mithilfe des geschützten Bereichs deklarieren und dann eine Methode zu Papier bringen, die diesen Pointer in der internen Variable speichert.


  Abb. 5 Die Durchführungslogik

Abb. 5 Die Durchführungslogik


6. Handelssystem

Der Zeitrahmen des Charts ist D1. Der zu benutzende Indikator ist Envelopes mit einer durchschnittlichen Periode von 13 sowie Exponentieller Mittelwertbildung. Die Typen von Aufträgen, die der Expert Advisor öffnen kann, sind Sell Stop und Buy Stop.

Falls der letzte Balken ein Bulle war, stellen wir einen Sell Stop-Auftrag ein. Falls der letzte Balken ein Bär war, stellen wir einen Buy Stop-Auftrag ein. Wir hoffen mit anderen Worten auf einen Pullback:

Abb. 6 Handelssystem

Abb. 6 Handelssystem

Um vom Handelssystem akzeptierte Handelssignale zu kreieren, wurde das Standardmodul des Handelssignalgenerators SignalEnvelopes.mqh entsprechend modifiziert.

Nehmen Sie bitte zur Kenntnis, dass Sie im vorliegenden Fall jeden Handelssignalgenerator der Standard-Library verwenden können.


7. Modifizierung eines Handelssignalgenerators - Den Balkenpreis erhalten

Lassen Sie uns beginnen. Ich möchte dazu sagen, dass ich es vorziehe, meine Programme im MQL5-Speicher zu sichern.

Das Erste, was wir tun müssen, um unseren Handelssignalgenerator zu modifizieren, ist das Anlegen einer leeren Include-Datei, indem wir diese vollständig löschen. Anschließend kopieren wir den gesamten Inhalt von Standardisierter Handelssignalgenerator des Envelopes-Indikators dort hinein.

Standardmäßig befindet sich der Handelssignalgenerator unter MQL5\Include\Expert\Signal. Um den Ordner ...\Signal der Standard-Library nicht mit zu vielen Informationen zu überladen, legen wir einen neuen Ordner im Ordner ...\Expert an und nennen diesen \MySignals:

Abb. 7 Den neuen Ordner MySignals anlegen

Abb. 7 Den neuen Ordner MySignals anlegen

Als Nächstes erzeugen wir mit Hilfe des MQL5-Assistenten eine Include-Datei.

Dazu gehen wir im MetaEditor im Dateimenü auf „Neu" und klicken dann „Include-Datei (*.mqh)" wählen.

Abb. 8 Der MQL5-Assistent. Eine Include-Datei anlegen

Abb. 8 Der MQL5-Assistent. Eine Include-Datei anlegen

Der Name der Klasse unseres Signalgenerators soll MySignalEnvelopes sein.

Und sie soll unter folgendem Pfad erreichbar sein: Include\Expert\MySignals\MySignalEnvelopes. Legen wir sie fest:

Abb. 9 Der MQL5-Assistent. Ort der Include-Datei

Abb. 9 Der MQL5-Assistent. Ort der Include-Datei

Nach einem Klick auf „Abschließen" erzeugt der MQL5-Assistent eine leere Vorlage, also ein Templates.

Dann muss die generierte MySignalEnvelopes.mqh-Datei dem MQL5-Datenspeicher hinzugefügt werden.

Abb. 10 Der MQL5-Speicher. Hinzufügen der Datei

Abb. 10 Der MQL5-Speicher. Hinzufügen der Datei

Sobald die Datei hinzugefügt worden ist, müssen wir die Änderungen im MQL5-Datenspeicher durchführen:

Abb. 11 Der MQL5-Speicher. Änderungen durchführen

Abb. 11 Der MQL5-Speicher. Änderungen durchführen

Nachdem die obigen Schritte durchgeführt wurden, können wir damit weitermachen, unser Handelssignal zu modifizieren.

Da der Generator auf der Datei \Include\Expert\Signal\SignalEnvelopes.mqh basiert, kopieren wir den den gesamten Inhalt der Datei in die Generatordatei, so dass nur noch der ursprüngliche Header übrig bleibt.

//+------------------------------------------------------------------+
//|                                            MySignalEnvelopes.mqh |
//|                              Copyright © 2013, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2013, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalEnvelopes : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

public:
                     CSignalEnvelopes(void);
                    ~CSignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalEnvelopes::~CSignalEnvelopes(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+

Nun werden wir einige ausgewählte Teile des Codes modifizieren.

Um Verwirrungen zu vermeiden, wird der modifizierte Code entsprechend hervorgehoben:

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2013, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+

Dieser Code muss kopiert und in den Handelssignalgenerator eingefügt werden. Ich hoffe, dass diese Hervorhebungen Ihnen dabei helfen, den Code besser zu verstehen.

Da wir unsere eigene Handelssignalgeneratorklasse schreiben, sollte der Name sich von dem der Basisklasse unterscheiden. Wir ersetzen daher überall im Code CSignalEnvelopes durch CMySignalEnvelopes:

Abb.12 Umbenennung der Klasse

Abb. 12 Umbenennung der Klasse

Um sicherzustellen, dass die Handelssignalgeneratorklasse im MQL5-Assistenten unter ihrem Namen angezeigt wird, ändern Sie bitte den Klassennamen im Beschreibungsblock

//| Title=Signals of indicator 'Envelopes'                           |

zu

//| Title=Signals of indicator 'MySignalEnvelopes'                   |

Ändern Sie den MA-Periodenwert

//| Parameter=PeriodMA,int,45,Period of averaging                    |

auf 13 (dies ist nur ein Vorschlag meinerseits, Sie können hier jeden Wert einstellen, der Ihnen beliebt)

//| Parameter=PeriodMA,int,13,Period of averaging                    |

Zusätzlich modifizieren wir außerdem den Abweichungsparameter,

//| Parameter=Deviation,double,0.15,Deviation                        |

indem wir einen größeren Wert einstellen.

//| Parameter=Deviation,double,1.15,Deviation                        |

Entsprechend unserer Durchführungslogik, müssen wir eine interne Variable deklarieren, die den Pointer im Hauptsignal speichern soll.

Da es sich hierbei zwangsläufig um eine interne Variable handeln muss (nur im Bereich der Handelssignalgeneratorklasse), wird sie zum folgenden Codeblock hinzugefügt:

protected:
   CiEnvelopes       m_env;          // object-indicator
   //--- adjusted parameters
   int               m_ma_period;    // the "period of averaging" parameter of the indicator
   int               m_ma_shift;     // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;     // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;    // the "deviation" parameter of the indicator
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0
   CExpertSignal    *m_signal;         // storing the pointer to the main signal

Bitte nehmen Sie zur Kenntnis, dass ich alle überflüssigen Variablen aus dem Code vollständig entfernt habe.  

Die Methode, um den Pointer im Hauptsignal zu speichern, wird in einem anderen Codeblock gespeichert - die „Methode, um den Pointer im Hauptsignal abzulegen“. Auch hier habe ich einige unnötige Methoden entfernt.

public:
                     CMySignalEnvelopes(void);
                    ~CMySignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);
   //--- method of setting the pointer to the main signal
   virtual bool      InitSignal(CExpertSignal *signal=NULL);

Lassen Sie uns nun einige modifizierte Parameter im Konstruktor spezifizieren und alle Variablen löschen, die nicht mehr länger verwendet werden:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMySignalEnvelopes::CMySignalEnvelopes(void) : m_ma_period(13),
                                               m_ma_shift(0),
                                               m_ma_method(MODE_SMA),
                                               m_ma_applied(PRICE_CLOSE),
                                               m_deviation(1.15),
                                               m_pattern_0(50)

An dieser Stelle können wir damit fortfahren, die Generierungslogik des Handelssignals entsprechend unseres Handelssystems zu modifizieren.

Der für ein Kaufen-Signal zuständige Codeblock:

int CMySignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

sieht nach den notwendigen Änderungen wie folgt aus:

int CMySignalEnvelopes::LongCondition(void) //---buy
  {
   int result=0;
   int idx   =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close<open)
        {
         prlevel=GetPriceLevelStopp(open,Open(0));
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }

Der für ein Verkaufen-Signal zuständige Codeblock:

int CMySignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

sieht nach den notwendigen Änderungen wie folgt aus:

int CMySignalEnvelopes::ShortCondition(void) //---sell
  {
   int result  =0;
   int idx     =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close>open)
        {
         prlevel=GetPriceLevelStopp(Open(0),open);
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }


8. Eine Bemerkungen den Signalcodeblock betreffend

Falls die benötigte Bedingung für ein bestimmtes Signal erfüllt wird, rufen wir die Methode GetPriceLevelStopp auf, die uns eine Nummer wie „20“ oder „15“ ausgibt, also den Wert des Abstands zum aktuellen Kurs.

Hieran anknüpfend wird die Methode PriceLevel des Objekts m_signal aufgerufen (die den Abstand zum Ermitteln des Kursniveaus des bedingten Auftrags einstellt). M_signal ist, noch einmal gesagt, dasjenige Objekt der Klasse CExpertSignal, dass den Pointer im Hauptsignal speichert.

Unten findet sich der Code für die GetPriceLevelStopp-Methode:

double CMySignalEnvelopes::GetPriceLevelStopp(double price_0,double min)
  {
   double level;
   double temp;
   temp-=(price_0-min)/PriceLevelUnit();
   level=NormalizeDouble(temp,0);
   return(level);
  }

Als Nächstes müssen wir diese Methode im Klassen-Header deklarieren.

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
   double            GetPriceLevelStopp(double price,double min);
  };

Eine weitere Methode, derer wir uns wohl oder übel bedienen werden müssen, ist die Methode des Weiterreichens des Pointers zum Hauptsignal bzw. zur internen Variable:

bool CMySignalEnvelopes::InitSignal(CExpertSignal *signal)
  {
   m_signal=signal;
   return(true);
  }

 Im Anschluss daran sollten wir einen Expert Advisor unter Zuhilfenahme des MQL5-Assistenten kreieren und diesem das Signalmodul „MySignalEnvelopes“ überantworten.

Wir müssen außerdem den Aufruf der Methode InitSignal zum Code des mittels des MQL5-Assistenten generierten EAs hinzufügen:

//--- Set filter parameters
   filter0.PeriodMA(Signal_Envelopes_PeriodMA);
   filter0.Shift(Signal_Envelopes_Shift);
   filter0.Method(Signal_Envelopes_Method);
   filter0.Applied(Signal_Envelopes_Applied);
   filter0.Deviation(Signal_Envelopes_Deviation);
   filter0.Weight(Signal_Envelopes_Weight);
   filter0.InitSignal(signal);
//...

Um die Operationen des EAs ein wenig anschaulicher zu machen, habe ich mir die Freiheit genommen, ein kleines Video zusammenzustellen:

Der Code des (durch den MQL5-Assistenten erstellten) EAs als auch der des Signalmoduls sind beide an diesen Artikel angehangen.

Unten sehen Sie die Testresultate des Expert Advisors. Der Test wurde für folgende Spezifikationen durchgeführt: EURUSD und USDJPY, 01.01.2013 - 01.09.2013, D1, Stop-Loss-Level = 85, Take-Profit-Level = 195.

Abb. 13 Test für EURUSD, D1

Abb. 13 Test für EURUSD, D1

Abb. 14 Test für USDJPY, D1

Abb. 14 Test für USDJPY, D1


Fazit

Wir haben soeben gelernt, wie wir den Code des Handelssignalmoduls so modifizieren, dass die Funktion eingesetzt werden kann, einen bedingten Auftrag unabhängig des aktuellen Kurses in Auftrag zu geben, wobei es sich um den Eröffnungs- oder Schlusskurs des vorherigen Balkens als auch um den gleitenden Durchschnittswert handeln kann. Die Optionen sind grenzenlos. Entscheidend ist, dass Sie einen Eröffnungskurs für einen bedingten Auftrag einstellen können.

Vorliegender Artikel hat Ihnen demonstriert, wie Sie den Pointer an das Hauptsignal anbinden und Ihnen somit also einen Einblick hinsichtlich der CExpertSignal-Klassenmethoden gegeben.  Ich glaube und hoffe, dass dieser Artikel allen Tradern hilft, die sich mit bedingten Aufträgen beschäftigen bzw. all jenen, die noch planen, dies zu tun.