English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
Handelsoperationen in MQL5 - Nichts leichter als das

Handelsoperationen in MQL5 - Nichts leichter als das

MetaTrader 5Beispiele | 27 Januar 2016, 12:26
8 839 0
MetaQuotes
MetaQuotes

Kaum ein Händler dürfte nicht auf dem Markt aktiv sein, um Geld zu verdienen, obwohl ein sich gewisser Teil vielleicht auch an der Teilnahme am Handelsgeschehen selbst erfreut. Aber Freude daran vermittelt nicht nur der manuelle Handel. Die Entwicklung automatischer Handelssysteme kann genauso begeisternd sein. Die Erstellung eines automatischen Expert-Systems für den Handel kann ein ebenso fesselndes Erlebnis sein, wie einen Krimi zu lesen.

Wenn man einen Handelsalgorithmus entwickelt, muss man sich mit der Lösung einer Unmenge technischer Fragen herumschlagen, darunter auch den wichtigsten:

  1. Was handeln?
  2. Wann handeln?
  3. Wie handeln?

Die Antwort auf die erste Frage ist für die Wahl des passenden Finanzinstrumentes unerlässlich. Diese Wahl ist von zahlreichen Faktoren abhängig einschließlich der Möglichkeit der Automatisierung des Handelssystems für den betreffenden Markt. Die zweite Frage bezieht sich auf die Formulierung von Handelsregeln, in denen die Zeitpunkte und Richtungen für den Markteinstieg und das Schließen von Positionen klar und deutlich angegeben werden. Vor diesem Hintergrund lautet die dritte Frage schlicht, wie werden die Kauf- und Verkaufsoperationen in dieser Programmiersprache abgewickelt?

In diesem Beitrag werden wir untersuchen, wie Handelsoperationen im algorithmengestützten Handel mithilfe von MQL5 umgesetzt werden.


Was bringt MQL5 für den algorithmengestützten Handel?

Bei MQL5 handelt es sich um eine Programmiersprache für Handelsstrategien, sie verfügt über zahlreiche Handelsfunktionen für die Arbeit mit Aufträgen, Positionen und Handelsanfragen. Deshalb ist die Erstellung automatischer algorithmengestützter Handelssysteme in MQL5 aus Entwicklersicht weitaus weniger arbeitsaufwendig.

Mit MQL5 können Sie eine Handelsanfrage anlegen und sie mithilfe der Funktionen OrderSend() oder OrderSendAsync() an einen Server übermitteln, das Ergebnis ihrer Verarbeitung empfangen, sich den Handelsverlauf anzeigen lassen, die Vertragsvorgaben für ein Kürzel studieren, ein Handelsereignis verarbeiten und weitere benötigte Informationen beziehen.

Außerdem können Sie in MQL5 eigene technische Indikatoren programmieren und die bereits angelegten verwenden sowie beliebige Markierungen und Objekte in Diagramme einzeichnen, eigene Benutzeroberflächen erstellen u. v. a. m. Aber das ist ein anderes Thema, zu dem zahlreiche Artikel interessante Umsetzungsbeispiele bieten.


Handelsoperationen - ein Kinderspiel!

Es gibt einige grundlegende Arten von Handelsoperationen, die Sie für Ihr automatisches Handelssystem benötigen werden:

  1. Kaufen/Verkaufen zum aktuellen Kurs;
  2. Platzieren einer Pending Order für den Kauf/Verkauf unter bestimmten Bedingungen;
  3. Ändern/Löschen einer Pending Order;
  4. Schließen/Aufstocken/Herabsetzen/Umkehren einer Position.

