English Русский 中文 Español 日本語 Português
preview
Ein Versuch, einen EA-Konstruktor zu entwickeln

Ein Versuch, einen EA-Konstruktor zu entwickeln

MetaTrader 5Beispiele | 10 Januar 2022, 09:46
931 0
Vladimir Karputov
Vladimir Karputov

Inhalt


Einführung

Von Anfang an war es mein Ziel, die Standardbibliothek zu nutzen. Meine erste Aufgabe bestand darin, die einfachste Funktionalität zu implementieren: die Handelsklasse CTrade einbinden und die Methode Buy oder Sell ausführen. Ich habe die Standardbibliothek gewählt, weil sie einen kurzen und prägnanten Code liefert. Der folgende kurze Code, der in Form eines Skripts ausgeführt wird, eröffnet eine Kaufposition mit einem Volumen von 1,0 Lot:

//+------------------------------------------------------------------+
//|                                                     Open Buy.mq5 |
//|                         Copyright © 2018-2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018-2021, Vladimir Karputov"
#property version   "1.001"
//---
#include <Trade\Trade.mqh>
CTrade         m_trade;                      // trading object
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   m_trade.Buy(1.0); // open Buy position, volume 1.0 lot
  }

Nach und nach wurden die Anforderungen immer komplizierter und ich stieß beim Schreiben eines neuen Expert Advisor (EA) fast jedes Mal auf Handelsfehler. So wurde mein Wunsch, korrekten Code zu schreiben, immer stärker. Schließlich erschien ein sehr wichtiger Artikel Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll. Zu dem Zeitpunkt, als dieser Artikel veröffentlicht wurde, war mir bereits bewusst, dass ich zuverlässige Kontrollfunktionen für die Ausführung von Handelsaufträgen benötigte. Von da an begann ich, mir nach und nach bewährte Funktionen anzueignen, die sich mit Kopieren->Einfügen leicht in den EA einfügen lassen.

Da bei der Arbeit von EAs fast immer mit Indikatoren gearbeitet wird, habe ich begonnen, die Funktionen für die korrekte Erstellung von Indikator-Handles sowie für den Empfang von Indikator-Daten zu beschaffen.

NB: Der MQL5-Stil impliziert, dass das Indikator-Handle EINMAL erstellt wird. In der Regel wird dies in OnInit gemacht.

Seit etwa Version 2.XXX habe ich damit begonnen, zwei Entwicklungszweige zu pflegen den normalen prozeduralen Code und den Code in Form einer Klasse (das Hauptziel der Klasse ist die Implementierung von Mehrwährungs-EAs).

Im Laufe meiner Arbeit erhielt der Konstruktor nach und nach die üblichen Einstellungen:

  • Stop Loss und Take Profit,
  • Trailing,
  • Berechnung der Losgröße (lot) als Risikoprozentsatz oder als Konstante/Mindestlot,
  • Kontrolle des Zeitintervalls, innerhalb dessen der Handel durchgeführt wird,
  • Das Vorhandensein von nur einer Position auf dem Markt,
  • Umkehrung der Handelssignale,
  • Schließen von Positionen erzwingen, falls ein gegenteiliges Signal erscheint...

Jede Eingabe erforderte die Erstellung von Codeblöcken und neuen Funktionen.

Für den täglichen Gebrauch habe ich beschlossen, die üblichen Funktionen und alle Eingaben in dem EA Trading engine 3.mq5 zu sammeln. In der Tat ist dies ein fertiger EA, der uns von einer Menge Routinearbeit befreit. Alles, was wir tun müssen, ist, Funktionen hinzuzufügen/zu entfernen oder die Interaktion zwischen Codeblöcken in jedem einzelnen Fall zu ändern.


1. EA-Funktionalität nach dem Konstruktor

Der vom Konstruktor erstellte EA verfügt sofort über mehrere Einstellungen, die zu einzigartigen Strategien kombiniert werden können. In der Version 4.XXX gelten die folgenden Regeln: 

  • Das aktuelle Symbol wird verwendet (ein Symbol des Charts, auf dem der EA gestartet wird).
  • Take Profit, Stop Loss und Trailing werden in Points (Punkten) in den Eingaben eingestellt. Points — aktuelle Symbolpunktgröße in der Kurswährung, z.B. für "EURSD" 1.00055-1.00045=10 Punkte.

Die "points" sind immer auf dem Symboldiagramm zu sehen, wenn Sie sich das Fadenkreuz anzeigen lassen:

points

Abb. 1. Points

