MQL5-Kochbuch: Verarbeitung des TradeTransaction-Ereignisses

Denis Kirichenko | 13 Juni, 2016

Einleitung

In diesem Artikel würde ich sehr gerne eine der beiden Möglichkeiten ansprechen, Handelsereignisse mittels der Instrumente und Tools von MQL5 zu kontrollieren. Es sei vorsorglich erwähnt, dass bereits einige wenige Artikel zu diesem Thema existieren. „Handelsereignisse im Expert-Advisor mit Hilfe der OnTrade()-Funktion bearbeiten“ ist einer von Ihnen. Ich werde an dieser Stelle nicht dazu übergehen, die Worte anderer Autoren zu wiederholen. Ich werde vielmehr auf einen anderen Behandler vertrauen: OnTradeTransaction().

Erlauben Sie mir kurz, Ihre Aufmerksamkeit auf einen weiteren Punkt zu lenken. Die aktuelle Version der MQL5-Sprache zählt offiziell 14 Ereignisbehandler des Kundenterminals. Zusätzlich haben Programmierer die Möglichkeit, eigene benutzerspezifische Ereignisse via EventChartCustom() zu kreieren und diese per OnChartEvent() zu verarbeiten. Allerdings taucht der Terminus „ereignisgesteuertes Programmieren“ (EDP) innerhalb der gesamten Dokumentation nicht ein einziges Mal auf. Das ist zweifellos merkwürdig, bedenkt man den Umstand, dass ein jedes MQL5-Programm auf den Prinzipien von EDP basiert. So muss der Benutzer zum Beispiel während des Schritts „Ereignisbehandler für den EA“ im Template eines EAs eine Entscheidung treffen.

Es ist geradezu offensichtlich, dass verschiedene Mechanismen ereignisgesteuerten Programmierens in MQL5 auf die ein oder andere Weise verwendet werden. Die Sprache enthält womöglich einige Programmblöcke, die aus zwei Teilen bestehen: Auswahl und Verarbeitung von Ereignissen. Mehr noch: Wenn wir über Kundenterminalereignisse reden, so hat ein Programmierer nur Kontrolle über den zweiten Teil. Gleichwohl gibt es - wie so oft - auch für diese Regel einige Ausnahmen. D.h., für einige Ereignisse gilt dies nicht. Hierunter befinden sich beispielsweise Timer und benutzerspezifische Ereignisse. Programmierer besitzen die vollständige Kontrolle über derartige Ereignisse.

1. Das TradeTransaction-Ereignis

Bevor wir noch weiter in das Thema eindringen, möchte ich zunächst noch kurz auf einige offizielle Informationen verweisen.

Entsprechend der Dokumentation stellt das TradeTransaction-Ereignis das Resultat verschiedener Operationen dar, die mit einem Handelskonto ausgeführt worden sind. Eine Operation selbst besteht aus einer Zahl der Phasen, die durch Transaktionen bestimmt werden. So wird beispielsweise das Öffnen einer Position mit einem Marktauftrag, eine der beliebtesten Handelskontooperationen, auf folgende Weise durchgeführt:

  1. Senden einer Tradinganfrage;
  2. Verifizierung dieser Anfrage;
  3. Senden der Anfrage an den Server;
  4. Erhalten einer Antwort über die Ausführung dieses Handelsauftrags durch den Server.

Solch eine Sequenz zeigt allerdings nur die Logik des Arbeitens mit einem Terminalserverpaar auf - die findet sich ferner in den Strings des EA-Codes. Aus Sicht des Handelsereignis TradeTransaction wird eine Marktposition auf die folgende Weise geöffnet:

  1. Das MQL5-Programm erhält seitens des Servers eine Nachricht über das Ergebnis der erfolgreichen Anfrage;
  2. Die Anfrage wird in Form eines Auftrags mit einem einzigartigen Ticket in die Liste der offenen Aufträge aufgenommen;
  3. Nach der Durchführung wird der Auftrag aus der Liste der offenen Aufträge gelöscht;
  4. Dann wandert der Auftrag in die Kontohistorie;
  5. Die Kontohistorie enthält ferner Daten bzgl. des Deals, in dem die Auftragsausführung endet.

Das heißt, um eine Position zu öffnen, sind insgesamt fünf Aufrufe des OnTradeTransaction()-Behandlers notwendig.

Wir werden den Programmcode ein wenig später noch etwas detaillierter besprechen. Für den Moment werden wir uns zunächst dem Header der Funktion zuwenden. Dieser weist drei Eingabeparameter auf.

void  OnTradeTransaction(
   const MqlTradeTransaction&    trans,        // structure of the trade transaction
   const MqlTradeRequest&        request,      // structure of the request
   const MqlTradeResult&         result        // structure of the response
   );

Diese Parameter werden in der Dokumentation detailliert beschrieben, wodurch ich mir dies an dieser Stelle sparen kann. Ich möchte sehr gerne hinzufügen, dass ein Parameter einer Handelstransaktionsstruktur in gewisser Weise den Informationen ähnelt, die ein Behandler während des aktuellen Aufrufs erhält.

