MetaTrader 5 herunterladen

Der MQL5 Assistent: Wie man ein Modul an Handelssignalen erzeugt

14 März 2016, 14:55
MetaQuotes Software Corp.
0
618

Einleitung

MetaTrader 5 besitzt ein leistungsstarkes Tool zum schnellen Überpüfen von Handelskonzepten, nämlich den Handelsstrategien-Generator des MQL5 Assistenten. Die Verwendung des MQL5 Assistenten zur automatischen Erzeugung von Expert Advisor Codes wird im Beitrag "Der MQL5 Assistent: Erzeugung von Expert Advisors ohne Programmieren" beschrieben. Das offene System zur Generierung des Codes erlaubt Ihnen, die Standardklassen durch Ihre eigenen Klassen an Handelssignalen, Geldverwaltungssystemen und nachziehenden Modulen zu ergänzen.

Dieser Beitrag beschreibt die Prinzipien des Schreibens von Handelssignal-Modulen und wie man sie bei der Erzeugung von Expert Advisors mit dem MQL5 Assistenten einsetzt.

Der mit dem MQL5 Assistenten erzeugte Expert Advisor ruht auf vier Säulen - den vier Basisklassen:

Abb. 1 Die Struktur der CExpert Basisklasse

Abb. 1 Die Struktur der CExpert Basisklasse

Die CExpert Klasse (oder ihre Unterklasse) ist der "Hauptmotor" eines Handelsroboters. Eine Instanz von CExpert enthält eine Kopie jeder der folgenden Klasse: CExpertSignal, CExpertMoney und CExpertTrailing (oder ihre Unterklassen):

  1. CExpertSignal ist die Basis des Handelssignale-Generators. Eine Instanz der in CExpert umfassten, abgeleiteten CExpertSignal Klasse versorgt einen Expert Advisor mit Informationen auf Grundlage des eingebauten Algorithmus über die Möglichkeit eines Markteintritts, die Eintrittslevel und die Platzierung von schützenden Orders. Die endgültige Entscheidung über die Ausführung der Handelsoperationen trifft der EA.
  2. CExpertMoney ist die Basis des Geld- und Risikoverwaltungssystems. Eine Instanz der abgeleiteten CExpertMoney Klasse berechnet die Volumen zur Eröffnung von Positions und der Platzierung von pending Orders. Die endgültige Entscheidung über das Volumen trifft der EA.
  3. CExpertTrailing - ist die Basis des Moduls zur Unterstützung offener Positions. Eine Instanz der abgeleiteten CExpertTrailing Klasse informiert einen EA über die Notwendigkeit schützende Orders einer Position modifizieren zu müssen. Die endgültige Entscheidung über eine Order-Modifikation trifft der EA.

Zusätzlich dazu sind die Mitglieder der CExpert Klasse Instanzen der folgenden Klassen:

  • CExpertTrade (für den Handel)
  • CIndicators (zur Kontrolle der Indikatoren und Zeitreihen, die an der Arbeit des EA beteiligt sind).
  • CSymbolInfo (zum Abfragen von Informationen über das Instrument)
  • CAccountInfo (zum Abfragen von Informationen über den Status des Handels-Accounts)
  • CPositionInfo (zum Abfragen von Informationen über Positions)
  • COrderInfo (zum Abfragen von Informationen über pending Orders)

Im Folgenden bezeichnen wir daher mit "Expert" eine Instanz von CExpert oder ihrer Unterklasse.

Weitere Einzelheiten zu CExpert und der Arbeit mit dieser Klasse werden in einem separaten Beitrag beschrieben.

1. CExpertSignal Basisklasse

CExpertSignal ist die Basis des Handelssignale-Generators. Zur Kommunikation mit "außen" besitzt CExpertSignal eine Reihe von public virtuellen Methoden:

Initialisierung

 Beschreibung

virtuell Init

Initialisierung der Klasseninstanz bietet die Synchronisierung der Moduldaten mit den EA-Daten

virtuell ValidationSettings

Validierung der eingerichteten Parameter

virtuell InitIndicators

Erzeugt und initialisiert alle Indikatoren und Zeitreihen, die für die Arbeit mit Handelssignalen notwendig sind

Signale zur Eröffnung/Umkehrung/Schließen von Positions

 

virtuell CheckOpenLong

Generiert das Signal zur Eröffnung einer Long Position, legt die Eintrittslevels fest und platziert schützende Order