Nachfolgend finden Sie die Eingaben des EA, der mit Hilfe des Konstruktors erstellt wird:

  • Handelseinstellungen
    • Arbeitszeitrahmen. Der Arbeitszeitrahmen (working timeframe) kann sich von dem Chart-Zeitrahmen unterscheiden, auf dem der EA gestartet wird. Dies ist der Zeitrahmen, auf dem der Indikator erstellt wird (wenn nicht explizit ein anderer Zeitrahmen im Indikator angegeben ist). Er wird auch verwendet, um den Zeitpunkt der Erstellung eines neuen Balkens zu verfolgen (falls ein Handelssignal nur dann erkannt werden soll, wenn ein neuer Balken erscheint oder wenn das Trailing nur dann gestartet werden soll, wenn ein neuer Balken erscheint).
    • Stop Loss (0 — deaktiviert).
    • Take Profit (0 — deaktiviert).
    • Trailing on ... Überprüfen des Trailing-Bedingung bei jedem Tick (Balken #0 (bei jedem Tick)) oder nur, wenn ein neuer Balken erscheint (Balken #1 (bei einem neuen Balken)).
    • Search signals on ... Suche nach einem Handelssignal bei jedem Tick (Balken #0 (bei jedem Tick)) oder nur wenn ein neuer Balken erscheint (Balken #1 (bei einem neuen Balken)).
    • Trailing Stop (min distance from price to Stop Loss)  minimaler Abstand zwischen dem Preis und dem Stop Loss der Position. Das Trailing wird nur aktiviert, wenn die Position profitabel ist und sich der Preis um Trailing Stop + Trailing Step vom offenen Preis entfernt. Die Trailing-Operation wird in den TrailingStop Codebildern angezeigt.
    • Trailing Step
  • Positionsgrößenverwaltung (Losgrößenberechnung).
    • Money Management Lot: Lot OR Risk Berechnungssystem der Losgröße. Die Losgröße (lot) kann konstant sein (Money management= konstante Losgröße, festgelegt wird die Losgröße durch "The value for "Money management" eingestellt) oder dynamisch - Risiko % pro Position (Money management= Risiko in Prozent für eine Position, der Prozentsatz des Risikos wird im The value for "Money management" eingestellt). Sie können auch eine konstante Losgröße einstellen, das dem Minimum entspricht (Money management= Lots Min).
    • The value for "Money management"  
  • Handelsmodus
    • Handelsmodus: Nur KAUF-Positionen erlaubt, Nur VERKAUF-Positionen erlaubt und KAUF- und VERKAUFS-Positionen erlaubt
  • DEMA Nutzerdefinierte Indikatorparameter. Hier stellen Sie schließlich Ihren Indikator und seine Parameter ein
    • DEMA: averaging period (Glättungslänge)
    • DEMA: horizontal shift (horizontale Verschiebung)
    • DEMA: type of price (Art des Preises)
  • Time control Arbeitszeitraum. Die Zeitspanne, innerhalb derer nach Handelssignalen gesucht werden darf
    • Use time control  Flag, zur Aktivierung/Deaktivierung der Zeitsteuerung
    • Start Hour  Stunden des Beginns des Zeitintervalls
    • Start Minute  Minute des Beginns des Zeitintervalls
    • End Hour  Stunden des Endes des Zeitintervalls
    • End Minute  Minute des Endes des Zeitintervalls
  • Pending Order Parameters  Parameter für schwebende Aufträge (pending orders)
    • Pending: Expiration, in minutes (0 -> OFF)  Lebensdauer des schwebenden Auftrags (0 deaktiviert). 
    • Pending: Indent Abstand des schwebenden Auftrags vom aktuellen Preis (wenn der Preis des schwebenden Auftrags nicht explizit festgelegt ist).
    • Pending: Maximum spread (0 -> OFF) Maximaler Spread (0 deaktiviert). Wenn der aktuelle Spread den angegebenen Wert übersteigt, wird die Pending Order nicht gesetzt (der EA wartet auf eine Verringerung des Spreads).
    • Pending: Only one pending  aktivieren/deaktivieren durch das Flag. Nur ein schwebender Auftrag ist auf dem Markt erlaubt.
    • Pending: Reverse pending type  aktivieren/deaktivieren durch das Flag. Umkehren der Handelsaufträge.
    • Pending: New pending -> delete previous ones  wenn ein schwebender Auftrag abgeschickt werden soll, dann werden alle anderen schwebenden Aufträge vorher gelöscht.
  • Zusätzliche Eigenschaften
    • Positions: Only one  aktivieren/deaktivieren durch das Flag. Es ist nur eine Position auf dem Markt erlaubt.
    • Positions: Reverse  aktivieren/deaktivieren durch das Flag. Umkehren der Handelsaufträge.
    • Positions: Close opposite  aktivieren/deaktivieren durch das Flag. Liegt ein Handelsauftrag vor, werden alle Positionen vorläufig geschlossen, damit der Auftrag ausgeführt werden kann.
    • Print log  aktivieren/deaktivieren durch das Flag. Anzeige von erweiterten Informationen über Operationen und Fehler.
    • Coefficient (if Freeze==0 Or StopsLevels==0)  Verhältnis unter Berücksichtigung des Stop Levels. 
    • Deviation  angegebener Schlupf (slippage).
    • Magic number  die eindeutige ID des EAs.

2. Der allgemeine Algorithmus des Konstruktors

Das Array SPosition wird auf der globalen Programmebene (im EA-Header) deklariert. Es besteht aus der Struktur STRUCT_POSITION. Während des Starts hat das Array eine Größe von Null. Nach der Verarbeitung eines Handelssignals geht das Array ebenfalls auf Null zurück.

Ab OnTick wird die Funktion SearchTradingSignals aufgerufen. Wenn das Signal entstanden ist (der Markt hat keine offenen Positionen), erstellt die Funktion einen Handelsauftrag (eine einzelne Struktur STRUCT_POSITION wird für jeden Handelsauftrag im Array erstellt). Das Vorhandensein einer Handelsorder wird in OnTick überprüft — die Array-Größe von SPositionswird überprüft: wenn sie größer als Null ist, liegt eine Handelsorder vor, die zur Ausführung an OpenBuy oder OpenSell gesendet wird. Die Kontrolle über die Ausführung des Handelsauftrags erfolgt in OnTradeTransaction:

Allgemeiner Algorithmus (vereinfacht)

Abb. 2. Allgemeiner Algorithmus (vereinfacht)

Es wird immer davon ausgegangen, dass der EA mit dem aktuellen Symbol arbeitet — demjenigen, auf dessen Chart der EA platziert ist. Beispiel: Wenn der EA auf USDPLN platziert ist, arbeitet er mit USDPLN.

2.1. Die Struktur STRUCT_POSITION

Diese Struktur ist das Herzstück des EAs. Sie erfüllt gleich zwei Aufgaben: Die Struktur enthält die Felder, in denen der Handelsauftrag gesetzt wird (das Setzen erfolgt in SearchTradingSignals). Die Struktur enthält auch die Felder zur Verwaltung der Ausführung eines Handelsauftrags (die Steuerung erfolgt in OnTradeTransaction). 

//+------------------------------------------------------------------+
//| Structure Positions                                              |
//+------------------------------------------------------------------+
struct STRUCT_POSITION
  {
   ENUM_POSITION_TYPE pos_type;              // position type
   double            volume;                 // position volume (if "0.0" -> the lot is "Money management")
   double            lot_coefficient;        // lot coefficient
   bool              waiting_transaction;    // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction
   ulong             waiting_order_ticket;   // waiting order ticket, ticket of the expected order
   bool              transaction_confirmed;  // transaction confirmed, "true" -> transaction confirmed
   //--- Constructor
                     STRUCT_POSITION()
     {
      pos_type                   = WRONG_VALUE;
      volume                     = 0.0;
      lot_coefficient            = 0.0;
      waiting_transaction        = false;
      waiting_order_ticket       = 0;
      transaction_confirmed      = false;
     }
  };

Einige Felder sind für den Handelsauftrag selbst zuständig, während andere die Ausführung übernehmen. Die Struktur enthält den Konstruktor die Spezialfunktion STRUCT_POSITION(). Sie wird bei der Erstellung des Strukturobjekts aufgerufen und zur Initialisierung der Strukturelemente verwendet.

Felder eines Handelsauftrags:

  • pos_type zu eröffnende Positionsart (kann POSITION_TYPE_BUY oder POSITION_TYPE_SELL sein).
  • volume Positionsvolumen. Wenn das Volumen 0,0 ist, wird es aus der Gruppe der Eingaben 'Position size management (lot calculation)' übernommen.
  • lot_coefficient  Ist das Verhältnis größer als 0,0, wird das Positionsvolumen mit dem Verhältnis multipliziert.

Felder der Steuerung der Ausführung von Handelsaufträgen

  • waiting_transaction  das Flag, das anzeigt, dass ein Handelsauftrag erfolgreich ausgeführt wurde und auf die Bestätigung gewartet werden muss.
  • waiting_order_ticket Index des Auftrags, der bei der Ausführung eines Handelsauftrags erhalten wurde.
  • Transaction_confirmed Das Flag, das anzeigt, dass die Ausführung einer Handelsorder bestätigt wurde. 

Nach der Aktivierung des Flags in transaction_confirmed wird ein Handelsauftrag aus der Struktur entfernt. Wenn also eine EA-Operation keinen Handelsauftrag beinhaltet, hat die Struktur eine Größe von Null. Weitere Informationen zu den Strukturfeldern und der Steuerung finden Sie im Bereich "Erfassen der Transaktion (vereinfachter Code)".

Warum genau verwende ich einen solchen Algorithmus?

Auf den ersten Blick mag es genügen, die Methode Buy auf true oder false zu prüfen und im Falle von true davon auszugehen, dass die Handelsorder ausgeführt wurde. In vielen Fällen funktioniert dieser Ansatz tatsächlich. Aber manchmal garantiert die Rückgabe von true das Ergebnis nicht. Dies wird in der Dokumentation zu den Methoden Buy und Sell ausgeführt:

Hinweis

Eine erfolgreiche Beendigung der Methode bedeutet nicht immer eine erfolgreiche Ausführung einer Handelsoperation. Es ist notwendig, das Ergebnis der Handelsanfrage (Rückgabecode des Handelsservers) mit ResultRetcode() und dem von ResultDeal() zurückgegebenen Wert zu überprüfen.

Das Vorhandensein des Eintrags in der Handelshistorie kann als endgültige und genaue Bestätigung der Ausführung der Handelsoperation dienen. Daher wurde der folgende Algorithmus gewählt: wenn die Methode erfolgreich ausgeführt wurde, wird ResultDeal (Handelsticket) geprüft, ResultRetcode (Ergebniscode der Anfrageausführung) geprüft und ResultOrder (Orderticket) gespeichert. Das Orderticket befindet sich in OnTradeTransaction.


3. Hinzufügen des Standardindikators — Handhabung der Datei Indicators Code.mq5

Für mehr Bequemlichkeit sind die vorgefertigten Codeblöcke (Deklaration der Variablen für die Speicherung von Handles, Inputs, Erstellung von Handles) in dem EA Indicators Code.mq5 gesammelt. Die Eingabeparameter des Indikators und die Variablen zum Speichern von Handles befinden sich im EA-"Header", die Handle-Erstellung wird in OnInit festgelegt. Beachten Sie, dass die Namen der Variablen für die Speicherung von Handles wie folgt gebildet werden: 'handle_' + 'indicator', zum Beispiel 'handle_iStdDev'. Die gesamte Handhabung von Indicators Code.mq5 läuft auf ein fortgesetztes Kopieren-Einfügen hinaus. 

NB: Der MQL5-Stil impliziert, dass das Indikator-Handle EINMAL erstellt wird. In der Regel wird dies in OnInit gemacht.

3.1. Beispiel für das Hinzufügen des Indikators iRVI (Relative Vigor Index, RVI)

Erstellen wir den EA Add indicator.mq5. Wir starten im MetaEditor den MQL-Assistenten, z. B. durch Klicken auf Neu und wählen Sie Expert Advisor (template)

Expert Advisor (template)

Abb. 3. MQL-Assistent -> Expert Advisor (template)

Ich empfehle dringend, im nächsten Schritt mindestens eine Eingabe hinzuzufügen 

Expert Advisor (template)

Abb. 4. Expert Advisor (Vorlage) -> Parameter hinzufügen

Damit lassen sich die Zeilen für den Eingabeblock automatisch in den Code einfügen:

//--- input parameters
input int      Input1=9;

MQL Wizard hat einen leeren EA erstellt. Fügen wir nun den iRVI (Relative Vigor Index, RVI) Indikator hinzu. Suchen Sie in der Datei Indicators Code.mq5 nach handle_iRVI (über ctrl + F). Die Suche ergibt die Variable, in der der Handle gespeichert ist:

iRVI

Abb. 5. RVI Handle

Kopiere wir die gefundene Zeilen und fügen sie in die EA-Kopf 'Add indicator' (Indikator hinzufügen) ein:

//--- input parameters
input int      Input1=9;
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

Wir setzen die Suche fort und suchen den Block zur Erstellung des Handles:

iRVI

Abb. 6. Handle des iRVI

Wir kopieren die gefundenen Zeilen und fügen sie in 'Add indicator' EA in OnInit ein:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iRVI
   handle_iRVI=iRVI(m_symbol.Name(),Inp_RVI_period,Inp_RVI_ma_period);
//--- if the handle is not created
   if(handle_iRVI==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iRVI indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_RVI_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Fügen wir nun die Indikatoreingaben hinzu. Mit der mittleren Maustaste klicken wir in Indicators Code.mq5 auf Inp_RVI_period, um direkt zum Eingabeblock zu gelangen:

iRVI

Abb. 7. Handle des iRVI

Kopieren wir die Zeilen und fügen sie zu den Eingabeparametern hinzu:

#property version   "1.00"
//--- input parameters
input group             "RVI"
input ENUM_TIMEFRAMES      Inp_RVI_period                = PERIOD_D1;      // RVI: timeframe
input int                  Inp_RVI_ma_period             = 15;             // RVI: averaging period
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

Das Kompilieren erzeugt die folgenden Fehler: m_symbol und m_init_error. Dies ist ein erwartetes Verhalten, da diese Variablen in dem Code vorhanden sind, der nach der Konstruktoroperation erhalten wird, während der EA "Add indicator" EA nur erstellt wurde, um die Handhabung der Datei Indicators Code.mq5 zu demonstrieren.


4. Hinzufügen eines nutzerdefinierten Indikators

Lassen Sie uns einen MA on DeMarker Indikator hinzufügen. Erstens ist er ein nutzerdefinierter Indikator, zweitens verwendet er Gruppe. Erstellen wir wie im vorherigen Abschnitt den EA 'Add custom indicator'. Kopieren Sie anschließend die Eingaben aus dem nutzerdefinierten Indikator und fügen Sie sie in den EA ein:

#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---

Wir suchen in Indicators Code.mq5 die Variable handle_iCustom zur Speicherung des Handles des nutzerdefinierten Indikators und fügen sie in den EA ein:

//+------------------------------------------------------------------+
//|                                         Add custom indicator.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---
int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

Wir suchen den Block zur Erstellung des nutzerdefinierten Indikator-Handles in OnInit() aus Indicators Code.mq5 und kopieren ihn in den EA:

int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),Inp_DEMA_period,"Examples\\DEMA",
                          Inp_DEMA_ma_period,
                          Inp_DEMA_ma_shift,
                          Inp_DEMA_applied_price);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_DEMA_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |

Hier haben wir einiges an Arbeit vor uns. Wir müssen den Zeitrahmen (InpWorkingPeriod), den Pfad zum Indikator (wir nehmen an, dass er im Stammverzeichnis des Ordners Indicators gespeichert ist) und die Eingaben festlegen:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),InpWorkingPeriod,"MA on DeMarker",
                          "DeMarker",
                          Inp_DeM_ma_period,
                          Inp_DeM_LevelUP,
                          Inp_DeM_LevelDOWN,
                          "MA",
                          Inp_MA_ma_period,
                          Inp_MA_ma_method);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(InpWorkingPeriod),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