Außerdem möchte ich sehr gerne noch einige Worte über den Typ der Handelstransaktionen verlieren, die uns später begegnen werden.

Was MQL5 betrifft, so ist ENUM_TRADE_TRANSACTION_TYPE ein spezieller Aufzählungstyp, der für den Typ der Handelstransaktion verantwortlich ist. Um herauszufinden, welchem Typ eine Handelstransaktion zugehörig ist, müssen wir auf die Parameterkonstante des Typs MqlTradeTransaction verweisen.

struct MqlTradeTransaction
  {
   ulong                         deal;             // Ticket of the deal
   ulong                         order;            // Ticket of the order
   string                        symbol;           // Trade symbol
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Type of the trade transaction
   ENUM_ORDER_TYPE               order_type;       // Type of the order
   ENUM_ORDER_STATE              order_state;      // Status of the order
   ENUM_DEAL_TYPE                deal_type;        // Type of the deal
   ENUM_ORDER_TYPE_TIME          time_type;        // Order expiration type
   datetime                      time_expiration;  // Order expiration time
   double                        price;            // Price 
   double                        price_trigger;    // Price that triggers the Stop Limit order
   double                        price_sl;         // Level of Stop Loss
   double                        price_tp;         // Level of Take Profit
   double                        volume;           // Volume in lots
  };

Das vierte Strukturfeld ist genau die Aufzählung, nach der wir suchen.

2. Die Verarbeitung von Positionen

Nahezu alle Handelsoperationen, die die Verarbeitung von Positionen betreffen, bringen einen fünffachen Aufruf des Behandlers OnTradeTransaction() mit sich. Hierzu zählen:

  • Öffnen einer Position;
  • Position;
  • Umkehrung von Positionen;
  • einer Position Lots hinzufügen;
  • teilweise Schließung einer Position.

Das Modifizieren einer Position ist die einzige Handelsoperation, die den Ereignisbehandler TradeTransaction zwei Mal aufruft.

Da es keine Informationen darüber gibt, welche Transaktionstypen für eine bestimmte Handelsoperation verantwortlich sind, müssen wir uns der Trial-and-Error-Methode bedienen.

Bevor wir dies tun, müssen wir zuerst ein Template des EAs anlegen, das den TradeTransaction-Ereignisbehandler enthält. Ich habe meine Version dieses Templates auf den Namen TradeProcessor.mq5 getauft. Ich habe außerdem ein Feature hinzugefügt, das es ermöglicht, Informationen über die Werte des Strukturfelds im Log anzuzeigen. Diese Werte sind die Parameter des Ereignisbehandlers. Eine Analyse dieser Aufzeichnungen wird zweifellos eine Menge Zeit in Anspruch nehmen. Am Ende werden wir allerdings in Form des gesamten, umfassenden Bildes eines Ereignisses belohnt werden.

Wir müssen den EA im Debugmodus auf irgendeinen der MetaTrader-5-Terminalcharts anwenden und starten.

Dann öffnen wir manuell eine Position und sehen uns den Code an. Der erste Aufruf des Behandlers sieht wie folgt aus (Abb. 1).

Abb. 1 Das Typenfeld ist identisch mit TRADE_TRANSACTION_REQUEST

Abb. 1 Das Typenfeld ist identisch mit TRADE_TRANSACTION_REQUEST

Die folgenden Einträge werden im Log erscheinen:

IO      0       17:37:53.233    TradeProcessor (EURUSD,H1)      ---===Transaction===---
NK      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
RR      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
DE      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ticket of the order: 0
JS      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
JN      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
FD      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Price: 0.0000
FN      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
HF      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
FQ      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
RR      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Trade symbol: 
HD      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
GS      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
DN      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Type of the trade transaction TRADE_TRANSACTION_REQUEST
FK      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Volume in lots: 0.00

In diesem Block interessieren uns lediglich die Aufzeichnungen hinsichtlich des Transaktionstyps. Wie wir sehen, gehört dieser Typ zu der Anfrage TRADE_TRANSACTION_REQUEST.

Informationen über die Anfragendetails können in dem Block „Anfragen“ eingesehen werden.

QG      0       17:37:53.233    TradeProcessor (EURUSD,H1)      ---===Request===--- HL      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Type of the trade operation: TRADE_ACTION_DEAL EE      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Comment to the order: JP      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Deviation from the requested price: 0 GS      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Order expiration time: 1970.01.01 00:00 LF      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Magic number of the EA: 0 FM      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869 EJ      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Price: 1.3137 QR      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Stop Loss level of the order: 0.0000 IJ      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Take Profit level of the order: 0.0000 KK      0       17:37:53.233    TradeProcessor (EURUSD,H1)      StopLimit level of the order: 0.0000 FS      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Trade symbol: EURUSD RD      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY

Daten über die Resultate der Anfragenausführung finden sich demgegenüber in dem Block „Antworten“.