virtuell CheckOpenShort

Generiert das Signal zur Eröffnung einer Short Position, legt die Eintrittslevels fest und platziert schützende Order

virtuell CheckCloseLong

Generiert das Signal zum Schließen einer Long Position und legt das Austrittslevel

virtuell CheckCloseShort

Generiert das Signal zum Schließen einer Short Position und legt das Austrittslevel

virtuell CheckReverseLong

Generiert das Signal zur Umkehr einer Long Position, legt die Umkehrlevels fest und platziert schützende Order

virtuell CheckReverseShort

Generiert das Signal zur Umkehr einer Short Position, legt die Umkehrlevels fest und platziert schützende Order

Verwaltung von pending Orders

 

virtuell CheckTrailingOrderLong

Generiert das Signal zur Modifizierung einer pending Buy-Order und legt den neuen Order-Preis fest

virtuell CheckTrailingOrderShort

Generiert das Signal zur Modifizierung einer pending Sell-Order und legt den neuen Order-Preis fest

Beschreibung der Methoden

1.1 Initialisierungsmethoden:

1.1.1 Init

Die Init() Methode wird gleich, nachdem dem Expert eine Klasseninstanz hinzugefügt wurde, automatisch aufgerufen. Aufhebung der Methode ist nicht notwendig.

virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);

1.1.2 ValidationSettings

Die ValidationSettings() Methode wird direkt vom Expert aufgerufen, nachdem alle Parameter eingerichtet sind. Sollte es irgendwelche Einrichtungs-Parameter geben, muss diese Methode aufgehoben werden.

virtual bool ValidationSettings();

Sind alle Optionen gültig (d.h. es kann mit ihnen gearbeitet werden), muss die aufgehobene Methode 'true' liefern. Ist mind. einer der Parameter nicht korrekt, muss sie 'false' liefern (weitere Arbeit ist nicht möglich).

Die BasisklasseCExpertSignal besitzt keine anpassbaren Parameter, daher liefert diese Basisklassen-Methode immer 'true', ohne dabei Prüfungen durchzuführen.

1.1.3 InitIndicators

Die InitIndicators () Methode implementiert die Erzeugung und Initialisierung aller notwendigen Indikatoren und Zeitreihen. Sie wird vom Expert aufgerufen, nachdem alle Parameter eingerichtet sind und ihre Exaktheit erfolgreich bestätigt wurde. Diese Methode sollte aufgehoben werden, wenn der Handelssignale-Generator mind. einen Indikator oder Zeitreihe verwendet.

virtual bool InitIndicators(CIndicators* indicators);

Indikatoren und/oder Zeitreihen sollten mittels der geeigneten Klassen der Standard Library verwendet werden. Der Sammlung an Indikatoren eines Experts sollten Zeiger aller Indikatoren und/oder Zeitreihen (ein Zeiger, der an sie als Parameter übertragen wird) hinzugefügt werden .

Die aufgehobene Methode muss 'true' liefern, wenn alle Arbeiten an den Indikatoren und/oder Zeitreihen erfolgreich waren (wenn also mit ihnen gearbeitet werden kann). Sollte mind. einer der Vorgänge mit den Indikatoren und/oder Zeitreihen fehlgeschlagen sein, muss die Methode 'false' liefern (weitere Arbeit ist nicht möglich).

Die Basisklasse CExpertSignal verwendet keine Indikatoren oder Zeitreihen, sodass ihre Methode immer 'true' liefert, ohne irgendeine Handlung auszuführen.

1.2 Methoden zur Prüfung des Signals zur Eröffnung von Positions:

1.2.1 CheckOpenLong

Die CheckOpenLong() Methode generiert ein Signal zur Eröffnung einer Long Position und legt das Eintrittslevel und die Levels der Platzierung von schützenden Orders fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Eröffnung einer Long Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Eröffnung einer Long Position gerechnet wird.

virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);

Die Methode sollte den Algorithmus zur Prüfung der Bedingung zur Eröffnung einer Long Position implementieren. Wird diese Bedingung erfüllt, müssen dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zur Eröffnung einer Long Position, sodass ihre Methode immer 'false' liefert.

1.2.2 CheckOpenShort

Die CheckOpenShort() Methode generiert ein Signal zur Eröffnung einer Short Position und legt das Eintrittslevel und die Levels der Platzierung von schützenden Orders fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Eröffnung einer Short Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Eröffnung einer Short Position gerechnet wird. 

virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);

Die Methode muss den Algorithmus zur Prüfung der Bedingung zur Eröffnung einer Short Position implementieren. Wird diese Bedingung erfüllt, müssen dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zur Eröffnung einer Short Position, sodass ihre Methode immer 'false' liefert.

1.3 Methoden zur Prüfung des Signals zum Schließen von Positions:

1.3.1 CheckCloseLong

Die CheckCloseLong() Methode generiert ein Signal zum Schließen einer Long Position und legt das Austrittslevel fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob das Schließen einer Long Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zum Schließen einer Long Position gerechnet wird.

virtual bool CheckCloseLong(double& price);

Die Methode muss den Algorithmus zur Prüfung der Bedingung zum Schließen der Long Position implementieren. Wird diese Bedingung erfüllt, muss dem Preis der Variablen (Verweise, die an sie als Parameter übertragen werden) der entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methdoe 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zum Schließen der Long Position, sodass ihre Methode immer 'false' liefert.

1.3.2 CheckCloseShort

Die CheckCloseShort() Methode generiert ein Signal zum Schließen einer Short Position und legt das Austrittslevel fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob das Schließen einer Short Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zum Schließen einer Short Position gerechnet wird.

virtual bool CheckCloseShort(double& price);

Die Methode muss den Algorithmus zur Prüfung der Bedingung zum Schließen der Short Position implementieren.. Wird diese Bedingung erfüllt, muss dem Preis der Variablen (Verweise, die an sie als Parameter übertragen werden) der entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zum Schließen der Short Position, sodass ihre Methode immer 'false' liefert.


1.4. Methoden zur Prüfung des Signals zur Umkehrung von Positions:

1.4.1 CheckReverseLong

Die CheckReverseLong Methode generiert ein Signal zur Umkehrung einer Long Position, legt das Umkehrlevel und die Levels der Platzierung von schützenden Orders fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Umkehrung einer Long Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Umkehrung einer Long Position gerechnet wird.

virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);

Die Methode muss den Algorithmus zur Prüfung der Bedingung für eine Umkehrung der Long Position implementieren. Wird diese Bedingung erfüllt, müssen dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

In der Basisklasse CExpertSignal ist der folgende Algorithmus zur Generierung eines Signals zur Umkehrung einer Long Position implementiert:

  1. Suche nach einem Signal zum Schließen einer Long Position.
  2. Suche nach einem Signal zum Öffnen einer Short Position.
  3. Sind beide Signale aktiv (die Bedingungen erfüllt) und stimmen der Schluss- und Eröffnungskurs überein, werden dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode liefert 'true'.
Wird die Bedingung nicht erfüllt, liefert die Methode 'false'.

1.4.2 CheckReverseShort

Die CheckReverseShort Methode generiert ein Signal zur Umkehrung einer Short Position, legt das Umkehrlevel und die Levels der Platzierung von schützenden Orders fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Umkehrung einer Short Position notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Umkehrung einer Short Position auf Grundlage des Algorithmus gerechnet wird, der sich von dem in der Basisklasse implementierten unterscheidet.

virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);

Die Methode muss den Algorithmus zur Prüfung der Bedingung für eine Umkehrung der Short Position implementieren. Wird diese Bedingung erfüllt, müssen dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

In der Basisklasse CExpertSignal ist der folgende Algorithmus zur Generierung eines Signals zur Umkehrung einer Short Position implementiert:

  1. Suche nach einem Signal zum Schließen einer Short Position
  2. Suche nach einem Signal zum Öffnen einer Long Position.
  3. Sind beide Signale aktiv (die Bedingungen erfüllt) und stimmen der Schluss- und Eröffnungskurs überein, werden dem Preis der Variablen, Stop Loss, Take Profit und dem Ablauf (Verweise, die an sie als Parameter übertragen werden), entsprechende Werte zugewiesen werden, und die Methode liefert 'true'.

Wird die Bedingung nicht erfüllt, liefert die Methode 'false'.


1.5. Methoden zur Prüfung des Signals zur Modifikation einer pending Order:

1.5.1 CheckTrailingOrderLong

Die CheckTrailingOrderLong() Methode generiert ein Signal zur Modifikation einer pending Buy-Order und legt einen neuen Orderpreis fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Modifikation einer pending Buy-Order notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Modifikation einer pending Buy-Order gerechnet wird.

virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)