5. Erfassen der Transaktion (vereinfachter Code)

NB: Dies ist eine vereinfachte Version des EA. Viele Funktionen haben einen kürzeren Code im Vergleich zu einem vollwertigen Konstruktor.

Wenn es keine Positionen auf dem Markt gibt, die von diesem EA eröffnet wurden, setzen wir die Handelsanfrage, um eine KAUF-Position zu eröffnen. Die Bestätigung der Positionseröffnung wird über OnTradeTransaction und OnTick ausgegeben. Suchen und Schreiben eines Handelsauftrags in der Funktion SearchTradingSignals:

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(IsPositionExists())
      return(true);
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);
   ArrayResize(SPosition,size_need_position+1);
   SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
   return(true);
  }

Wenn der Markt keine vom EA eröffneten Positionen hat und die Array-Größe SPosition null ist, erhöhen wir die Array-Größe um eins. Auf diese Weise erstellen wir ein einzelnes STRUCT_POSITION-Strukturobjekt. Dieses wiederum ruft den Konstruktor STRUCT_POSITION() auf. Nach dem Aufruf des Konstruktors werden die Strukturelemente initialisiert (z.B. Volumen - das Positionsvolumen wird auf 0.0 gesetzt, es wird also aus der Gruppe 'Positionsgrößenverwaltung (Losberechnung)' übernommen). Jetzt bleibt nur noch die Handelsauftragsart in die Struktur zu setzen. In diesem Fall kann sie interpretiert werden als: "Eröffnen einer KAUF-Position".