KG      0       17:37:53.233    TradeProcessor (EURUSD,H1)      ---===Response===---
JR      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Code of the operation result: 10009
GD      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ticket of the deal: 15258202
NR      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869
EF      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Volume of the deal: 0.11
MN      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Price of the deal: 1.3137
HJ      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Bid: 1.3135
PM      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Ask: 1.3137
OG      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Comment to the operation: 
RQ      0       17:37:53.233    TradeProcessor (EURUSD,H1)      Request ID: 1

Nach einer Analyse anderer Parameter des Behandlers - wie beispielsweise Strukturen der Anfragen und Antworten - können Sie zusätzliche Informationen über die Anfragen während des ersten Aufrufs erhalten.

Der zweite Aufruf betrifft das Hinzufügen von Aufträgen zur Liste der offenen Aufträge (Abb. 2).

Abb. 2 Das Typenfeld ist identisch mit  TRADE_TRANSACTION_ORDER_ADD

Abb. 2 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_ADD

Der Block „Transaktion“ ist der einzige, den wir im Log benötigen.

MJ      0       17:41:12.280    TradeProcessor (EURUSD,H1)      ---===Transaction===---
JN      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
FG      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
LM      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869
LI      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
LP      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
QN      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Price: 1.3137
PD      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
NL      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
PG      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
DL      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Trade symbol: EURUSD
JK      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
QD      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
IQ      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD
PL      0       17:41:12.280    TradeProcessor (EURUSD,H1)      Volume in lots: 0.11

Der Auftrag hat, wie wir sehen können, bereits sein Ticket und andere Parameter (Symbol, Preis und Volumen) erhalten und befindet sich nun in der Liste der offenen Aufträge.

Der dritte Aufruf des Ereignisbehandlers steht mit der Löschung des Auftrags aus der Liste der öffnen Aufträge in Verbindung (Abb. 3).

Abb. 3 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_DELETE

Abb. 3 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_DELETE

Der Block „Transaktion“ ist der einzige, den wir im Log benötigen.

PF      0       17:52:36.722    TradeProcessor (EURUSD,H1)      ---===Transaction===---
OE      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
KL      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
EH      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869
QM      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
QK      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
HS      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Price: 1.3137
MH      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
OP      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
EJ      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
IH      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Trade symbol: EURUSD
KP      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
LO      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
HG      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_ORDER_DELETE
CG      0       17:52:36.722    TradeProcessor (EURUSD,H1)      Volume in lots: 0.11

In diesem Block gibt es keine neuen Informationen außer denjenigen über den Typ der Transaktion.

Der Behandler wird zum vierten Mal aufgerufen, wenn ein neuer historischer Auftrag in der Historienliste erscheint (Abb. 4).

Abb. 4 Das Typenfeld ist identisch mit TRADE_TRANSACTION_HISTORY_ADD

Abb. 4 Das Typenfeld ist identisch mit TRADE_TRANSACTION_HISTORY_ADD

Wir können die relevanten Informationen vom Block „Transaktion“ erhalten.

QO      0       17:57:32.234    TradeProcessor (EURUSD,H1)      ---===Transaction==---
RJ      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
NS      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
DQ      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869
EH      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_FILLED
RL      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
KJ      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Price: 1.3137
NO      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
PI      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
FS      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
JS      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Trade symbol: EURUSD
LG      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
KP      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
OL      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_HISTORY_ADD
JH      0       17:57:32.234    TradeProcessor (EURUSD,H1)      Volume in lots: 0.00

In diesem Stadium können wir erkennen, dass der Auftrag ausgeführt wurde.

Was schließlich den fünften und letzten Aufruf betrifft, so findet dieser dann statt, wenn ein Deal zur Historienliste hinzugefügt wird (Abb. 5).

Abb. 5  Das Typenfeld ist identisch mit TRADE_TRANSACTION_DEAL_ADD

Abb. 5 Das Typenfeld ist identisch mit TRADE_TRANSACTION_DEAL_ADD

Am Log interessiert uns - erneut - nur der Block „Transaktion“.

OE      0       17:59:40.718    TradeProcessor (EURUSD,H1)      ---===Transaction===---
MS      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Ticket of the deal: 15258202
RJ      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
HN      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535869
LK      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
LE      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
MM      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Price: 1.3137
PF      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
NN      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
PI      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
DJ      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Trade symbol: EURUSD
JM      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
QI      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
CK      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_DEAL_ADD
RQ      0       17:59:40.718    TradeProcessor (EURUSD,H1)      Volume in lots: 0.11

Der wichtige String dieses Blocks ist das Ticket des Deals.

Ich werde nun damit beginnen, ein Schema der Transaktion skizzieren. Für Positionen gibt es derer nur zwei. Das erste sieht wie das der Abbildung 6 aus.

Abb. 6 Das erste Schema des Transaktionsprozesses

Abb. 6 Das erste Schema des Transaktionsprozesses

Alle Handelsoperationen, die mit der Verarbeitung von Positionen in Verbindung stehen, ereignen sich gemäß dieses Schemas. Die einzige Ausnahme: die Operation zur Modifizierung einer Position. Die letzte Operation beinhaltet die Verarbeitung der folgenden zwei Transaktionen (Abb. 7).

Abb. 7 Das zweite Schema des Transaktionsprozesses

Abb. 7 Das zweite Schema des Transaktionsprozesses