Diese Operationen werden alle mithilfe der Funktion OrderSend() ausgeführt. Es gibt auch noch eine asynchrone Variante dieser Funktion, sie heißt OrderSendAsync(). Die gesamte Vielfalt der Handelsoperationen wird von dem Gerüst MqlTradeRequest angegeben, das die Beschreibung der Handelsanfrage enthält. Deshalb können die einzigen Schwierigkeiten mit Handelsoperationen lediglich im richtigen Füllen des MqlTradeRequest-Gerüsts sowie in der Verarbeitung des Ergebnisses der Anfrageausführung bestehen.

Entsprechend den Regeln Ihres Handelssystems können Sie einen Kauf oder Verkauf zum Marktkurs abschließen (BUY oder SELL) oder etwas abseits des aktuellen Marktkurses eine Pending Kauf- bzw. Verkaufsorder platzieren:

  • BUY STOP, SELL STOP - Kauf oder Verkauf bei Durchbrechen einer vorgegebenen Grenze (ungünstiger als der aktuelle Kurs);
  • BUY STOP, SELL STOP - Kauf oder Verkauf bei Erreichen einer vorgegebenen Grenze (günstiger als der aktuelle Kurs);
  • BUY STOP LIMIT, SELL STOP LIMIT - Erteilen BUY LIMIT- oder SELL LIMIT-Auftrags bei Erreichen eines vorgegebenen Kurses.

Die Arten dieser Standardaufträge entsprechen der Aufzählung ENUM_ORDER_TYPE



Es kann außerdem sein, dass Sie eine Pending Order anpassen oder sogar löschen müssen. Auch das geschieht unter Verwendung der Funktionen OrderSend() oder OrderSendAsync(). Die Anpassung einer eröffneten Position dürfte ebenfalls keine Schwierigkeiten bereiten, da sie infolge der Ausführung derselben Handelsoperationen erfolgt.

Wenn Sie bisher gedacht haben, Handelsoperationen seien kompliziert und verwirrend, ist es jetzt an der Zeit, Ihre Meinung zu ändern. Wir werden nicht nur vorführen, wie schnell und einfach Käufe und Verkäufe in MQL5 zu programmieren sind, sondern Ihnen darüber hinaus auch vormachen, wie man mit einem Handelskonto und den Eigenschaften der Kürzel arbeitet. Dabei helfen uns die Handelsklassen.


CAccountInfo zur Überprüfung Ihres Handelskontos

Vor allem anderen benötigt man beim Starten eines automatischen Handelssystems Informationen über das Handelskonto, auf dem gehandelt wird. Da wir einen Übungscode programmieren, sehen wir eine Prüfung für den Fall vor, dass das Expert-System unvorhergesehen auf einem echten Konto gestartet wird.

Für die Arbeit mit einem Konto gibt es die eigens dazu entwickelte Klasse CAccountInfo. Wir binden in unseren Code zusätzlich die Datei AccountInfo.mqh ein und zeichnen die Variable dieser Klasse als account aus:

#include <Trade\AccountInfo.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- object for working with the account
   CAccountInfo account;
//--- receiving the account number, the Expert Advisor is launched at
   long login=account.Login();
   Print("Login=",login);
//--- clarifying account type
   ENUM_ACCOUNT_TRADE_MODE account_type=account.TradeMode();
//--- if the account is real, the Expert Advisor is stopped immediately!
   if(account_type==ACCOUNT_TRADE_MODE_REAL)
     {
      MessageBox("Trading on a real account is forbidden, disabling","The Expert Advisor has been launched on a real account!");
      return(-1);
     }
//--- displaying the account type    
   Print("Account type: ",EnumToString(account_type));
//--- clarifying if we can trade on this account
   if(account.TradeAllowed())
      Print("Trading on this account is allowed");
   else
      Print("Trading on this account is forbidden: you may have entered using the Investor password");
//--- clarifying if we can use an Expert Advisor on this account
   if(account.TradeExpert())
      Print("Automated trading on this account is allowed");
   else
      Print("Automated trading using Expert Advisors and scripts on this account is forbidden");