Die Methode muss den Algorithmus zur Prüfung der Bedingung für eine Modifikation einer pending Buy-Order implementieren. Wird diese Bedingung erfüllt, muss dem Preis der Variable (der Verweis, der an sie als Parameter übertragen wird), der entsprechende Wert zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zur Modifikation einer pending Buy-Order, sodass ihre Methode immer 'false' liefert.

1.5.2 CheckTrailingOrderShort

The CheckTrailingOrderShort() Methode generiert ein Signal zur Modifikation einer pending Sell-Order und legt einen neuen Orderpreis fest. Sie wird von einem Expert zur Feststellung aufgerufen, ob die Modifikation einer pending Sell-Order notwendig ist. Die Methode muss aufgehoben werden, wenn mit der Generierung eines Signals zur Modifikation einer pending Sell-Order gerechnet wird.

virtual bool CheckTrailingOrderShort(COrderInfo* order, double& price)

Die Methode muss den Algorithmus zur Prüfung der Bedingung für eine Modifikation einer pending Sell-Order implementieren. Wird diese Bedingung erfüllt, muss dem Preis der Variable (der Verweis, der an sie als Parameter übertragen wird), der entsprechende Wert zugewiesen werden, und die Methode sollte 'true' liefern. Wird die Bedingung nicht erfüllt, muss die Methode 'false' liefern.

Die Basisklasse CExpertSignal besitzt keinen eingebauten Algorithmus zur Generierung eines Signals zur Modifikation einer pending Sell-Order, sodass ihre Methode immer 'false' liefert.

2. Entwicklung Ihres eigenen Handelssignale-Generators

Da wir uns jetzt die Struktur der CExpertSignal Basisklasse angesehen haben, können Sie mit der Erzeugung Ihres eigenen Handelssignale-Generators beginnen.

Wie oben bereits ausgeführt, ist die CExpertSignal Klasse eine Reihe an virtuellen public "Hilfsseilen" - Methoden, mit deren Hilfe der Expert die Meinung des Handelssignale-Generators bzgl. des Markteintritts in die eine oder andere Richtung erkennen kann.

Daher ist unser erstes Ziel die Erzeugung unserer eigenen Klasse des Handelssignale-Generators, die von der CExpertSignal Klasse abgeleitet wird und die Aufhebung der geeigneten virtuellen Methoden und Implementierung der erforderlichen Algorithmen.

Unser zweites Ziel (ganz genauso wichtig) ist, diese Klasse für den MQL5 Assistenten auch "sichtbar" zu machen. Doch der Reihe nach..

2.1 Erzeugung der Klasse des Handelssignale-Generators

Also los.

Zuerst erzeugen wir (z.B. indem wir denselben MQL5 Assistenten verwenden) eine einzuschließende Datei mit der Erweiterung .mqh.

Im Dateimenü wählen wir dazu "Erzeugen" aus (oder drücken Ctrl+N) und geben die Erzeugung einer eingeschlossenen Datei an:

Abb. 2 Erzeugung einer einzuschließenden Datei mit Hilfe des MQL5 Assistenten.

Abb. 2 Erzeugung einer einzuschließenden Datei mit Hilfe des MQL5 Assistenten.

An dieser Stelle möchte ich darauf hinweisen, dass diese Datei, damit sie vom MQL5 Assistenten als Signal-Generator "entdeckt" werden kann, im Include\Expert\Signal\ Order erzeugt werden sollte.

Um die Standard Librarynicht zuzumüllen, erzeugen Sie Ihren eigenen Include\Expert\Signal\MySignals Ordner, in dem Sie dann die SampleSignal.mqh Datei und die Parameter im MQL5 Assistenten anlegen:

Abb. 3 Standort der einzuschließenden Datei einrichten

Abb. 3 Standort der einzuschließenden Datei einrichten

Als Ergebnis der Arbeit des MQL5 Assistent erhalten wir dann das folgenden Muster:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Was nun folgt ist nur "manuelle" Arbeit. Entfernen Sie die unnötigen Teile entfernen und fügen, alles was benötigt wird, hinzu (Umfassen der Datei ExpertSignal.mqh der Standard Library und einer Klassenbeschreibung, die jetzt leer ist).

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator.                      |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Als nächstes müssen wir die Algorithmen auswählen..