Die Modifikation einer Position kann also in der Historienliste der Deals und Aufträge nicht zurückverfolgt werden.

So viel zu Positionen.

3. Die Verarbeitung einer Pending-Order

Was Pending-Orders angeht, sollte gesagt werden, dass sämtliche Operationen, die mit ihnen in Verbindung stehen, weniger Transaktionen benötigen. Zur gleichen Zeit gibt es mehr Kombinationen an Transaktionstypen, wenn mit Aufträgen gearbeitet wird.

Um einen Auftrag zu modifizieren, wird der Behandler zwei Mal aufgerufen - ähnlich der Modifikation einer Position. Das Platzieren und Löschen eines Auftrags benötigt drei Aufrufe. Das Ereignis TradeTransaction tritt vier Mal während der Löschung oder Ausführung eines Auftrags auf.

Mit dieser Funktion wird eine Pending-Order platziert. Wir müssen den EA erneut im Debugmodus auf irgendeinen der MetaTrader-5-Terminalcharts anwenden und starten.

Der erste Aufruf des Behandlers wird mit der Anfrage verknüpft sein (Abb. 8).

Abb. 8 Das Typenfeld ist identisch mit TRADE_TRANSACTION_REQUEST

Abb. 8 Das Typenfeld ist identisch mit TRADE_TRANSACTION_REQUEST

Die Protokolldatei enthält die folgenden Zeilen:

IO      0       18:13:33.195    TradeProcessor (EURUSD,H1)      ---===Transaction===---
NK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
RR      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
DE      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ticket of the order: 0
JS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
JN      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY
FD      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Price: 0.0000
FN      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
HF      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
FQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
RR      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Trade symbol: 
HD      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
GS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
DN      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_REQUEST
FK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Volume in lots: 0.00
NS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      

QG      0       18:13:33.195    TradeProcessor (EURUSD,H1)      ---===Request==---
IQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Type of the trade operation: TRADE_ACTION_PENDING
OE      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Order comment: 
PQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Deviation from the requested price: 0
QS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Order expiration time: 1970.01.01 00:00
FI      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Magic number of the EA: 0
CM      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535983
PK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Price: 1.6500
KR      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Stop Loss level of the order: 0.0000
OI      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Take Profit level of the order: 0.0000
QK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      StopLimit level of the order: 0.0000
QQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Trade symbol: GBPUSD
RD      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY_LIMIT
LS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Order execution type: ORDER_FILLING_RETURN
MN      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
IK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Volume in lots: 0.14
NS      0       18:13:33.195    TradeProcessor (EURUSD,H1)      
CD      0       18:13:33.195    TradeProcessor (EURUSD,H1)      ---===Response===---
RQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Code of the operation result: 10009
JI      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
GM      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535983
LF      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Volume of the deal: 0.14
JN      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Price of the deal: 0.0000
MK      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Bid: 0.0000
CM      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Ask: 0.0000
IG      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Comment to the operation: 
DQ      0       18:13:33.195    TradeProcessor (EURUSD,H1)      Request ID: 1

Der zweite Aufruf des Behandlers wird den Auftrag zur Liste der offenen Aufträge hinzufügen (Abb. 9).

Abb. 9 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_ADDED

Abb. 9 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_ADDED

Im Log müssen wir uns nur den Block „Transaktion“ zu Gemüte führen.

HJ      0       18:17:02.886    TradeProcessor (EURUSD,H1)      ---===Transaction===---
GQ      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
CH      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
RL      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535983
II      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_STARTED
OG      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY_LIMIT
GL      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Price: 1.6500
IE      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
CO      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
IF      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
PL      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Trade symbol: GBPUSD
OL      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
HJ      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
LF      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD
FR      0       18:17:02.886    TradeProcessor (EURUSD,H1)      Volume in lots: 0.14

Der dritte Aufruf des Behandlers wird die Daten entsprechend des platzierten Auftrags erneuern (Abb. 10).

Insbesondere wird der Auftragsstatus den Wert von ORDER_STATE_PLACED erhalten.

Abb. 10 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_UPDATE

Abb. 10 Das Typenfeld ist identisch mit TRADE_TRANSACTION_ORDER_UPDATE

Im Log müssen wir uns die Aufzeichnungen für den Block „Transaktion“ ansehen.

HS      0       18:21:27.004    TradeProcessor (EURUSD,H1)      ---===Transaction==---
GF      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Ticket of the deal: 0
CO      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Type of the deal: DEAL_TYPE_BUY
RE      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Ticket of the order: 22535983
KM      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Status of the order: ORDER_STATE_PLACED
QH      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Type of the order: ORDER_TYPE_BUY_LIMIT
EG      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Price: 1.6500
GL      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Level of Stop Loss: 0.0000
ED      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Level of Take Profit: 0.0000
GO      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Price that triggers the Stop Limit order: 0.0000
RE      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Trade symbol: GBPUSD
QS      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Pending order expiration time: 1970.01.01 00:00
JS      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Order expiration type: ORDER_TIME_GTC
RD      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Type of the trade transaction: TRADE_TRANSACTION_ORDER_UPDATE
JK      0       18:21:27.004    TradeProcessor (EURUSD,H1)      Volume in lots: 0.14