//--- clarifying if the permissible number of orders has been set
   int orders_limit=account.LimitOrders();
   if(orders_limit!=0)Print("Maximum permissible amount of active pending orders: ",orders_limit);
//--- displaying company and server names
   Print(account.Company(),": server ",account.Server());
//--- displaying balance and current profit on the account in the end
   Print("Balance=",account.Balance(),"  Profit=",account.Profit(),"   Equity=",account.Equity());
   Print(__FUNCTION__,"  completed"); //---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }

Wie der Code zeigt, können mithilfe der Variablen account in der Funktion OnInit() zahlreiche nützliche Informationen bezogen werden. Sie können Ihrem Expert-System diesen Code hinzufügen, das wird Ihnen die Auswertung der Protokolle bei der Analyse seiner Arbeit erheblich erleichtern.

Die folgende Abbildung zeigt das Ergebnis der Arbeit eines Expert-Systems auf einem Wettbewerbskonto bei der Automated Trading Championship 2012:



CSymbolInfo für Angaben zu dem betreffenden Kürzel

Die Informationen über das Konto haben wir erhalten, aber zur Ausführung von Handelsoperationen fehlen uns noch die Eigenschaften des Kürzels, mit dem wir handeln wollen. Auch dafür gibt es eine geeignete Klasse, nämlich CSymbolInfo, mit einer Vielzahl von Methoden. In unserem Beispiel werden wir nur einen kleinen Teil vorstellen.

#include<Trade\SymbolInfo.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- object for receiving symbol settings
   CSymbolInfo symbol_info;
//--- set the name for the appropriate symbol
   symbol_info.Name(_Symbol);
//--- receive current rates and display
   symbol_info.RefreshRates();
   Print(symbol_info.Name()," (",symbol_info.Description(),")",
         "  Bid=",symbol_info.Bid(),"   Ask=",symbol_info.Ask());
//--- receive minimum freeze levels for trade operations
   Print("StopsLevel=",symbol_info.StopsLevel()," pips, FreezeLevel=",
         symbol_info.FreezeLevel()," pips");
//--- receive the number of decimal places and point size
   Print("Digits=",symbol_info.Digits(),
         ", Point=",DoubleToString(symbol_info.Point(),symbol_info.Digits()));
//--- spread info
   Print("SpreadFloat=",symbol_info.SpreadFloat(),", Spread(current)=",
         symbol_info.Spread()," pips");
//--- request order execution type for limitations
   Print("Limitations for trade operations: ",EnumToString(symbol_info.TradeMode()),
         " (",symbol_info.TradeModeDescription(),")");
//--- clarifying trades execution mode
   Print("Trades execution mode: ",EnumToString(symbol_info.TradeExecution()),
         " (",symbol_info.TradeExecutionDescription(),")");
//--- clarifying contracts price calculation method
   Print("Contract price calculation: ",EnumToString(symbol_info.TradeCalcMode()),
         " (",symbol_info.TradeCalcModeDescription(),")");
//--- sizes of contracts
   Print("Standard contract size: ",symbol_info.ContractSize(),
         " (",symbol_info.CurrencyBase(),")");
//--- minimum and maximum volumes in trade operations
   Print("Volume info: LotsMin=",symbol_info.LotsMin(),"  LotsMax=",symbol_info.LotsMax(),
         "  LotsStep=",symbol_info.LotsStep());