Als Basis für unseren Handelssignale-Generator, ziehen wir das weit verbreite Modell "Preis übersteigt den gleitenden Durchschnitt" heran. Doch wir fügen noch eine Prämisse hinzu: "Nach Überschreiten des gleitenden Durchschnitts, bewegt sich der Preis zurück und geht erst dann in die richtige Richtung." Dies sollte unsere Datei abbilden.

Allgemeiner Tipp: Wenn Sie etwas schreiben, dann sparen Sie bitte nicht an Kommentaren, denn wenn Sie später nach einiger Zeit einen sauber kommentierten Code lesen, dann werden Sie sich riesig freuen.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Class CSampleSignal.                                             |
//| Purpose: Class of trading signal generator when price            |
//|          crosses moving average,                                 |
//|          entering on the subsequent back movement.               |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Jetzt müssen wir festlegen welche Daten für die Entscheidungen über die Erzeugung von Handelssignalen notwendig sind. In unserem Fall: der Eröffnungs- und der Schlusskurs des vorherigen Balkens und der Wert des gleitenden Durchschnitts auf dem gleichen, vorherigen Balken.

Um auf diese Daten zugreifen zu können, verwenden wir die Stadnard-Library Klassen CiOpen, CiClose und CiMA. Zu den Indikatoren und Zeitreihen kommen wir später noch.

Legen wir in der Zwischenzeit lieber eine Liste der Einstellungen für unseren Generator fest. Zuerst müssen wir den gleitenden Durchschnitt festlegen. Diese Parameter beinhalten den Zeitraum, die Verschiebung entlang der Zeitachse, die Durchschnittsmethode und das Objekt des Durchschnitts. Danach müssen wir das Einstiegslevel und die Level zur Platzierung von schützenden Orders einrichten sowie die Dauer einer pending Order, da wir ja mit pending Orders arbeiten werden.

Alle Einstellungen des Generators werden in geschützten Datenmitgliedern der Klasse abgelegt. Zugriff auf die Einstellungen wird mit Hilfe der geeigneten public Methoden implementiert.

Wir ergänzen unsere Datei mit diesen Veränderungen:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;           // level to place a pending order relative to the MA
   double             m_stop_loss;       // level to place a stop loss order relative to the open price
   double             m_take_profit;     // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
  };
//+------------------------------------------------------------------+

Da wir mit geschützten Datenmitgliedern arbeiten, müssen wir einen Klassen-Constructor hinzufügen, in dem wir diese Daten per Standardwerte initialisieren.

Um die Parameter prüfen zu können, heben wir die virtuelle Methode ValidationSettings der gemäß der Beschreibung der Basisklasse auf.

Beschreibung der 'Klasse:

class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
   //--- Methods to validate the parameters
   virtual bool       ValidationSettings();
  };

Implementierung der ValidationSettings() Methode:


//+------------------------------------------------------------------+
//| Validation of the setup parameters.                              |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+

Da wir jetzt mit den gesamten Vorbereitungsarbeiten fertig sind, können wir uns eingehender mit Indikatoren und Zeitreihen beschäftigen.

Indikatoren und Zeitreihen sind die Hauptinformationsquelle für den Entscheidungsprozess (klar können Sie auch eine Münze werfen oder nach den Mondphasen gehen, doch kann das nur schwer formal dargestellt werden).

Wie wir oben ja bereits festgelegt haben, brauchen wir für vernünftige Entscheidungen die folgenden Informationen: den Eröffnungskurs des vorherigen Balkens, der Schlusskurs des vorherigen Balkens und den Wert des gleitenden Durchschnitts auf demselben vorherigen Balken.

Um diese Daten zu bekommen, verwenden wir die folgenden Klassen der Standard Library:

  • CiOpen - Zugriff auf den Eröffnungskurs des vorherigen Balkens,
  • CiClose - Zugriff auf den Schlusskurs des vorherigen Balkens,
  • CiMA   - Zugriff auf den Wert des gleitenden Durchschnitts des vorherigen Balkens.

Sie fragen Sie vielleicht: "Warum verwendet man den Indikator oder Zeitreihen, die von einer Klasse 'umhüllt' sind, wenn man nur eine einzige Zahl erhalten möchte?"

Die Bedeutung liegt in bisschen im Verborgenen - und das mache ich Ihnen nun klar.

Wie werden die Daten eines Indikators oder von Zeitreihen verwendet?

Dazu müssen wir zunächst einen Indikator erzeugen.

Danach müssen wir die notwendige Datenmenge in einen Zwischenpuffer kopieren.