Nach dem Setzen des Handelsauftrags besteht das Array SPosition aus einer einzigen Struktur und die Strukturelemente haben die folgenden Werte:

Element Wert Hinweis 
 pos_type  POSITION_TYPE_BUY  bestimmt in SearchTradingSignals
 volume  0.0  initialisiert im Konstruktors der Struktur
 lot_coefficient  0.0  initialisiert im Konstruktors der Struktur
 waiting_transaction  false  initialisiert im Konstruktors der Struktur
 waiting_order_ticket  0  initialisiert im Konstruktors der Struktur
 transaction_confirmed  false  initialisiert im Konstruktors der Struktur

5.1. Wir gelangen zu OnTick bei einem neuen Tick

OnTick, allgemeines Prinzip:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
     {
      for(int i=size_need_position-1; i>=0; i--)
        {
         if(SPosition[i].waiting_transaction)
           {
            if(!SPosition[i].transaction_confirmed)
              {
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed);
               return;
              }
            else
               if(SPosition[i].transaction_confirmed)
                 {
                  ArrayRemove(SPosition,i,1);
                  return;
                 }
           }
         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
         if(SPosition[i].pos_type==POSITION_TYPE_SELL)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
        }
     }
//--- search for trading signals only at the time of the birth of new bar
   if(!RefreshRates())
      return;