Der wichtigste String ist hierbei der Status des Auftrags.

Die Verarbeitung von Pending-Orders kann im Gegensatz zur Verarbeitung von Positionen nicht mithilfe eines Schemas umgesetzt werden. Jede Handelsoperation, die im Zusammenhang mit einer Pending-Order steht, wird in Hinblick auf die Handelstransaktionstypen einzigartig sein.

Zum Platzieren einer Pending-Order werden drei Transaktionen benötigt (Abb. 11).

Abb. 11 Transaktionen zur Verarbeitung der Platzierung einer Pending-Order

Abb. 11 Transaktionen zur Verarbeitung der Platzierung einer Pending-Order

Das Modifizieren einer Pending-Order wird zwei Transaktionen generieren (Abb. 12).

Abb. 12 Transaktionen zur Verarbeitung der Modifizierung einer Pending-Order

Abb. 12 Transaktionen zur Verarbeitung der Modifizierung einer Pending-Order

Falls eine Pending-Order gelöscht wird, wird der Behandler OnTradeTransaction() vier Mal aufgerufen werden (Abb. 13).

Abb. 13 Transaktionen zur Verarbeitung des Löschens einer Pending-Order

Abb. 13 Transaktionen zur Verarbeitung des Löschens einer Pending-Order

Das Löschen einer Pending-Order wird durch das folgende Schema definiert (Abb. 14).

Abb. 14 Transaktionen zur Verarbeitung des Löschens einer Pending-Order

Abb. 14 Transaktionen zur Verarbeitung des Löschens einer Pending-Order

Wenn eine Pending-Order ausgelöst wird, dann wird die letzte Handelsoperation vier Transaktionen einleiten (Abb. 15).

Abb. 15 Transaktionen zur Verarbeitung der Aktivierung einer Pending-Order

Abb. 15 Transaktionen zur Verarbeitung der Aktivierung einer Pending-Order

Ich werde an dieser Stelle davon absehen, die Logeinträge hinsichtlich aller möglichen Kombinationen zu zitieren. Falls der Leser die Muße haben sollte, so kann er diese selbst studieren, indem er den Code ausführt.


4. Universalbehandler

Lassen Sie uns mit den Augen eines Endnutzers einen Blick auf das Programm werfen, das mit dem TradeTransaction-Ereignis arbeiten kann. Der Endnutzer benötigt sehr wahrscheinlich ein Programm, dass ohne Probleme mit beidem arbeiten kann - Aufträgen und Positionen. Ein Programmierer muss den Code für OnTradeTransaction() in der Weise schreiben, als dass alle Transaktionen und ihre Kombinationen unabhängig davon, was durchgeführt wurde (Position oder Auftrag), identifiziert werden können. Idealerweise sollte das Programm in der Lage sein, nach dem Abschluss der Verarbeitung einer Serie von Transaktionen auf die Operation hinzudeuten, die letztendlich ausgeführt wurde.

Im unteren Beispiel wird eine sequentielle Verarbeitung der Transaktion verwendet. Der Entwickler von MQL5 äußert sich allerdings wie folgt:

...Eine Handelsanfrage, die manuell vom Terminal oder mittels der Funktionen OrderSend()/OrderSendAsync() gesendet wird, kann auf dem Handelsserver mehrere konsekutive Transaktionen hervorrufen. Da die Priorität des Ankommens dieser Transaktionen beim Terminal nicht gewährleistet wird, sollten Handelsalgorithmen nicht auf der Vermutung basieren, dass eine Gruppe von Transaktionen nach einer anderen ankommen wird. Außerdem können Transaktionen auf dem Weg vom Server in Richtung Terminal verloren gehen...

Das bedeutet, wenn die Notwendigkeit existiert, ein Programm zu schreiben, das möglichst nahe an das Ideal heranreicht, können Sie das vorgeschlagene Beispiel noch weiter verbessern, indem Sie die Verarbeitung der Transaktionen unabhängig von der Ankunft der Auftragstransaktionen gestalten.

Ganz generell gesprochen: Positionen und Aufträge können gemeinsame Transaktionstypen aufweisen. Es gibt insgesamt 11 Typen von Transaktionen. Allerdings haben lediglich vier Stück davon etwas mit dem Trading via Terminal zu tun:

  • TRADE_TRANSACTION_DEAL_UPDATE;
  • TRADE_TRANSACTION_DEAL_DELETE;
  • TRADE_TRANSACTION_HISTORY_UPDATE;
  • TRADE_TRANSACTION_HISTORY_DELETE.

Wir werden sie im vorliegenden Artikel allerdings nicht diskutieren. Diese Typen, so die Entwickler, wurden speziell dafür designt, um eine größere Funktionalität aufseiten des Tradingservers zu gewährleisten. Ich muss gestehen, dass ich in letzter Zeit so gut wie gar nicht mit diesen Typen in Kontakt gekommen bin.

Folglich verbleiben uns sieben vollfunktionale Typen, die am häufigsten in OnTradeTransaction() verarbeitet werden.