Und schließlich müssen wir überprüfen, ob der Kopiervorgang auch abgeschlossen ist.

Denn nur so können wir die Daten verwenden.

Wenn Sie die Klassen der Standard Library verwenden, sparen Sie sich die Notwendigkeit, einen Indikator erzeugen zu müssen und müssen sich auch keine Gedanken mach, ob Zwischenpuffer verfügbar sind oder sich mit Datenladen oder Freigabe eines Handels herumschlagen. Das Objekt einer geeigneten Klasse macht das alles für sie. Alle benötigten Indikatoren werden durch unseren Signal-Generator während der Initialisierungsphase generiert. Und alle Indikatoren kommen dann mit dem entsprechend notwendigen temporären Puffer. Und außerdem: sobald wir der Sammlung ein Indikator- oder Zeitreihenobjekt hinzufügen (das Objekte einer speziellen Klasse), müssen Sie sich über die Relevanz der Daten keine Sorgen mehr machen (der Expert aktualisiert die Daten automatisch).

Wir platzieren die Objekte dieser Klassen in die geschützten Datenmitglieder und erzeugen für jedes Objekt eine Methode zur Initialisierung und zum Datenzugriff.

Dazu heben wir die virtuell Methode InitIndicators (gemäß der Beschreibung der Basisklasse) auf.

Beschreibung der Klasse:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values om the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementierung der Methoden InitIndicators, InitMA, InitOpen, InitClose:

//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+

Nun ist die gesamten Vorbereitungsarbeit abgeschlossen. Und Sie sehen, dass unsere Klasse ganz erheblich angewachsen ist.

Jetzt können wir endlich Handelssignale erzeugen.

Abb. 4 Handelssignale für den Preis, der den gleitenden Durchschnitt übersteigt

Abb. 4 Handelssignale für den Preis, der den gleitenden Durchschnitt übersteigt

Sehen wir uns unsere Algorithmen nochmals genauer an.

1. Das Signal für Kauf erscheint wenn beim vorherigen Balken die folgenden Bedingungen erfüllt sind:

  • der Eröffnungspreis des Balkens liegt unter dem Wert des gleitenden Durchschnitts,
  • der Schlusspreis des Balkens liegt über dem Wert des gleitenden Durchschnitts,
  • der gleitende Durchschnitt nimmt zu.

In diesem Fall bieten wir die Platzierung einer pending Buy-Order mit den durch die Einstellungen festgelegten Parameter an. Und dazu heben wir die virtuelle Methode CheckOpenLong auf und füllen sie mit den entsprechenden Funktionseinheiten.

2. Das Signal für Verkauf erscheint wenn beim vorherigen Balken die folgenden Bedingungen erfüllt sind:

  • der Eröffnungspreis des Balkens liegt über dem Wert des gleitenden Durchschnitts,
  • der Schlusspreis des Balkens liegt unter dem Wert des gleitenden Durchschnitts,
  • der gleitende Durchschnitt nimmt ab.

In diesem Fall bieten wir die Platzierung einer pending Sell-Order mit den durch die Einstellungen festgelegten Parameter an.. Und dazu heben wir die virtuelle Methode CheckOpenShort auf und füllen sie mit den entsprechenden Funktionseinheiten.

3. Wir generieren keine Signale zum Schließen von Positions. Die Positions werden durch Stop Loss/Take Profit ордерам. geschlossen.

Und deshalb heben wir die virtuelle Methoden CheckCloseLong und CheckCloseShort auch nicht auf.

4. Wir schlagen die Modifikation einer pending Order entlang des gleitenden Durchschnitts in einem "Abstand" vor, der von den Einstellungen festgelegt wurde.

 Dazu heben wir die virtuellen Methoden CheckTrailingOrderLong und CheckTrailingOrderShort auf, und füllen sie mit den entsprechenden Funktionseinheiten.

Beschreibung der Klasse:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values of the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters

   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementierung der Methoden CheckOpenLong, CheckOpenShort, CheckTrailingOrderLong, CheckTrailingOrderShort:

//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Das erste Problem ist also gelöst. Der oben stehende Code ist ein Quellcode der Handelssignale-Generator Klasse, die unsere Hauptaufgabe erfüllt.

2.2 Vorbereitung der Beschreibung der erzeugten Handelssignale-Klasse für den MQL5 Assistenten