//--- search for trading signals
   if(!SearchTradingSignals())
      return;
//---
  }

Zu Beginn von OnTick wird die Größe des Arrays SPosition überprüft (dies ist das Array der Struktur STRUCT_POSITION). Wenn die Array-Größe Null übersteigt, beginne mit dem Traversieren zu Null, wobei zwei Szenarien möglich sind: 

  • Wenn das Flag der Struktur waiting_transaction true ist (Handelsauftrag wurde vorbereitet, muss auf Bestätigung warten), wird das Flag transaction_confirmed geprüft. 
    • Wenn false, wurde die Transaktion noch nicht bestätigt (dies kann z.B. passieren, wenn der Handelsauftrag gesendet wurde, ein neues Tick eingetroffen ist, während OnTradeTransaction noch keine Bestätigung hat). Die entsprechende Meldung ausgeben und mit return beenden auf einen neuen Tick warten, in der Hoffnung, dass die Informationen mit dem neuen Tick aktualisiert werden.
    • Wenn true, wurde die Transaktion bestätigt. Es wird die Struktur aus dem Array entfernt und mit return verlassen.
  • Wenn das Strukturflag waiting_transaction false ist (der Handelsauftrag wurde gerade angegeben und noch nicht ausgeführt), wird das Flag waiting_transaction aktiviert und der Auftrag an OpenPosition umgeleitet. Der Codeblock kann vereinfacht werden zu

             SPosition[i].waiting_transaction=true;
             OpenPosition(i);
             return;
    aber ich habe es so belassen, damit die vollständige Form des EA-Konstruktors leichter zu verstehen ist:
             if(SPosition[i].pos_type==POSITION_TYPE_BUY)
               {
                if(InpCloseOpposite)
                  {
                   if(count_sells>0)
                     {
                      ClosePositions(POSITION_TYPE_SELL);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }
             if(SPosition[i].pos_type==POSITION_TYPE_SELL)
               {
                if(InpCloseOpposite)
                  {
                   if(count_buys>0)
                     {
                      ClosePositions(POSITION_TYPE_BUY);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }

Lassen Sie uns die Verfolgung fortsetzen. Ich möchte Sie an den Codeblock erinnern:

         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }

Der Handelsauftrag wurde gerade in die Struktur gesetzt (in der Funktion SearchTradingSignals) und das Flag waiting_transaction ist auf false gesetzt. Also setzen wir das Flag waiting_transaction auf true und übergeben den Parameter i an die Funktion OpenPosition. Dies ist die Seriennummer der Struktur im Array OpenPosition. Da die Handelsauftragsart POSITION_TYPE_BUY ist, übergeben wir die Struktur-Seriennummer an die Funktion OpenBuy.

5.2. Die Funktion OpenBuy

Das Ziel der Funktion ist es, die Vorprüfungen zu bestehen, eine Handelsanfrage zur Eröffnung von BUY zu senden und das Ergebnis sofort zu verfolgen.

Die erste Prüfung - SYMBOL_VOLUME_LIMIT

 SYMBOL_VOLUME_LIMIT Das maximal zulässige Gesamtvolumen der offenen Positionen und schwebender Aufträge in einer Richtung (entweder Kauf oder Verkauf) für dieses Symbol. Zum Beispiel können wir bei einem Volumen-Limit von 5 Lot eine offene Kaufposition von 5 Lot haben und eine Sell-Limit-Order von 5 Lot platzieren. In diesem Fall können wir jedoch weder eine schwebende Buy-Limit-Order platzieren (da das Gesamtvolumen in einer Richtung das Limit überschreitet) noch eine Sell-Limit-Order über 5 Lot platzieren.

Wenn die Prüfung nicht bestanden wird, entfernen wir das Strukturelement aus dem Array SPosition.

Die zweite Prüfung - Marge

Wir ermitteln die nach einer Handelsoperation verbleibende freie Marge (FreeMarginCheck) und die für eine Handelsoperation notwendige Marge (MarginCheck). Danach sollte die Summe zur Sicherheit mindestens so hoch sein wie FreeMarginCheck:

   if(free_margin_check>margin_check)

Wenn die Prüfung nicht bestanden wird, wird die Variable free_margin_check ausgedruckt und das Strukturelement aus dem SPosition-Array entfernt.

Die dritte Prüfung - boolsches Ergebnis der Operation Buy

Wenn die Methode Buy false zurückgibt, wird der Fehler ausgedruckt und waiting_transaction auf false gesetzt (der häufigste Grund ist Fehler 10004, requote). Damit wird ein Versuch unternommen, die KAUF-Position mit einem neuen Ticket wieder zu öffnen. Wenn das Ergebnis true ist (unten ist der Codeblock, in dem die Methode Buy Methode zurückgegeben hat true),

         if(m_trade.ResultDeal()==0)
           {
            if(m_trade.ResultRetcode()==10009) // trade order went to the exchange
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }
         else
           {
            if(m_trade.ResultRetcode()==10009)
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }

dann wird  ResultDeal geprüft (deal ticket).

Wenn das Deal-Ticket Null ist, prüfen wir ResultRetcode (Request execution reslut code). Der resultierende Returncode ist 10009 (z.B. die Handelsauftrag wurde an ein externes Handelssystem, wie eine Börse, gesendet, daher ist das Deal-Ticket Null). Wir setzen waiting_transaction auf true, während waiting_order_ticket ResultOrder (Auftragsticket) enthalten soll. Andernfalls (der Returncode ist nicht 10009), wird waiting_transaction auf false gesetzt und die Fehlermeldung wird ausgegeben.

Wenn das Deal-Ticket nicht Null ist (z. B. weil die Ausführung auf demselben Handelsserver erfolgt), werden die gleichen Rückgabeprüfungen durchgeführt und die Werte in Wartende_Transaktion und Wartende_Bestellungsticket geschrieben.

5.3. OnTradeTransaktion

Wenn der Handelsauftrag erfolgreich gesendet wurde, warten wir auf die Bestätigung, dass der Auftrag durchgeführt und in der Handelshistorie aufgezeichnet wurde. In OnTradeTransaction arbeiten wir mit der Variablen trans (die Struktur des MqlTradeTransaction-Typs). Die Struktur hat nur zwei Zeilen von Interesse — deal und type:

struct MqlTradeTransaction
  {
   ulong                         deal;             // Deal ticket
   ulong                         order;            // Order ticket
   string                        symbol;           // Symbol name
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Trading transaction type
   ENUM_ORDER_TYPE               order_type;       // Order type
   ENUM_ORDER_STATE              order_state;      // Order state
   ENUM_DEAL_TYPE                deal_type;        // Deal type
   ENUM_ORDER_TYPE_TIME          time_type;        // Order type by lifetime
   datetime                      time_expiration;  // Order expiration time
   double                        price;            // Price 
   double                        price_trigger;    // Stop Limit order trigger price
   double                        price_sl;         // Stop Loss level
   double                        price_tp;         // Take Profit level
   double                        volume;           // Volume in lots
   ulong                         position;         // Position ticket
   ulong                         position_by;      // Opposite position ticket
  };


Sobald OnTradeTransaction TRADE_TRANSACTION_DEAL_ADD erhält (Hinzufügen eines Geschäfts zur Historie), wird eine Prüfung durchgeführt: Versuch, ein Deal in der Historie über HistoryDealSelect auszuwählen. Wenn die Auswahl fehlschlägt, wird der Fehler ausgeben. Wenn der Deal in der Historie existiert, iteriere über das SPosition-Array in einer Schleife. In der Schleife werden nur die Strukturen betrachtet, die waiting_transaction auf true gesetzt haben, während waiting_order_ticket gleich dem Ticket der Bestellung eines ausgewählten Deals ist. Wenn eine Übereinstimmung gefunden wird, setzen wir transaction_confirmed auf true. Das bedeutet, dass der Handelsauftrag ausgeführt und bestätigt wurde.

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
   if(type==TRADE_TRANSACTION_DEAL_ADD)
     {
      ResetLastError();
      if(HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
        {
         Print(__FILE__," ",__FUNCTION__,", ERROR: ","HistoryDealSelect(",trans.deal,") error: ",GetLastError());
         return;
        }
      if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic)
        {
         if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
           {
            int size_need_position=ArraySize(SPosition);
            if(size_need_position>0)
              {
               for(int i=0; i<size_need_position; i++)
                 {
                  if(SPosition[i].waiting_transaction)
                     if(SPosition[i].waiting_order_ticket==m_deal.Order())
                       {
                        Print(__FUNCTION__," Transaction confirmed");
                        SPosition[i].transaction_confirmed=true;
                        break;
                       }
                 }
              }
           }
        }
     }
  }

Bei einem neuen Tick starten wir wieder bei OnTick. Die Struktur mit true in transaction_confirmed wird aus dem SPosition-Array entfernt. Damit ist ein Handelsauftrag erteilt und verfolgt worden, bis er in der Handelshistorie erscheint.


6. Erstellen eines EA (Positionseröffnungssignale) mit Hilfe des Konstruktors

Bevor wir einen EA entwickeln, sollten wir über seine Handelsstrategie nachdenken. Betrachten wir eine einfache Strategie, die auf dem Indikator iDEMA (Double Exponential Moving Average, DEMA) basiert. Dies ist eine Standardstrategie, die im Konstruktor eingestellt ist. Ein Versuch, ein offenes Signal zu finden, wird nur unternommen, wenn ein neuer Balken erscheint, während das Handelssignal selbst ein Indikator ist, der sequentiell nach oben oder unten geht:

DEMA-Strategie

Abb. 8. DEMA-Strategie

Denken Sie daran, dass jede Strategie durch Anpassung der Parameter stark verändert werden kann. Wir können zum Beispiel Trailing deaktivieren, aber Take Profit und Stop Loss beibehalten. Oder umgekehrt: Take Profit und Stop Loss deaktivieren, Trailing aber beibehalten. Wir können auch die Handelsrichtungen einschränken, indem wir nur KAUFEN oder VERKAUFEN zulassen. Es ist auch möglich, die Zeitsteuerung zu aktivieren und den Handel in der Nacht einzuschränken oder, im Gegenteil, den Handel nur zur Nachtzeit einzurichten. Ein Handelssystem kann auch drastisch verändert werden, indem Parameter aus der Gruppe Zusätzliche Funktionen angepasst werden.

Im Allgemeinen wird das Rückgrat einer Handelsstrategie in der Funktion SearchTradingSignals gebildet, während alle anderen Parameter für das "Sondieren" des Marktes auf der Suche nach optimalen Ansätzen gedacht sind.

Wir erstellen also eine neue Datei, die ein leerer EA sein soll (wir führen die in den Abbildungen 3 und 4 angegebenen Schritte aus). In Schritt 4 geben wir einen eindeutigen Namen für Ihren EA an. Nehmen wir an, es ist iDEMA Full EA.mq5. Als Ergebnis erhalten wir die folgende Zwischenversion:

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input int      Input1=9;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Kopieren wir nun den gesamten Code aus Trading engine 3.mq5 und fügen ihn anstelle der Zeilen ein. Nun ist es an der Zeit, den "EA-Header" zu bearbeiten. Der resultierende "Header" sieht wie folgt aus:

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//+------------------------------------------------------------------+
//|                                             Trading engine 3.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "4.003"
#property description "barabashkakvn Trading engine 4.003"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

Der "Kopf" sollte wie folgt aussehen:

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.001"
#property description "iDEMA EA"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

Wenn wir dies jetzt kompilieren, gibt es keine Fehler. Der erhaltene EA ist sogar in der Lage zu handeln.

6.1. Die Funktion SearchTradingSignals

Dies ist die Hauptfunktion, die für die Überprüfung der Verfügbarkeit von Handelsaufträgen verantwortlich ist. Betrachten wir diese Funktion Block für Block.

Nicht mehr als eine Position pro Balken:

   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);

Checking the trading time range:

   if(!TimeControlHourMinute())
      return(true);

Empfangen von Daten aus dem Indikator. Die Indikatordaten werden an das Array dema übergeben. Mit Hilfe von ArraySetAsSeries wird für dieses die umgekehrte Indizierungsreihenfolge festgelegt (das Array-Element [0] soll dem ganz rechten Balken im Chart entsprechen). Die Daten werden über die nutzerdefinierte Funktion iGetArray empfangen:

   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);