Im Body des Behandlers gibt es ein Segment, dass den Typ der aktuellen Transaktion definiert. Ihm kommt eine wichtige Rolle zu.

//--- ========== Types of transaction [START]
   switch(trans_type)
     {
      //--- 1) if it is a request
      case TRADE_TRANSACTION_REQUEST:
        {

         //---
         break;
        }
      //--- 2) if it is an addition of a new open order
      case TRADE_TRANSACTION_ORDER_ADD:
        {

         //---
         break;
        }
      //--- 3) if it is a deletion of an order from the list of open ones
      case TRADE_TRANSACTION_ORDER_DELETE:
        {

         //---     
         break;
        }
      //--- 4) if it is an addition of a new order to the history
      case TRADE_TRANSACTION_HISTORY_ADD:
        {

         //---     
         break;
        }
      //--- 5) if it is an addition of a deal to history
      case TRADE_TRANSACTION_DEAL_ADD:
        {

         //---
         break;
        }
      //--- 6) if it is a modification of a position 
      case TRADE_TRANSACTION_POSITION:
        {

         //---
         break;
        }
      //--- 7) if it is a modification of an open order
      case TRADE_TRANSACTION_ORDER_UPDATE:
        {

         //---
         break;
        }
     }
//--- ========== Types of transactions [END]

Durch diesen Typ definieren wir, welche Handelsoperation wir verarbeiten. Um herauszufinden, womit wir arbeiten - einer Position oder einem Auftrag - werden wir eine Memorisierung des Typs der Handelsoperation in Auftrag geben. Und zwar erteilen wir diesen Auftrag dem Case-Modul, das die Anfrage verarbeitet .

Das Modul selbst sieht so aus:

//--- 1) if it is a request
      case TRADE_TRANSACTION_REQUEST:
        {
         //---
         last_action=request.action;
         string action_str;

         //--- what is the request for?
         switch(last_action)
           {
            //--- а) on market
            case TRADE_ACTION_DEAL:
              {
               action_str="place a market order";
               trade_obj=TRADE_OBJ_POSITION;
               break;
              }
            //--- б) place a pending order
            case TRADE_ACTION_PENDING:
              {
               action_str="place a pending order";
               trade_obj=TRADE_OBJ_ORDER;
               break;
              }
            //--- в) modify position
            case TRADE_ACTION_SLTP:
              {
               trade_obj=TRADE_OBJ_POSITION;
               //---
               StringConcatenate(action_str,request.symbol,": modify the levels of Stop Loss",
                                 " and Take Profit");

               //---
               break;
              }
            //--- г) modify order
            case TRADE_ACTION_MODIFY:
              {
               action_str="modify parameters of the pending order";
               trade_obj=TRADE_OBJ_ORDER;
               break;
              }
            //--- д) delete order
            case TRADE_ACTION_REMOVE:
              {
               action_str="delete pending order";
               trade_obj=TRADE_OBJ_ORDER;
               break;
              }
           }
         //---
         if(InpIsLogging)
            Print("Request received: "+action_str);

         //---
         break;
        }

In diesem Fall ist es nicht besonders schwer, eine Variable zu ändern.

static ENUM_TRADE_REQUEST_ACTIONS last_action; // market operation at the first pass

Der Variable last_action kommt die Aufgabe zu, sich zu merken, warum der Ereignisbehandler überhaupt erst gestartet worden ist.

static ENUM_TRADE_OBJ trade_obj;               // specifies the trade object at the first pass

Die Variable trade_obj wird sich daraufhin merken, was verarbeitet wurde - Position oder Auftrag. Hierfür werden wir die Aufzählung ENUM_TRADE_OBJ anlegen.

Danach heißt es, sich dem Modul zuzuwenden, das die Transaktionen des Typs TRADE_TRANSACTION_ORDER_ADD verarbeitet:

//--- 2) if it is an addition of a new open order
      case TRADE_TRANSACTION_ORDER_ADD:
        {
         if(InpIsLogging)
           {
            if(trade_obj==TRADE_OBJ_POSITION)
               Print("Open a new market order: "+
                     EnumToString(trans.order_type));
            //---
            else if(trade_obj==TRADE_OBJ_ORDER)
               Print("Place a new pending order: "+
                     EnumToString(trans.order_type));
           }
         //---
         break;
        }

Dieses Modul ist verhältnismäßig simpel. Da im ersten Schritt eine Position verarbeitet wurde, wirr ein Logeintrag namens „Öffnen eines neuen Marktauftrags“ erscheinen. Andernfalls tritt ein „Eine-neue-Pending-Order-platzieren“-Eintrag auf. In diesem Block finden lediglich Aktionen statt, die informieren.

Nun wird es für das dritte Modul Zeit, das den Typ TRADE_TRANSACTION_ORDER_DELETE verarbeitet:

//--- 3) if it is a deletion of an order from the list of open ones
      case TRADE_TRANSACTION_ORDER_DELETE:
        {
         if(InpIsLogging)
            PrintFormat("Order deleted from the list of open ones: #%d, "+
                        EnumToString(trans.order_type),trans.order);
         //---     
         break;
        }