Wenden wir uns nun unserem zweiten Problem zu. Unser Signal sollte vom Generator der Handelsstrategien des MQL5 Assistenten auch "erkannt" werden.

Die erste dazu notwendige Bedingung haben wir schon geschaffen: wir haben die Datei, in der er vom MQL5 Assistenten "gefunden" werden kann, platziert. Doch das genügt noch nicht. Der MQL5 Assistent muss die Datei nicht nur "finden", er muss sie auch als solche "erkennen". Dazu müssen wir dem ursprünglichen Text den Klassen-Descriptor für den MQL5 Assistenten hinzufügen.

Einen Klassen-Descriptor ist ein Block an Kommentaren, der gemäß bestimmter Regeln zusammengesetzt ist.

Und die sehen wir uns jetzt mal an.

1. Der Kommentarblock sollte mit den folgenden Zeilen beginnen:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |

2. Die nächste Zeile ist ein Text-Descriptor (das was wir im MQL5 Assistenten dann sehen, wenn wir das Signal auswählen) im Format "//| Title=<Text> |". Ist der Text zu lang für einen Zeile, dann fügen Sie noch eine Zeile (aber nicht mehr!) hinzu. 

In unserem Fall ergibt das dann:

//| Title=Signal on the crossing of a price and the MA               |
//| entering on its back movement                                    |

3. Danach folgt einen Zeile mit dem spezifizierten Klassentyp im Format "//| Type=<Type> |". Das <Typ> Feld muss den Signalwert besitzen (zusätzlich zu Signalen kennt der MQL5 Assistent auch noch andere Typen an Klassen).

Man schreibt:

//| Type=Signal                                                      |

4. Die folgende Zeile im Format "//| Name=<Name> |" ist der Kurzname des Signals (den der MQL5 Assistent zur Generierung der Namen der globalen Variablen des Experts verwendet).

Wir erhalten folgendes:

//| Name=Sample                                                      |

5. Der Name einer Klasse ist ein wichtiges Element der Beschreibung. In der Zeile im Format "//| Class=<ClassNameа> |", muss der <ClassName> Parameter mit dem Namen unserer Klasse übereinstimmen:

//| Class=CSampleSignal                                              |

6. Wir füllen diese Zeile nicht, doch muss sie trotzdem da sein (sie stellt die Verbindung zum Bereich Sprachreferenz dar):

//| Page=                                                            |

7. Des weiteren gibt es die Beschreibungen der Parameter für die Signaleinrichtung, die

aus einer Anzahl Reihen bestehen (ihre Anzahl = der Anzahl der Parameter).

Das Format jeder Zeile lautet: "//| Parameter=<NameOfMethode>,<TypeOfParameter>,<DefaultValue> |".

Und das ist unser Reihe an Parametern:

//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |

8. Der Kommentarblock sollte mit den folgenden Zeilen enden:

//+------------------------------------------------------------------+
// wizard description end

Fügen wir nun dem Quellcode den Descriptor hinzu.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal on crossing of the price and the MA                 |
//| entering on the back movement                                    |
//| Type=Signal                                                      |
//| Name=Sample                                                      |
//| Class=CSampleSignal                                              |
//| Page=                                                            |
//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| CSampleSignal class.                                             |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;               // object to access the values of the moving average
   CiOpen             m_open;             // object to access the bar open prices
   CiClose            m_close;            // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;        // averaging period of the MA
   int                m_shift_ma;         // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;        // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;       // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //---Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
//+------------------------------------------------------------------+
//| CSampleSignal Constructor.                                       |
//| INPUT:  No.                                                      |
//| OUTPUT: No.                                                      |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
void CSampleSignal::CSampleSignal()
  {
//--- Setting the default values
   m_period_ma  =12;
   m_shift_ma   =0;
   m_method_ma  =MODE_EMA;
   m_applied_ma =PRICE_CLOSE;
   m_limit      =0.0;
   m_stop_loss  =50.0;
   m_take_profit=50.0;
   m_expiration =10;
  }
//+------------------------------------------------------------------+
//| Validation of parameters.                                        |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Und das ist alles. Das Signal kann nun verwendet werden.

Damit der Handelsstrategien-Generator MQL5 Assistent unser Signal auch verwenden kann, sollte der MetaEditor neu gestartet werden (der MQL5 Assistent scannt den Ordner Include\Expert nur beim Booten).