Eröffnungssignal für eine KAUF-Position. Falls erforderlich (die Variable InpReverse speichert den Positions: Reverse-Eingangswert) kann ein Handelssignal umgekehrt werden. Wenn es eine Einschränkung bezüglich der Handelsrichtung gibt (die Variable InpTradeMode speichert den Handelsmodus: der Wert des Eingabeparameters) wird diese berücksichtigt:

//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_SELL;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL");
            return(true);
           }
        }
     }

Der Codeblock für ein VERKAUFS-Signal ist ähnlich. 


7. Erstellen eines EA (Signale für schwebende Aufträge (pending order)) mit dem Konstruktor

Der Name des EA lautet iDEMA Full EA Pending.mq5. Wir öffnen iDEMA Full EA.mq5 und speichern ihn unter dem neuen Namen.

Eine Handelsstrategie wird immer zuerst entwickelt, dann folgt der Code. Lassen Sie uns die im Abschnitt 6 verwendete Strategie leicht abändern: Erstellen Sie den EA (Positionseröffnungssignale) mit dem Konstruktor. Das Positionseröffnungssignal KAUFEN wird durch den schwebenden Auftrag Buy-Stop ersetzt, während bei einem Positionseröffnungssignal VERKAUFEN durch den schwebenden Auftrag Sell-Stop ersetzt wird. Die folgenden Parameter werden für die schwebenden Aufträge verwendet:

  • Pending: Expiration, in minutes (0 -> OFF)  -> 600
  • Pending: Indent  -> 50 — Abstand des schwebenden Auftrags vom aktuellen Preis (wenn der Preis des schwebenden Auftrags nicht explizit festgelegt ist)
  • Pending: Maximum spread (0 -> OFF). -> 12 — Wenn der aktuelle Spread den angegebenen Wert übersteigt, wird der schwebende Auftrag nicht erteilt (der EA wartet auf eine Verringerung des Spreads)
  • Pending: Only one pending  aktivieren/deaktivieren durch das Flag. Only one pending order is allowed in the market -> true
  • Pending: Reverse pending type  aktivieren/deaktivieren durch das Flag. Pending order reverse -> false
  • Pending: New pending -> delete previous ones  Wenn ein schwebender Auftrag erteilt werden soll, dann werden alle anderen schwebenden Aufträge vorher gelöscht -> true