Auch diesem Modul kommt eine informative Rolle zu.

Das vierte Case-Modul verarbeitet den Typ TRADE_TRANSACTION_HISTORY_ADD:

//--- 4) if it is an addition of a new order to the history
      case TRADE_TRANSACTION_HISTORY_ADD:
        {
         if(InpIsLogging)
            PrintFormat("Order added to the history: #%d, "+
                        EnumToString(trans.order_type),trans.order);

         //--- if a pending order is being processed
         if(trade_obj==TRADE_OBJ_ORDER)
           {
            //--- if it is the third pass
            if(gTransCnt==2)
              {
               //--- if the order was canceled, check the deals
               datetime now=TimeCurrent();

               //--- request the history of orders and deals
               HistorySelect(now-PeriodSeconds(PERIOD_H1),now);

               //--- attempt to find a deal for the order
               CDealInfo myDealInfo;
               int all_deals=HistoryDealsTotal();
               //---
               bool is_found=false;
               for(int deal_idx=all_deals;deal_idx>=0;deal_idx--)
                  if(myDealInfo.SelectByIndex(deal_idx))
                     if(myDealInfo.Order()==trans.order)
                        is_found=true;

               //--- if the deal was not found
               if(!is_found)
                 {
                  is_to_reset_cnt=true;
                  //---
                  PrintFormat("Order canceled: #%d",trans.order);
                 }
              }
            //--- if it is the fourth pass
            if(gTransCnt==3)
              {
               is_to_reset_cnt=true;
               PrintFormat("Order deleted: #%d",trans.order);
              }
           }
         //---     
         break;
        }

Zusätzlich zu der Aufzeichnung, dass der Auftrag zur Historie hinzugefügt wurde, überprüft dieses Modul, ob zu Anfang mit einer Pending-Order gearbeitet worden ist oder nicht. Falls dies getan worden ist, so müssen wir die Zahl des aktuellen Durchlaufs des Behandlers ermitteln. Das Problem hierbei ist das Folgende: Dieser Transaktionstyp kann im Falle des Arbeitens mit einem Auftrag während des dritten Durchlaufs auftreten, falls eine Pending-Order rückgängig gemacht wurde. Falls dieser Typ während des vierten Durchgangs auftritt, so wurde eine Pending-Order gelöscht.

Was die Strings betrifft, die den dritten Durchgang überprüfen, müssen wir erneut auf die Historie der Deals verweisen. Falls ein Deal für einen aktuellen Auftrag nicht gefunden wird, können wir solch einen Auftrag als rückgängig gemacht betrachten.

Das fünfte Case-Modul verarbeitet den TRADE_TRANSACTION_DEAL_ADD-Typ. Besieht man sich die Größe der Strings, so handelt es sich definitiv um den größten der Programmblöcke.

In diesem Block wird der Deal überprüft. Es ist dabei wichtig, einen Deal mithilfe des Tickets auszuwählen, um Zugriff auf die Eigenschaften zu erhalten. Der Typ eines Deals besitzt Informationen darüber, ob eine Position geöffnet, geschlossen oder etwas anderes wurde. Außerdem finden sich hier Informationen darüber, ob eine Pending-Order ausgelöst wurde. Dies ist der einzige Fall, in dem eine Pending-Order einen Deal im Kontext des Arbeitens des Ereigisbehandlers TradeTransaction generieren könnte.

//--- 5) if it is an addition of a deal to history
      case TRADE_TRANSACTION_DEAL_ADD:
        {
         is_to_reset_cnt=true;
         //---
         ulong deal_ticket=trans.deal;
         ENUM_DEAL_TYPE deal_type=trans.deal_type;
         //---
         if(InpIsLogging)
            PrintFormat("Deal added to history: #%d, "+EnumToString(deal_type),deal_ticket);

         if(deal_ticket>0)
           {
            datetime now=TimeCurrent();

            //--- request the history of orders and deals
            HistorySelect(now-PeriodSeconds(PERIOD_H1),now);

            //--- select a deal by the ticket
            if(HistoryDealSelect(deal_ticket))
              {
               //--- check the deal
               CDealInfo myDealInfo;
               myDealInfo.Ticket(deal_ticket);
               long order=myDealInfo.Order();

               //--- parameters of the deal
               ENUM_DEAL_ENTRY  deal_entry=myDealInfo.Entry();
               double deal_vol=0.;
               //---
               if(myDealInfo.InfoDouble(DEAL_VOLUME,deal_vol))
                  if(myDealInfo.InfoString(DEAL_SYMBOL,deal_symbol))
                    {
                     //--- position
                     CPositionInfo myPos;
                     double pos_vol=WRONG_VALUE;
                     //---
                     if(myPos.Select(deal_symbol))
                        pos_vol=myPos.Volume();

                     //--- if the market was entered
                     if(deal_entry==DEAL_ENTRY_IN)
                       {
                        //--- 1) opening of a position
                        if(deal_vol==pos_vol)
                           PrintFormat("\n%s: new position opened",deal_symbol);

                        //--- 2) addition to the open position        
                        else if(deal_vol<pos_vol)
                           PrintFormat("\n%s: addition to the current position",deal_symbol);
                       }

                     //--- if the market was exited
                     else if(deal_entry==DEAL_ENTRY_OUT)
                       {
                        if(deal_vol>0.0)
                          {
                           //--- 1) closure of a position
                           if(pos_vol==WRONG_VALUE)
                              PrintFormat("\n%s: position closed",deal_symbol);

                           //--- 2) partial closure of the open position        
                           else if(pos_vol>0.0)
                              PrintFormat("\n%s: partial closing of the current position",deal_symbol);
                          }
                       }

                     //--- if position was reversed
                     else if(deal_entry==DEAL_ENTRY_INOUT)
                       {
                        if(deal_vol>0.0)
                           if(pos_vol>0.0)
                              PrintFormat("\n%s: position reversal",deal_symbol);
                       }
                    }

               //--- order activation
               if(trade_obj==TRADE_OBJ_ORDER)
                  PrintFormat("Pending order activation: %d",order);
              }
           }

         //---
         break;
        }