//--- 
   Print(__FUNCTION__,"  completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }

Die Abbildung zeigt die Eigenschaften des Kürzels EURUSD in dem Wettbewerb Automated Trading Championship. Somit wären wir bereit, in den Handel einzusteigen.



CTrade - die geeignete Klasse für Handelsoperationen

Der Handel erfolgt in MQL5 lediglich durch zwei Funktionen, OrderSend() und OrderSendAsync(). Eigentlich handelt es sich dabei jedoch nur um zwei unterschiedliche Umsetzungen einer einzigen Funktion. Während OrderSend() eine Handelsanfrage abschickt und auf das Ergebnis von deren Erfüllung wartet, schickt die asynchrone Funktion OrderSendAsync() die Anfrage einfach ab und gestattet dem Programm weiterzuarbeiten, ohne auf eine Antwort des Handelsservers zu warten. Es ist also wirklich einfach, in MQL5 zu handeln, da eine Funktion für alle Handelsoperationen reicht.

Worin besteht dann die Herausforderung? Beide Funktionen erhalten als ersten Parameter das Gerüst MqlTradeRequest mit über zehn Feldern. Dabei müssen nicht unbedingt alle Felder gefüllt werden. Die Auswahl der erforderlichen Felder hängt von der Art der Handelsoperation ab. Die Angabe eines falschen Wertes oder ein freigelassenes Pflichtfeld führt zu einem Fehler, und die Anfrage wird schlicht nicht an den Server verschickt. 5 dieser Felder erfordern die Angabe korrekter Werte aus vorgegebenen Aufzählungen.

Diese große Zahl Felder ist durch die Notwendigkeit bedingt, in einer Handelsanfrage zahlreiche Eigenschaften des Auftrags anzugeben. Diese können wiederum je nach Ausführungsweise, Ablaufzeit und anderen Parametern variieren. Aber Sie müssen all diese Feinheiten nicht unbedingt lernen. Verwenden Sie einfach die vorgefertigte Klasse CTrade. In etwa folgendermaßen kann ihre Anwendung in Ihrem automatischen Handelssystem aussehen:

#include<Trade\Trade.mqh>
//--- object for performing trade operations
CTrade  trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- set MagicNumber for your orders identification
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- set available slippage in points when buying/selling
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- order filling mode, the mode allowed by the server should be used
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- logging mode: it would be better not to declare this method at all, the class will set the best mode on its own
   trade.LogLevel(1); 
//--- what function is to be used for trading: true - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);
//---
   return(0);
  }

Jetzt ist der richtige Zeitpunkt, um zu sehen, wie CTrade Handelsoperationen unterstützt.

Kauf/Verkauf zum aktuellen Kurs

Häufig muss der Kauf oder Verkauf zum aktuellen Kurs in Handelsstrategien umgehend abgeschlossen werden. CTrade ist damit vertraut und fragt lediglich nach dem erforderlichen Umfang der Handelsoperation. Alle übrigen Parameter (der Eröffnungskurs, die Bezeichnung des Kürzels, die Stop Loss- und Take Profit-Grenzen sowie die Kommentare zu dem Auftrag) können weggelassen werden.