Die Funktion SearchTradingSignals sieht wie folgt aus:

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);
   if(!TimeControlHourMinute())
      return(true);
   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_pending=ArraySize(SPending);
   if(size_need_pending>0)
      return(true);
//---
   if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
     }
//--- SELL Signal
   if(dema[m_bar_current]<dema[m_bar_current+1] && dema[m_bar_current+1]<dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
     }
//---
   /*if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
   int size_need_pending=ArraySize(SPending);
   ArrayResize(SPending,size_need_pending+1);
   if(!InpPendingReverse)
      SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
   else
      SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
   SPending[size_need_pending].indent=m_pending_indent;
   if(InpPendingExpiration>0)
      SPending[size_need_pending].expiration=(long)(InpPendingExpiration*60);
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");*/
//---
   return(true);
  }

Beachten Sie, dass wir den Preis des schwebenden Auftrags nicht auf die SPending-Struktur setzen. Das bedeutet, dass der aktuelle Preis plus Abstand verwendet werden soll.

Wir haben ein Handelssignal erhalten, das erst dann ausgelöst wird (eine Pending Order wurde platziert), wenn der Spread unter den angegebene fällt:

iDEMA Full EA Pending

Abb. 9. iDEMA Full EA Pending


Die dem Artikel beigefügten Dateien:

Name Dateityp Beschreibung
Indikatoren Code EA Variablen zum Speichern von Handles, Indikatoreingaben, Indikatorerstellungsblöcke
Add indicator.mq5 EA Beispiel für die Arbeit mit Add indicator.mq5 Hinzufügen eines Standardindikators
Add custom indicator.mq5 EA
Beispiel für das Hinzufügen eines nutzerdefinierten Indikators
Trading engine 4.mq5 EA Konstruktor
iDEMA Full EA.mq5
EA
Erstellen eines EAs mit Hilfe des Konstruktors Positionseröffnungssignale
iDEMA Full EA Pending.mq5
EA
EA erstellt mit Hilfe des Konstruktors Pending Order Placement Signale

Schlussfolgerung

Ich hoffe, dass dieser Satz von Handelsfunktionen Ihnen helfen wird, zuverlässigere Expert Advisors zu erstellen, die für die sich ständig ändernden Handelsbedingungen des Marktes bereit sind. Zögern Sie nicht, mit den Parametern zu experimentieren. Sie können Ihre Strategie drastisch verändern, indem Sie einige Parameter aktivieren, während Sie andere deaktivieren.


Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/9717

Beigefügte Dateien |
Indicators_Code.mq5 (88.76 KB)
Add_indicator.mq5 (4.55 KB)
Trading_engine_4.mq5 (177.98 KB)
iDEMA_Full_EA.mq5 (177.93 KB)
MQL5 Kochbuch – Der Wirtschaftskalender MQL5 Kochbuch – Der Wirtschaftskalender
Der Artikel hebt die Programmierfunktionen des Wirtschaftskalenders hervor und befasst sich mit der Erstellung einer Klasse für einen vereinfachten Zugriff auf die Kalendereigenschaften und den Empfang der Ereigniswerte. Als praktisches Beispiel dient die Entwicklung eines Indikators, der die nicht-kommerziellen Nettopositionen der CFTC verwendet.
Grafiken in der Bibliothek DoEasy (Teil 88): Grafische Objektkollektion — zweidimensionales dynamisches Array zur Speicherung der sich dynamisch ändernden Objekteigenschaften Grafiken in der Bibliothek DoEasy (Teil 88): Grafische Objektkollektion — zweidimensionales dynamisches Array zur Speicherung der sich dynamisch ändernden Objekteigenschaften
In diesem Artikel werde ich eine dynamische mehrdimensionale Array-Klasse erstellen, die die Möglichkeit bietet, die Datenmenge in jeder Dimension zu ändern. Auf der Grundlage der erstellten Klasse werde ich ein zweidimensionales dynamisches Array erstellen, um einige dynamisch veränderte Eigenschaften von grafischen Objekten zu speichern.
Ein manuelles Chart- und Handelswerkzeug (Teil III). Optimierungen und neue Werkzeuge Ein manuelles Chart- und Handelswerkzeug (Teil III). Optimierungen und neue Werkzeuge
In diesem Artikel werden wir die Idee des Zeichnens von grafischen Objekten auf Charts mit Hilfe von Tastenkombinationen weiterentwickeln. Der Bibliothek wurden neue Werkzeuge hinzugefügt, darunter eine gerade Linie, die durch beliebige Scheitelpunkte gezeichnet wird, und eine Reihe von Rechtecken, die die Auswertung der Umkehrzeit und des Levels ermöglichen. Außerdem zeigt der Artikel die Möglichkeit, den Code zu optimieren, um die Leistung zu verbessern. Das Implementierungsbeispiel wurde umgeschrieben, sodass Shortcuts neben anderen Handelsprogrammen verwendet werden können. Erforderliche Code-Kenntnisse: etwas höher als die eines Anfängers.
Die Verwendung von AutoIt mit MQL5 Die Verwendung von AutoIt mit MQL5
Kurzbeschreibung. In diesem Artikel befassen wir uns mit dem Skripting des MetraTrader 5-Terminals durch die Integration von MQL5 mit AutoIt. Es wird gezeigt, wie man verschiedene Aufgaben durch Manipulation der Benutzeroberfläche des Terminals automatisieren kann, und es wird eine Klasse vorgestellt, die die AutoItX-Bibliothek verwendet.