Der Transaktionstyp RADE_TRANSACTION_POSITION ist einzigartig und wird nur dann verarbeitet, wenn eine Position modifiziert wird:

//--- 6) if it is a modification of a position
      case TRADE_TRANSACTION_POSITION:
        {
         is_to_reset_cnt=true;
         //---
         PrintFormat("Modification of a position: %s",deal_symbol);
         //---
         if(InpIsLogging)
           {
            PrintFormat("New price of stop loss: %0."+
                        IntegerToString(_Digits)+"f",trans.price_sl);
            PrintFormat("New price of take profit: %0."+
                        IntegerToString(_Digits)+"f",trans.price_tp);
           }

         //---
         break;
        }

Das letzte Case-Modul wird während der Verarbeitung des Typs TRADE_TRANSACTION_ORDER_UPDATE aktiviert.

Dieser Typ scheint nur für Pending-Orders zu funktionieren. Er wird gestartet, sobald eine beliebige Handelsoperation betreffend die Pending-Orders ausgelöst wird - allerdings variiert die Phase.

//--- 7) if it is a modification of an open order
      case TRADE_TRANSACTION_ORDER_UPDATE:
        {

         //--- if it was the first pass
         if(gTransCnt==0)
           {
            trade_obj=TRADE_OBJ_ORDER;
            PrintFormat("Canceling the order: #%d",trans.order);
           }
         //--- if it was the second pass
         if(gTransCnt==1)
           {
            //--- if it is an order modification
            if(last_action==TRADE_ACTION_MODIFY)
              {
               PrintFormat("Pending order modified: #%d",trans.order);
               //--- clear counter
               is_to_reset_cnt=true;
              }
            //--- if it is deletion of the order
            if(last_action==TRADE_ACTION_REMOVE)
              {
               PrintFormat("Delete pending order: #%d",trans.order);

              }
           }
         //--- if it was the third pass
         if(gTransCnt==2)
           {
            PrintFormat("A new pending order was placed: #%d, "+
                        EnumToString(trans.order_type),trans.order);
            //--- clear counter
            is_to_reset_cnt=true;
           }

         //---
         break;
        }

Zusammengefasst: Falls dieser Typ während des ersten Auslösens von OnTradeTransaction() erscheint, dann wurde der Auftrag entweder rückgängig gemacht oder aber ausgeführt.

Falls der Typ während des zweiten Ausführens des Ereignisbehandlers erscheint, dann wurde der Auftrag entweder gelöscht oder modifiziert. Um herauszufinden, worin der Auftrag nun genau resultierte, müssen Sie auf die statische Variable last_action verweisen, die die Daten der letzten Handelsoperation enthält.

Die dritte Ausführung des Ereignisbehandlers ist der letzte Fall, in dem dieser Typ auftreten kann. Die dritte Ausführung schließt die Prozedur des Platzierens von Pending-Orders ab.

Außerdem wird die boolesche Variable is_to_reset_cnt im Code verwendet. Ihr kommt dabei die Rolle einer Flagge zum Säubern von Countern der Durchgänge des Behandlers OnTradeTransaction() zu.

Das wäre soweit alles, was Sie über die Verarbeitung des Ereignisses TradeTransaction wissen müssen. Ich würde übrigens ferner eine Pause zum Beginn des Behandleraufrufs einfügen. Sie dient dazu, die Chance zu minimieren, dass ein Deal oder ein Auftrag mit einer gewissen Verzögerung in die Historienliste aufgenommen wird.


Fazit

Innerhalb dieses Artikels habe ich den Versuch unternommen, zu illustrieren, wie man mit verschiedenen Handelsoperationen umgeht und wie man Informationen über bestimmte Terminalgeschehnisse ausliest.

Der größte Vorteil dieses Ansatzes besteht darin, dass das Programm Informationen über die schrittweise Umsetzung von Handelsoperationen empfangen kann. Meiner Meinung nach eignet sich solch ein Ansatz vorzüglich dafür, Deals von einem Terminal in Richtung eines anderen zu kopieren.