Nach dem Neustart des MetaEditors kann das erzeugte Handelssignale-Modul im MQL5 Assistenten eingesetzt werden:

Abb. 5 Der erzeugte Handelssignale-Generator im MQL5 Assistenten

Abb. 5 Der erzeugte Handelssignale-Generator im MQL5 Assistenten

Die im Abschnitt der Beschreibung der Parameter der Handelssignale festgelegten Eingabeparameter stehen nun zur Verfügung:

Abbildung 6 Eingabeparameter des erzeugten Handelssignale-Generators im MQL5 Assistenten

Abb. 6 Eingabeparameter des erzeugten Handelssignale-Generators im MQL5 Assistenten

Die besten Werte der Eingabeparameter der implementierten Handelsstrategie erhält man mit Hilfe des Strategie-Testers des MetaTrader 5 Terminals.

Fazit

Der Handelsstrategien-Generator des MQL5 Assistenten erleichtert das Testen von Handelskonzepten ganz enorm. Der Code des generierten Experten beruht auf den Klassen an Handelsstrategien der Standard Library, die zur Erzeugung bestimmter Implementierungen von Handelssignalklassen, Geld- und Risikoverwaltungsklassen und Klassen zur Unterstützung von Positions verwendet werden. 

Dieser Beitrag beschreibt, wie Sie Ihre eigene Klasse an Handelssignalen mit der Implementierung von Signalen beim Übertritt des Preises und des gleitenden Durchschnitts schreiben können und wie Sie sie in den Handelsstrategien-Generator des MQL5 Assistenten mit einschließen können. Des Weiteren wird hier auch die Struktur und das Formt der Beschreibung der generierten Klassen für den MQL5 Assistenten erläutert.

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/226

Beigefügte Dateien |
samplesignal.mqh (15.49 KB)
Ökonometrischer Ansatz zur Chartanalyse Ökonometrischer Ansatz zur Chartanalyse

Dieser Beitrag beschreibt die ökonometrischen Analysemethoden, die Autokorrelationsanalyse und insbesondere die Analyse von bedingten Varianzen. Worin liegt der Vorteil des hier beschriebenen Ansatzes? Die Arbeit mit nicht-linearen GARCH-Modellen erlaubt eine formelle Repräsentation der analysierten Serien vom mathematischen Gesichtspunkt aus, sowie die Erzeugung einer Prognose für eine festgelegte Anzahl an Schritten.

Die Indikatoren der Micro-, Mittel- und Haupttrends Die Indikatoren der Micro-, Mittel- und Haupttrends

Ziel dieses Beitrags ist die Untersuchung der Möglichkeiten von Handelsautomatisierung und ihrer Analyse in Form von Indikatoren und des Expert Advisors, auf Basis einiger Vorschläge aus James Hyerczyks Buch "Pattern, Price & Time: Using Gann Theory in Trading Systems". Ohne jeden Anspruch auf Vollständigkeit untersuchen wir hier nur ein Modell - den ersten Teil der Gann-Theorie.

Elektronische Tabellen in MQL5 Elektronische Tabellen in MQL5

Dieser Beitrag beschreibt eine Klasse eines dynamischen zweidimensionalen Arrays, die in ihrer ersten Dimension Daten verschiedener Typen enthält. Diese Daten in Form einer Tabelle abzulegen, ist zur Lösung von vielen Problemen bei der Anordnung, Speicherung und der Arbeit mit gebundenen Informationen unterschiedlicher Arten sehr bequem. Der Quellcode der Klasse, die Funktionalität mit Tabellen arbeiten zu können, implementiert, ist an diesen Beitrag angehängt.

MQL5 Assistent: Wie man ein Risiko- und Geldverwaltungsmodul erzeugt MQL5 Assistent: Wie man ein Risiko- und Geldverwaltungsmodul erzeugt

Der Handelsstrategien-Generator des MQL5 Assistenten vereinfacht die Tests von Handelskonzepten ganz erheblich. Dieser Beitrag beschreibt die Entwicklung eines individuell angepassten Risiko- und Geldverwaltungsmoduls und seine Aktivierung im MQL5 Assistenten. Als Beispiel haben wir einen Geldverwaltung-Algorithmus betrachtet, in dem die Größe des Handelsvolumens durch die Ergebnisse des vorigen Abschlusses festgelegt wird. Die Struktur und das Format der Beschreibung der für diesen MQL5 Assistenten erzeugte Klasse werden hier ebenfalls besprochen.