//--- 1. example of buying at the current symbol
   if(!trade.Buy(0.1))
     {
      //--- failure message
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Als Voreinstellung verwendet CTrade die Bezeichnung des Kürzels, in dessen Diagramm sie aufgerufen wird, sofern keine andere Kürzelbezeichnung angegeben ist. Das ist bei einfachen Strategien recht angenehm. Bei Strategien mit mehreren Währungen muss das jeweilige Kürzel, für das die Handelsoperation ausgeführt werden soll, jedes Mal ganz genau angegeben werden.

//--- 2. example of buying at the specified symbol
   if(!trade.Buy(0.1,"GBPUSD"))
     {
      //--- failure message
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Es können alle Auftragsparameter angegeben werden: Die Stop Loss-/Take Profit-Grenze, der Eröffnungskurs und die Kommentare.

//--- 3. example of buying at the specified symbol with specified SL and TP
   double volume=0.1;         // specify a trade operation volume
   string symbol="GBPUSD";    //specify the symbol, for which the operation is performed
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // number of decimal places
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // point
   double bid=SymbolInfoDouble(symbol,SYMBOL_BID);             // current price for closing LONG
   double SL=bid-1000*point;                                   // unnormalized SL value
   SL=NormalizeDouble(SL,digits);                              // normalizing Stop Loss
   double TP=bid+1000*point;                                   // unnormalized TP value
   TP=NormalizeDouble(TP,digits);                              // normalizing Take Profit
//--- receive the current open price for LONG positions
   double open_price=SymbolInfoDouble(symbol,SYMBOL_ASK);
   string comment=StringFormat("Buy %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(open_price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
   if(!trade.Buy(volume,symbol,open_price,SL,TP,comment))
     {
      //--- failure message
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Es sei daran erinnert, dass die magische Zahl (Magic Number) und der zulässige Schlupf (Slippage) bei der Bereitstellung der CTrade-Instanz festgelegt worden sind. Deshalb sind sie hier nicht erforderlich. Obwohl sie erforderlichenfalls dennoch unmittelbar vor jeder Handelsoperation angegeben werden können.

Platzieren eines begrenzten Auftrags (Limit Order)

Zur Platzierung eines begrenzten Auftrages werden die entsprechenden Methoden der Klasse BuyLimit() oder SellLimit() verwendet. In der Mehrzahl der Fälle kann die verkürzte Variante ausreichen, in der nur der Eröffnungskurs und der Umfang angegeben werden. Der Eröffnungskurs muss bei einem Buy Limit unter dem aktuellen Kurs liegen, während er bei einem Sell Limit höher sein muss. Das heißt, diese Aufträge werden für einen Markteinstieg zum jeweils besten Kurs für gewöhnlich in mit einem Rückprall von der Unterstützungslinie rechnenden Strategien verwendet. Dabei kommt das Kürzel zum Einsatz, für das das Expert-System gestartet wurde:

//--- 1. example of placing a Buy Limit pending order
   string symbol="GBPUSD";    // specify the symbol, at which the order is placed
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // number of decimal places
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // point
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // current buy price
   double price=1000*point;                                   // unnormalized open price
   price=NormalizeDouble(price,digits);                       // normalizing open price
//--- everything is ready, sending a Buy Limit pending order to the server
   if(!trade.BuyLimit(0.1,price))
     {
      //--- failure message
      Print("BuyLimit() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("BuyLimit() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Es kann auch die umfassendere Variante verwendet werden, in der alle Parameter anzugeben sind: Die SL-/TP-Grenze, die Ablaufzeit, die Bezeichnung des Kürzels sowie die Kommentare zu dem jeweiligen Auftrag.

//--- 2. example of placing a Buy Limit pending order with all parameters
   double volume=0.1;
   string symbol="GBPUSD";    // specify the symbol, at which the order is placed
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // number of decimal places
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // point
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // current buy price
   double price=1000*point;                                 // unnormalized open price
   price=NormalizeDouble(price,digits);                      // normalizing open price
   int SL_pips=300;                                         // Stop Loss in points
   int TP_pips=500;                                         // Take Profit in points
   double SL=price-SL_pips*point;                           // unnormalized SL value
   SL=NormalizeDouble(SL,digits);                            // normalizing Stop Loss
   double TP=price+TP_pips*point;                           // unnormalized TP value
   TP=NormalizeDouble(TP,digits);                            // normalizing Take Profit
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Limit %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- everything is ready, sending a Buy Limit pending order to the server
   if(!trade.BuyLimit(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
     {
      //--- failure message
      Print("BuyLimit() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("BuyLimit() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

In der zweiten Variante besteht Ihre Aufgabe darin, die SL- und die TP-Grenze richtig anzugeben. Dabei ist nicht zu vergessen, dass die Take Profit-Grenze bei Käufen höher sein muss als der Eröffnungskurs, die Stop Loss-Grenze dagegen niedriger. Bei Sell Limit-Aufträgen verhält es sich genau andersherum. Sie werden etwaige Fehler bei der Überprüfung Ihres Expert-Systems anhand der Verlaufsdaten schnell erkennen. Die Klasse CTrade gibt in einem solchen Fall automatisch eine Fehlermeldung aus (es sei denn, Sie haben selbst die Funktion LogLevel aufgerufen).

Platzieren einer Stop Order

Zum Platzieren einer Stop Order werden die vergleichbaren Methoden BuyStop() bzw. SellStop() verwendet. Der Eröffnungskurs muss bei einem Buy Stop über dem aktuellen Kurs liegen, während er bei einem Sell Stop niedriger sein muss. Stop Orders kommen in Strategien zum Einsatz, die beim Durchbrechen einer bestimmten Widerstandsgrenze einsteigen, sowie zur Begrenzung etwaiger Verluste. Hier ist eine einfache Variante:

//--- 1. example of placing a Buy Stop pending order
   string symbol="USDJPY";    // specify the symbol, at which the order is placed
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // number of decimal places
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // point
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // current buy price
   double price=1000*point;                                    // unnormalized open price
   price=NormalizeDouble(price,digits);                        // normalizing open price
//--- everything is ready, sending a Buy Stop pending order to the server 
   if(!trade.BuyStop(0.1,price))
     {
      //--- failure message
      Print("BuyStop() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("BuyStop() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Und hier eine ausführlichere, bei der das Maximum der Parameter für eine Pending Buy Stop-Order angegeben werden muss:

//--- 2. example of placing a Buy Stop pending order with all parameters
   double volume=0.1;
   string symbol="USDJPY";    // specify the symbol, at which the order is placed
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // number of decimal places
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // point
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // current buy price
   double price=1000*point;                                   // unnormalized open price
   price=NormalizeDouble(price,digits);                       // normalizing open price
   int SL_pips=300;                                          // Stop Loss in points
   int TP_pips=500;                                          // Take Profit in points
   double SL=price-SL_pips*point;                            // unnormalized SL value
   SL=NormalizeDouble(SL,digits);                             // normalizing Stop Loss
   double TP=price+TP_pips*point;                            // unnormalized TP value
   TP=NormalizeDouble(TP,digits);                             // normalizing Take Profit
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Stop %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- everything is ready, sending a Buy Stop pending order to the server 
   if(!trade.BuyStop(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
     {
      //--- failure message
      Print("BuyStop() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("BuyStop() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Für den Versand eines Sell Stop-Auftrages wird die entsprechende Methode der Klasse CTrade angewendet. Hauptsache, die Kurse werden korrekt angegeben.

Mit Positionen arbeiten

Anstelle der Methoden Buy() und Sell() können auch die Methoden zur Eröffnung einer Position verwendet werden, aber dann müssen weitere Angaben gemacht werden:

//--- number of decimal places
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- point value
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- receiving a buy price
   double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
//--- calculate and normalize SL and TP levels
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
//--- filling comments
   string comment="Buy "+_Symbol+" 0.1 at "+DoubleToString(price,digits);
//--- everything is ready, trying to open a buy position
   if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,price,SL,TP,comment))
     {
      //--- failure message
      Print("PositionOpen() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("PositionOpen() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Zum Schließen einer Position reicht die Angabe der Bezeichnung des Kürzels, den Rest erledigt die Klasse CTrade selbst.

//--- closing a position at the current symbol
   if(!trade.PositionClose(_Symbol))
     {
      //--- failure message
      Print("PositionClose() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("PositionClose() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Zur Änderung einer eröffneten Position stehen lediglich die Stop Loss- und die Take Profit-Grenze zur Verfügung. Das geschieht mithilfe der Methode PositionModify().

//--- number of decimal places
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- point value
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- receiving the current Bid price
   double price=SymbolInfoDouble(_Symbol,SYMBOL_BID);
//--- calculate and normalize SL and TP levels
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
//--- everything is ready, trying to modify the buy position
   if(!trade.PositionModify(_Symbol,SL,TP))
     {
      //--- failure message
      Print("Метод PositionModify() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("PositionModify() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Änderung oder Löschung eines Auftrags

Für die Änderung der Parameter einer Pending Order ist in der Klasse CTrade die Methode OrderModify() vorgesehen, an die alle erforderlichen Parameter zu übertragen sind.

//--- this is a sample order ticket, it should be received
   ulong ticket=1234556;
//--- this is a sample symbol, it should be received
   string symbol="EURUSD";
//--- number of decimal places
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- point value
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
//--- receiving a buy price
   double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
//--- calculate and normalize SL and TP levels
//--- they should be calculated based on the order type
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
   //--- setting one day as a lifetime
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);   
//--- everything is ready, trying to modify the order 
   if(!trade.OrderModify(ticket,price,SL,TP,ORDER_TIME_GTC,expiration))
     {
      //--- failure message
      Print("OrderModify() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("OrderModify() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Sie benötigen den Auftragszettel (das Ticket) des zu ändernden Auftrags. Je nach Art des Auftrags müssen die richtigen Stop Loss- und Take Profit-Grenzen angegeben. Außerdem muss auch der neue Eröffnungskurs im richtigen Verhältnis zum aktuellen Kurs sein.

Zum Löschen einer Pending Order reicht es aus, seinen Auftragszettel zu kennen:

//--- this is a sample order ticket, it should be received
   ulong ticket=1234556;
//--- everyrging is ready, trying to modify a buy position
   if(!trade.OrderDelete(ticket))
     {
      //--- failure message
      Print("OrderDelete() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("OrderDelete() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

In der Klasse gibt es auch die universelle Methode OrderOpen(), mit der Pending Orders aller Art platziert werden können. Anders als bei den spezialisierten Methoden BuyLimit, BuyStop, SellLimit und SellStop sind hier mehr Pflichtparameter anzugeben. Vielleicht finden Sie sie ja besser.


Was ist noch zu klären?

So, damit können wir zwei der drei Fragen schon einmal beantworten. Sie haben das Finanzinstrument selbst ausgesucht, an dem Ihre Strategie arbeiten soll, in diesem Beitrag haben wir gezeigt, wie einfach es ist, in einem automatischen Handelssystem Kauf- und Verkaufsoperationen sowie die Verarbeitung von Pending Orders zu programmieren. In dem Abschnitt „Handelsklassen“ befinden sich jedoch noch einige hilfreiche und angenehme Hilfen für MQL5-Entwickler:

  • COrderInfo für die Arbeit mit Aufträgen (Orders);
  • CHistoryOrderInfo für die Arbeit mit ausgeführten Aufträgen aus dem Handelsverlauf;
  • CPositionInfo für die Arbeit mit Positionen;
  • CDealInfo für die Arbeit mit Abschlüssen;
  • CTerminalInfo zum Abruf von Informationen über die Anwendung (Terminal) (es lohnt sich!).

Dank dieser Klassen können Sie sich ausschließlich auf die Handelsseite Ihrer Strategie konzentrieren und alle technischen Fragen auf ein Minimum reduzieren. Außerdem kann die Klasse CTrade zur Abwägung von Handelsanfragen benutzt werden. Mit der Zeit werden Sie imstande sein, auf ihrer Grundlage eigene Handelsklassen zu erstellen, in denen Sie Logik umsetzen, die Sie zur Verarbeitung der Ausführungsergebnisse von Handelsanfragen benötigen.

Bleibt die letzte Frage, wie empfängt man Handelssignale, und wie programmiert man das in MQL5. Der Großteil der Neueinsteiger in den algorithmengestützten Handel beginnt mit dem Studium einfacher klassischer Handelssysteme, etwa den Signalen an den Schnittpunkten gleitender Durchschnittswerte. Dazu muss man lernen, mit technischen Indikatoren zu arbeiten, wie man sie in einem automatischen Handelssystem anlegt und nutzt.

Wir empfehlen die Lektüre der Beiträge der Bereiche Indikatoren und Beispiele -> Indikatoren in chronologischer Reihenfolge. So gelangen Sie nach und nach von den einfachen zu den komplexeren. Um sich schnell eine Vorstellung von der Arbeit mit technischen Indikatoren zu verschaffen, lesen Sie MQL5 für Neueinsteiger: Leitfaden zur Verwendung technischer Indikatoren in Expert Advisors.


Komplizierte Dinge einfach machen

Bei allem Neuen erweisen sich die ersten Schwierigkeiten nach kurzer Zeit als die einfachsten Sachen, mit denen man zu tun hat. Die hier vorgestellten Verfahren zur Entwicklung automatischer Handelssysteme in MQL5 richten sich in erster Linie an Neueinsteiger, aber auch erfahrenere Entwickler finden hier möglicherweise etwas Neues und Nützliches.

MQL5 bietet nicht nur unbegrenzte Möglichkeiten für den algorithmengestützten Handel sondern ermöglicht jedem, sie auf höchst einfache und schnelle Weise umzusetzen. Benutzen Sie die Handelsklassen aus der Standardbibliothek, um Zeit für Wichtigeres zu sparen, zum Beispiel, um die Antwort auf die ewige Frage aller Händler zu suchen: Was ist ein Trend, und wie findet man ihn in Echtzeit?

Glauben Sie mir, es ist wesentlich einfacher, in MQL5 ein automatisches Handelssystem zu entwickeln, als eine Fremdsprache zu lernen oder dem Trend zu folgen!


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

Beigefügte Dateien |
demo_ctrade.mq5 (1.98 KB)
Auftragsstrategien. Ein universelles automatisches Handelssystem Auftragsstrategien. Ein universelles automatisches Handelssystem
In diesem Beitrag dreht sich alles um Strategien, in denen bedingte Aufträge (Pending Orders) intensiv genutzt werden, um eine Metasprache, die geschaffen werden kann, um diese Strategien in Formelsprache zu beschreiben, und um die Verwendung eines universellen automatischen Handelssystems, dessen Arbeitsweise auf diesen Beschreibungen beruht.
Schneller Einstieg in MQL5 Schneller Einstieg in MQL5
Sie haben sich entschlossen, zur Programmierung von Handelsstrategien MQL5 zu lernen, wissen aber noch nichts darüber? Wir haben versucht, MQL5 und die MetaTrader 5-Anwendung aus der Sicht eines Neueinsteigers zu betrachten, und daraufhin diese kurze Einführung geschrieben. In diesem Beitrag finden Sie ein grobe Darstellung der Möglichkeiten der Programmiersprache sowie einige Hinweise für die Arbeit mit dem Bearbeitungsprogramm MetaEditor 5 und der MetaTrader 5-Anwendung auf Ihrem Rechner.
Schnelleinstieg oder Kurzanleitung für Anfänger Schnelleinstieg oder Kurzanleitung für Anfänger
Liebe Leser, in diesem Artikel möchte ich Ihnen vermitteln und zeigen, wie man sich möglichst schnell und einfach die Grundlagen der Erstellung automatischer Handelssysteme, wie die Arbeit mit Indikatoren u. a., erschließt. Der Beitrag richtet sich an Neueinsteiger, in ihm kommen weder komplizierte noch schwer zu verstehende Beispiele zur Anwendung.
Erstellung eines automatischen Handelssystems ohne Zeitverlust Erstellung eines automatischen Handelssystems ohne Zeitverlust
Der Handel auf den Finanzmärkten ist mit einer Vielzahl von Risiken verbunden, unter denen das gefährlichste darin besteht, eine falsche Handelsentscheidung zu treffen. Jeder Händler träumt davon, sich selbst durch ein automatisches Handelssystem zu ersetzen, eine Maschine, stets in Bestform, unerschöpflich und frei von menschlichen Schwächen wie Angst, Raffgier und Ungeduld.