English Русский 中文 Español 日本語 Português
Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll

Welche Überprüfungen der Handelsroboter vor der Veröffentlichung in Market bestehen soll

MetaTrader 5Beispiele | 24 August 2016, 13:17
2 475 0
MetaQuotes
MetaQuotes

Wofür die Überprüfung vor der Veröffentlichung in Market nötig ist

Alle Markets Produkte vor der Veröffentlichung bestehen eine obligatorische vorläufige Überprüfung, da ein kleiner Fehler in der Logik des EAs oder des Indikators zu den Verlusten auf dem Handelskonto führen kann. Gerade deshalb von uns wurde eine Serie der grundlegenden Überprüfungen entwickelt, die das notwendige Niveau der Qualität der Markets Produkte gewährleisten.

Wenn im Laufe der Überprüfung Ihres Produktes von den Markets Moderatoren die Fehler gefunden werden, so müssen Sie unbedingt diese Fehler korrigieren. In diesem Artikel werden wir von den häufigsten Fehlern erzählen, die die Hersteller in den Handelsrobotern und den technischen Indikatoren machen. Wir empfehlen auch den folgenden Artikeln zu lesen:

Wie man Fehler schnell im Handelsroboter herausfinden und korrigieren soll

Der in der Plattform eingebaute Strategietesters ermöglicht Handelssysteme nicht nur auf der History zu prüfen, sondern findet auch die logischen und Algorithmenfehler heraus, die bei der Schreibung des Handelsroboters gemacht wurden. Während der Prüfung werden alle Benachrichtigungen von den Handelsoperationen und den gezeigten Fehlern im Journal des Testers gezeigt. Diese Benachrichtigungen für die Analyse bequem, in speziellem Logs Viewer zu betrachten, der vom Befehl des kontextabhängigen Menüs gerufen wird.


Öffnen Sie nach dem Test des EAs den Viewer und machen Sie den Modus "Nur die Fehler" an, wie es in Abb gezeigt ist. Wenn es in Ihrem Handelsroboter Fehler gibt, Sie werden sie sofort sehen. Wenn die Fehler am ersten Mal nicht gefunden wurden, führen Sie eine Serie der Tests mit dem Wechsel der Instrumente/Timeframe/Eingangsparameter und verschiedenen Werte des Anfangsdeposites durch. 99 % der Fehler zeigen sich durch diese einfachen Annahmen, und wir erzählen von ihnen in diesem Artikel.

Für die ausführliche Betrachtung des gezeigten Fehlers verwenden Sie in MetaEditor das Austesten auf der History — so im Modus des visuellen Tests können Sie nicht nur die Preise-Graphik und die Werte der verwendeten Indikatoren beobachten, sondern auch die Werte jeder Variable im Programm auf jedem Tick verfolgen. Es wird Ihnen ermöglichen, Ihre Handelsstrategie ohne wochendauernde Zeitverlust im online Modus auszutesten.

Der Mangel an Mittel für die Durchführung der Handelsoperationen

Vor jeder Abgabe der Handelsorder muss man die Zulänglichkeit der Mittel auf seinem Konto prüfen. Der Mangel an Mittel für die Versorgung der zukünftigen offenen Position oder der Order wird als grober Fehler angenommen.

Nehmen Sie in Acht, dass sogar für die Setzung einer Pending-Order eine Pfandversorgung — Marge verlangt werden kann.


Wir empfehlen den eigenen Handelsrobot auf wissentlich kleiner Größe der Anfangsdeposite zu testen, zum Beispiel, auf 1 USD oder 1 Euro.

Wenn die Überprüfung gezeigt hat, dass Mittel für die Durchführung der Handelsoperation nicht ausreichend sind, ist es notwendig, statt dem Aufruf der Funktion OrderSend(), ins Journal die Benachrichtigung über den Fehler auszugeben. Die Beispiele der Überprüfung:

MQL5

bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
  {
//--- Erhalten wir den Eröffnungspreis
   MqlTick mqltick;
   SymbolInfoTick(symb,mqltick);
   double price=mqltick.ask;
   if(type==ORDER_TYPE_SELL)
      price=mqltick.bid;
//--- Die Werte der notwendigen und freien Marge
   double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   //--- Rufen wir die Funktion der Überprüfung auf
   if(!OrderCalcMargin(type,symb,lots,price,margin))
     {
      //--- etwas ging schief, berichten wir es und geben false zurück
      Print("Error in ",__FUNCTION__," code=",GetLastError());
      return(false);
     }
   //--- wenn es Mittel für die Durchführung der Handelsoperationen nicht ausreichend sind
   if(margin>free_margin)
     {
      //--- berichten wir über den Fehler und geben false zurück
      Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
      return(false);
     }
//--- die Überprüfung ist erfolgreich gelaufen 
   return(true);
  }

MQL4

bool CheckMoneyForTrade(string symb, double lots,int type)
  {
   double free_margin=AccountFreeMarginCheck(symb,type,lots);
   //-- wenn es Geldmittel nicht ausreichend sind
   if(free_margin<0)
     {
      string oper=(type==OP_BUY)? "Buy":"Sell";
      Print("Not enough money for ", oper," ",lots, " ", symb, " Error code=",GetLastError());
      return(false);
     }
   //-- die Überprüfung ist erfolgreich gelaufen
   return(true);
  }

Die falschen Volumen in den Handelsoperationen

Vor der Abgabe der Handelsorder muss man auch die Korrektheit der Volumen prüfen, die in den Ordern angegeben werden. Die Anzahl der Lots, die der EA in der Order geben will, muss überprüft werden, bevor die Funktion OrderSend() aufgerufen wird. Für die Finanzinstrumente in der Spezifikation werden die minimalen und maximalen erlaubten Volumen für den Handel gegeben, sowie die Gradation der Volumen. Die Werte in MQL5 kann man aus der Aufzählung ENUM_SYMBOL_INFO_DOUBLE mit Hilfe der Funktion SymbolInfoDouble()
bekommen

SYMBOL_VOLUME_MIN

Der minimalen Volumen für den Abschluss des Trades

SYMBOL_VOLUME_MAX

Der maximalen Volumen für den Abschluss des Trades

SYMBOL_VOLUME_STEP

Der minimale Schritt für den Abschluss des Trades

Das Beispiel der Funktion für die Überprüfung der Korrektheit des Volumens

//+------------------------------------------------------------------+
//|  Überprüft den Volumen der Order auf die Korrektheit             |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &description)
  {
//--- der minimale erlaubte Volumens für die Handelsoperationen
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      description=StringFormat("der Volumen ist weniger den minimalen erlaubten SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- der maximale erlaubte Volumens für die Handelsoperationen
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      description=StringFormat("der Volumen ist mehr den maximalen erlaubten SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- wir bekommen die minimale Gradation des Volumens
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      description=StringFormat("Der Volumen ist divisibel der minimalen Gradation SYMBOL_VOLUME_STEP=%.2f, des nächsten korrekten Volumens %.2f",
                               volume_step,ratio*volume_step);
      return(false);
     }
   description="Der korrekte Wert des Volumens";
   return(true);
  }


Die Beschränkung auf die Anzahl der Pending Orders

Es gibt auch die Beschränkung auf die Anzahl der geltenden Pending Orders, die auf einem Konto gleichzeitig gesetzt werden können . Das Beispiel der Funktion IsNewOrderAllowed(), die überprüft, ob man noch eine Pending Order setzen kann. 

//+------------------------------------------------------------------+
//| Überprüft - ob noch eine Order gesetzt werden kann               |
//+------------------------------------------------------------------+
bool IsNewOrderAllowed()
  {
//--- Bekommen die Anzahl der erlaubten Pending Orders am Konto
   int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);

//---  wenn es keine Beschränkungen gibt - geben true zurück, man kann auch Order absenden
   if(max_allowed_orders==0) return(true);

//--- wenn es bis zu dieser Stelle angekommen ist, bedeutet dies, dass eine Beschränkung gibt, wie viel Order schon gelten
   int orders=OrdersTotal();

//--- geben wir das Ergebnis des Vergleiches zurück
   return(orders<max_allowed_orders);
  }

Die Funktion ist einfach: in der Variable max_allowed_orders bekommen wir die erlaubte Anzahl der Pending Orders, und wenn dieser Wert nicht 0 gleich ist — vergleichen es mit der aktuellen Anzahl der Orders. Allerdings wird diese Funktion noch eine mögliche Beschränkung nicht berücksichtigen — der höchstzulässige vereinte Volumen der offenen Position und der Pending Orders nach einem konkreten Symbol.


Die Beschränkung auf die Anzahl der Lots nach einem Symbol

Um die Größe des Volumens der offenen Position nach dem gegebenen Symbol zu bekommen, muss man vorläufig die Position mit Hilfe der Funktion PositionSelect() wählen. Und nur danach, den Volumen der gewählten Position mit Hilfe der Funktion PositionGetDouble() anzufordern, welche die verschiedene Eigenschaften der gewählten Position, die den Typ double haben, zurückgibt. Für das Erhalten des Volumens der Position nach dem gegebenen Symbol schreiben wir die Funktion PositionVolume()

//+------------------------------------------------------------------+
//| gibt die Größe der Position nach dem gegebenen Symbol zurück     |
//+------------------------------------------------------------------+
double PositionVolume(string symbol)
  {
//--- Versuchen wir die Position nach dem Symbol auszuwählen
   bool selected=PositionSelect(symbol);
//--- es gibt die Position 
   if(selected)
      //--- geben wir den Volumen der Position zurück
      return(PositionGetDouble(POSITION_VOLUME));
   else
     {
      //--- 
      Print(__FUNCTION__," PositionSelect() konnte fürs Symbol nicht ausgeführt werden ",
            symbol," Fehler ",GetLastError());
      return(-1);
     }
  }

Für die Kontos mit der Unterstützung Hedge muss man alle Positionen in diesem Instrumente betrachten.

Vor allem muss man die Handelsanfrage auf die Setzung der Pending Order nach dem Symbol machen, man braucht die Beschränkung auf den höchstzulässige vereinte Volumen der offenen Position und der Pending Orders nach einem konkreten Symbol — SYMBOL_VOLUME_LIMIT zu überprüfen. Wenn die Beschränkung nicht gibt, dann der Volumen der Pending Order den Volumen des maximal gesetzten Volumens nicht überschreiten kann, der mit Hilfe der Funktion SymbolInfoDouble() erhalten werden kann.

double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);
if(max_volume==0) volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);

Aber diese Methode berücksichtigt nicht den Volumen in den aktuellen Orders nach dem eingegebenen Symbol. Führen wir ein Beispiel der Funktion, das dieser Wert berechnet:

//+---------------------------------------------------------------------------------+
//|  gibt das Volumen aktuell platzierter Pending Orders nach Symbol zurück         |
//+---------------------------------------------------------------------------------+
double   PendingsVolume(string symbol)
  {
   double volume_on_symbol=0;
   ulong ticket;
//---  die Anzahl aller aktuell platzierten Orders auf allen Symbolen erhalten
   int all_orders=OrdersTotal();

//--- alle Orders in der Schleife durchlaufen
   for(int i=0;i<all_orders;i++)
     {
      //--- das Ticket der Order nach ihrer Position in der Liste erhalten
      if(ticket=OrderGetTicket(i))
        {
         //--- wenn unser Symbol in der Order angegeben ist, addieren wir das Volumen dieser Order
         if(symbol==OrderGetString(ORDER_SYMBOL))
            volume_on_symbol+=OrderGetDouble(ORDER_VOLUME_INITIAL);
        }
     }
//--- das Gesamtvolumen aller aktuell platzierten Pending Orders für das angegebene Symbol zurückgeben
   return(volume_on_symbol);
  }

Mit der Rücksicht auf den Volumen der offenen Postion und auf den Volumen in den Pending Orders, wird die endgültige Überprüfung so aussehen:

//+---------------------------------------------------------------------------+
//|  Es liefert den maximal erlaubten Volumen für die Order nach dem Symbol   |
//+---------------------------------------------------------------------------+
double NewOrderAllowedVolume(string symbol)
  {
   double allowed_volume=0;
//--- wir bekommen die Beschränkung auf dem maximalen Volumen in der Order 
   double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
//--- wir bekommen die Beschränkung nach dem Symbol auf den Volumen
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);

//--- wir bekommen den Volumen der offenen Position nach dem Symbol
   double opened_volume=PositionVolume(symbol);
   if(opened_volume>=0)
     {
      //--- wenn wir Volumen alle haben
      if(max_volume-opened_volume<=0)
         return(0);

      //--- Der Volumen der offenen Position überschreitet nicht max_volume
      double orders_volume_on_symbol=PendingsVolume(symbol);
      allowed_volume=max_volume-opened_volume-orders_volume_on_symbol;
      if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume;
     }
   return(allowed_volume);
  }


Die Setzung der Ebene TakeProfit und StopLoss innerhalb des minimalen Ebene SYMBOL_TRADE_STOPS_LEVEL

Viele EAs handeln unter Verwendung der Order TakeProfit und StopLoss, deren Ebene dynamisch im Moment der Vollziehung des Kaufes oder des Verkaufes ausgerechnet werden. Die Order TakeProfit dient für die Schließung der Position bei der Bewegung des Preises in die günstige Richtung, während die Order StopLoss wird für die Beschränkung der Verluste bei der Bewegung des Preises in die ungünstige Richtung verwendet.

Deshalb die Ebene TakeProfit und StopLoss muss man mit dem laufenden Preis vergleichen, nach dem man eine Operation nach der gegengesetzten Richtung machen kann:

  • Der Kauf wird beim Preis Ask abgeschlossen — die Ebene TakeProfit und StopLoss muss man mit dem laufenden Verkaufs-Preis Bid vergleichen.
  • Der Verkaufwird beim Preis Bid abgeschlossen — die Ebene TakeProfit und StopLoss muss man mit dem laufenden Kaufs-Preis Ask.
Der Kauf wird beim Preis Ask abgeschlossen
Der Verkauf wird beim Preis Bid abgeschlossen
TakeProfit >= Bid
StopLoss <= Bid
TakeProfit <= Ask
StopLoss >= Ask



Für die Finanzinstrumente in den Einstellungen des Symbols kann der Parameter SYMBOL_TRADE_STOPS_LEVELgegeben sein. Er weist in Punkten auf den minimalen Einzug der Ebene StopLoss und TakeProfit vom laufenden Schließung-Preis der geöffneten Position auf. Wenn der Wert dieser Eigenschaft Null ist, bedeutet dies, der minimale Einzug für SL/TP Order beim Kauf und Verkauf nicht gegeben ist.

Im Allgemeinen, die Überprüfung der Ebene TakeProfit und StopLoss unter Berücksichtigung der minimalen Distanz SYMBOL_TRADE_STOPS_LEVEL sieht so aus:

  • Der Kauf wird beim Preis Ask abgeschlossen— die Ebene TakeProfit und StopLoss müssen vom aktuellen Preis des Verkaufs Bid auf der Distanz mindestens SYMBOL_TRADE_STOPS_LEVEL Punkten sein.
  • Der Verkaufwird beim Preis Bid abgeschlossen — die Ebene TakeProfit und StopLoss müssen vom aktuellen Preis des Kaufs Ask auf der Distanz mindestens SYMBOL_TRADE_STOPS_LEVEL Punkten sein.
Der Kauf wird beim Preis Ask abgeschlossen
Der Verkauf wird beim Preis Bid abgeschlossen
TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL
Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL
Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL
StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL

Deshalb kann man die Funktion der Überprüfung CheckStopLoss_Takeprofit () erstellen, die fordert, dass die Entfernung von TakeProfit und StopLoss bis zum Endpreis nicht weniger als SYMBOL_TRADE_STOPS_LEVEL Punkten wäre:

bool CheckStopLoss_Takeprofit(ENUM_ORDER_TYPE type,double SL,double TP)
  {
//---  Erhalten wir die Ebene SYMBOL_TRADE_STOPS_LEVEL
   int stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
   if(stops_level!=0)
     {
      PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss und TakeProfit dürfen nicht näher"+
                  " als %d Punkten vom Exit-preis",stops_level,stops_level);
     }
//---
   bool SL_check=false,TP_check=false;
//--- Überprüfen wir nur zwei Art der Orders
   switch(type)
     {
      //--- Die Kauf-Operation
      case  ORDER_TYPE_BUY:
        {
         //--- Überprüfen wir StopLoss
         SL_check=(Bid-SL>stops_level*_Point);
         if(!SL_check)
            PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+
                        " (Bid=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d пунктов)",
                        EnumToString(type),SL,Bid-stops_level*_Point,Bid,stops_level);
         //--- Überprüfen wir TakeProfit
         TP_check=(TP-Bid>stops_level*_Point);
         if(!TP_check)
            PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+
                        " (Bid=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d пунктов)",
                        EnumToString(type),TP,Bid+stops_level*_Point,Bid,stops_level);
         //--- geben wir das Ergebnis der Überprüfung zurück
         return(SL_check&&TP_check);
        }
      //--- Die Verkauf-Operation
      case  ORDER_TYPE_SELL:
        {
         //--- Überprüfen wir StopLoss
         SL_check=(SL-Ask>stops_level*_Point);
         if(!SL_check)
            PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f "+
                        " (Ask=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d пунктов)",
                        EnumToString(type),SL,Ask+stops_level*_Point,Ask,stops_level);
         //--- Überprüfen wir TakeProfit
         TP_check=(Ask-TP>stops_level*_Point);
         if(!TP_check)
            PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f "+
                        " (Ask=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d пунктов)",
                        EnumToString(type),TP,Ask-stops_level*_Point,Ask,stops_level);
         //--- geben wir das Ergebnis der Überprüfung zurück
         return(TP_check&&SL_check);
        }
      break;
     }
//--- Für die Pendig-Orders braucht man eine andere Funktion
   return false;
  }

Selbst die Überprüfung kann so aussehen:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Erhalten wir nach zufälliger Weise den Typ der Operation
   int oper=(int)(GetTickCount()%2); // Das Ergebnis der Teilung um zwei ist immer 0 oder 1
   switch(oper)
     {
      //--- Kaufen
      case  0:
        {
         //--- wir werden den Preis der Eröffnung bekommen und setzen wissentlich falsche TP/SL 
         double price=Ask;
         double SL=NormalizeDouble(Bid+2*_Point,_Digits);
         double TP=NormalizeDouble(Bid-2*_Point,_Digits);
         //--- Machen wir die Überprüfung
         PrintFormat("Buy at %.5f   SL=%.5f   TP=%.5f  Bid=%.5f",price,SL,TP,Bid);
         if(!CheckStopLoss_Takeprofit(ORDER_TYPE_BUY,SL,TP))
            Print("Die Ebene StopLoss oder TakeProfit ist falsch angegeben!");
         //--- wir werden dennoch versuchen zu kaufen, um das Ergebnis der Ausführung zu sehen
         Buy(price,SL,TP);
        }
      break;
      //--- kaufen
      case  1:
        {
         //--- wir werden den Preis der Eröffnung bekommen und setzen wissentlich falsche TP/SL 
         double price=Bid;
         double SL=NormalizeDouble(Ask-2*_Point,_Digits);
         double TP=NormalizeDouble(Ask+2*_Point,_Digits);
         //--- Machen wir die Überprüfung
         PrintFormat("Sell at %.5f   SL=%.5f   TP=%.5f  Ask=%.5f",price,SL,TP,Ask);
         if(!CheckStopLoss_Takeprofit(ORDER_TYPE_SELL,SL,TP))
            Print("Die Ebene StopLoss oder TakeProfit ist falsch angegeben!");
         //--- wir werden dennoch versuchen zu verkaufen, um das Ergebnis der Ausführung zu sehen
         Sell(price,SL,TP);
        }
      break;
      //---
     }
  }

Das Beispiel der Funktion finden Sie in hinzugefügten Skripts Check_TP_and_SL.mq4 und Check_TP_and_SL.mq5. Das Beispiel der Ausführung:

MQL5
Check_TP_and_SL (EURUSD,H1) Buy at 1.11433   SL=1.11425   TP=1.11421  Bid=1.11423
Check_TP_and_SL (EURUSD,H1) SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss und TakeProfit dürfen nicht näher als 30 Punkte vom Exit-Preis
Check_TP_and_SL (EURUSD,H1) Für die Order ORDER_TYPE_BUY StopLoss=1.11425 muss es weniger als 1.11393 (Bid=1.11423 - SYMBOL_TRADE_STOPS_LEVEL=30 Punkte sein)
Check_TP_and_SL (EURUSD,H1) Für die Order ORDER_TYPE_BUY TakeProfit=1.11421 muss es mehr als 1.11453 (Bid=1.11423 + SYMBOL_TRADE_STOPS_LEVEL=30 Punkte sein)
Check_TP_and_SL (EURUSD,H1) Die Ebene StopLoss oder TakeProfit ist falsch angegeben!
Check_TP_and_SL (EURUSD,H1) OrderSend error 4756
Check_TP_and_SL (EURUSD,H1) retcode=10016  deal=0  order=0
MQL4
Check_TP_and_SL EURUSD,H1:  Sell at 1.11430   SL=1.11445   TP=1.11449  Ask=1.11447
Check_TP_and_SL EURUSD,H1:  SYMBOL_TRADE_STOPS_LEVEL=1: StopLoss und TakeProfit dürfen nicht näher als 1 Punkte vom Exit-Preis sein
Check_TP_and_SL EURUSD,H1:  Für die Order ORDER_TYPE_SELL StopLoss=1.11445 muss es größer als 1.11448  (Ask=1.11447 + SYMBOL_TRADE_STOPS_LEVEL=1 Punkte sein)
Check_TP_and_SL EURUSD,H1:  Für die Order ORDER_TYPE_SELL TakeProfit=1.11449 muss es weniger als 1.11446  (Ask=1.11447 - SYMBOL_TRADE_STOPS_LEVEL=1 Punkte sein)
Check_TP_and_SL EURUSD,H1: Die Ebene StopLoss oder TakeProfit ist falsch angegeben!
Check_TP_and_SL EURUSD,H1:  OrderSend error 130 

Für die Modellierung der Situation mit falschen Werten TakeProfit und StopLoss wurden zum Artikel die EAs Test_Wrong_TakeProfit_LEVEL.mq5 und Test_Wrong_StopLoss_LEVEL.mq5 hinzugefügt. Sie können nur auf einem Demo-Konto gestartet werden. Lernen Sie die Beispiele, damit Sie selbst erfahren, unter welchen Bedingungen ein erfolgreicher Kauf abgeschlossen werden kann.

Das Beispiel der EA-Ausführung Test_Wrong_StopLoss_LEVEL.mq5:

Test_Wrong_StopLoss_LEVEL.mq5
Point=0.00001 Digits=5
SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT
SYMBOL_TRADE_FREEZE_LEVEL=20: die Order oder die Position wird verboten, zu modifizieren, wenn es 20 Punkte bis zum Preis der Abnutzung blieben
SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss und TakeProfit dürfen nicht näher als 30 Punkte vom Exit-Preis
1. Buy 1.0 EURUSD at 1.11442 SL=1.11404 Bid=1.11430 ( StopLoss-Bid=-26 points ))
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11404 [invalid stops]
2. Buy 1.0 EURUSD at 1.11442 SL=1.11404 Bid=1.11431 ( StopLoss-Bid=-27 points ))
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11404 [invalid stops]
3. Buy 1.0 EURUSD at 1.11442 SL=1.11402 Bid=1.11430 ( StopLoss-Bid=-28 points ))
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11442 sl: 1.11402 [invalid stops]
4. Buy 1.0 EURUSD at 1.11440 SL=1.11399 Bid=1.11428 ( StopLoss-Bid=-29 points ))
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11440 sl: 1.11399 [invalid stops]
5. Buy 1.0 EURUSD at 1.11439 SL=1.11398 Bid=1.11428 ( StopLoss-Bid=-30 points ))
Buy 1.0 EURUSD done at 1.11439 with StopLoss=41 points (spread=12 + SYMBOL_TRADE_STOPS_LEVEL=30)

Das Beispiel der EA-Ausführung Test_Wrong_TakeProfit_LEVEL.mq5:

Test_Wrong_TakeProfit_LEVEL.mq5
Point=0.00001 Digits=5
SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT
SYMBOL_TRADE_FREEZE_LEVEL=20: die Order oder die Position wird verboten, zu modifizieren, wenn es 20 Punkte bis zum Preis der Abnutzung blieben
SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss und TakeProfit dürfen nicht näher als 30 Punkte vom Exit-Preis
1. Buy 1.0 EURUSD at 1.11461 TP=1.11478 Bid=1.11452 (TakeProfit-Bid=26 points)
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11478 [invalid stops]
2. Buy 1.0 EURUSD at 1.11461 TP=1.11479 Bid=1.11452 (TakeProfit-Bid=27 points)
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11479 [invalid stops]
3. Buy 1.0 EURUSD at 1.11461 TP=1.11480 Bid=1.11452 (TakeProfit-Bid=28 points)
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11480 [invalid stops]
4. Buy 1.0 EURUSD at 1.11461 TP=1.11481 Bid=1.11452 (TakeProfit-Bid=29 points)
CTrade::OrderSend: instant buy 1.00 EURUSD at 1.11461 tp: 1.11481 [invalid stops]
5. Buy 1.0 EURUSD at 1.11462 TP=1.11482 Bid=1.11452 (TakeProfit-Bid=30 points)
Buy 1.0 EURUSD done at 1.11462 with TakeProfit=20 points (SYMBOL_TRADE_STOPS_LEVEL=30 - spread=10)

Die Überprüfung der Ebene StopLoss und TakeProfit in Pending-Orders ist viel einfacher, diese Ebene sollen vom Eröffnungspreis der Order verschoben werden. Das heißt, die Überprüfung der Ebene unter Berücksichtigung der minimalen Distanz SYMBOL_TRADE_STOPS_LEVEL sieht so aus: die Ebene TakeProfit und StopLoss müssen vom Preis der Abnutzung der Order auf der Entfernung nicht weniger als SYMBOL_TRADE_STOPS_LEVEL Punkte sein.

BuyLimit и BuyStop
SellLimit и SellStop
TakeProfit - Open >= SYMBOL_TRADE_STOPS_LEVEL
Open - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL
Open - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL
StopLoss - Open >= SYMBOL_TRADE_STOPS_LEVEL

Im EA Test_StopLoss_Level_in_PendingOrders.mq5 wird eine Serie der Versuche BuyStop und BuyLimt  so lange gemacht, bis die Operation nicht erfolgreich endet. Mit jedem Versuch wird das Niveau StopLoss oder TakeProfit auf 1 Punkt zur richtigen Seite geschoben. Das Beispiel der EA-Ausführung:

Test_StopLoss_Level_in_PendingOrders.mq5
SYMBOL_TRADE_EXECUTION=SYMBOL_TRADE_EXECUTION_INSTANT
SYMBOL_TRADE_FREEZE_LEVEL=20: die Order oder die Position wird verboten, zu modifizieren, wenn es 20 Punkte bis zum Preis der Abnutzung blieben
SYMBOL_TRADE_STOPS_LEVEL=30: StopLoss und TakeProfit dürfen nicht näher als 30 Punkte vom Exit-Preis
1. BuyStop 1.0 EURUSD at 1.11019 SL=1.10993 (Open-StopLoss=26 points)
CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11019 sl: 1.10993 [invalid stops]
2. BuyStop 1.0 EURUSD at 1.11019 SL=1.10992 (Open-StopLoss=27 points)
CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11019 sl: 1.10992 [invalid stops]
3. BuyStop 1.0 EURUSD at 1.11020 SL=1.10992 (Open-StopLoss=28 points)
CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11020 sl: 1.10992 [invalid stops]
4. BuyStop 1.0 EURUSD at 1.11021 SL=1.10992 (Open-StopLoss=29 points)
CTrade::OrderSend: buy stop 1.00 EURUSD at 1.11021 sl: 1.10992 [invalid stops]
5. BuyStop 1.0 EURUSD at 1.11021 SL=1.10991 (Open-StopLoss=30 points)
BuyStop 1.0 EURUSD done at 1.11021 with StopLoss=1.10991 (SYMBOL_TRADE_STOPS_LEVEL=30)
 --------- 
1. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10647 (TakeProfit-Open=26 points)
CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10647 [invalid stops]
2. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10648 (TakeProfit-Open=27 points)
CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10648 [invalid stops]
3. BuyLimit 1.0 EURUSD at 1.10621 TP=1.10649 (TakeProfit-Open=28 points)
CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10621 tp: 1.10649 [invalid stops]
4. BuyLimit 1.0 EURUSD at 1.10619 TP=1.10648 (TakeProfit-Open=29 points)
CTrade::OrderSend: buy limit 1.00 EURUSD at 1.10619 tp: 1.10648 [invalid stops]
5. BuyLimit 1.0 EURUSD at 1.10619 TP=1.10649 (TakeProfit-Open=30 points)
BuyLimit 1.0 EURUSD done at 1.10619 with TakeProfit=1.10649 (SYMBOL_TRADE_STOPS_LEVEL=30)

Die Beispiele der Überprüfung der Ebene TakeProfit und StopLoss in den Pending-Orders befinden sich in den hinzufügten Ausgangskodes: Check_TP_and_SL.mq4 und Check_TP_and_SL.mq5.


Der Versuch der Order-Modifikation oder der Position innerhalb der Halte-Ebene SYMBOL_TRADE_FREEZE_LEVEL

In den Einstellungen des Symbols kann der Parameter SYMBOL_TRADE_FREEZE_LEVEL gegeben werden, der in Punkten die Halte-Distanz der Handelsoperationen für Pending-Orders und geöffneten Position zeigt. Zum Beispiel, wenn ein Trade nach dem Finanzinstrument für Posttranskription ins äußerliche Handelssystem abgeschickt wird, so kann sich die Pending Order BuyLimit in diesem Moment sehr nahe vom aktuellen Preis Ask befinden. Und wenn wir die Order auf die Modifikation dieser Order zu jenem Moment absenden werden, wenn der Preis der Eröffnung genug nah zum Preis Ask ist, so kann es werden, dass die Order schon ausgeführt ist und die Modifikation schon unmöglich sein wird.

Deshalb für die Pending Orders und die offenen Positionen in den Einstellungen des Symbols die Distanz der Halte gegeben werden kann, in deren Grenzen man keine Modifikation durchführen darf. Im Allgemeinen, bevor Sie versuchen, die Order auf die Modifikation zusenden, muss man die Überprüfung unter Berücksichtigung  SYMBOL_TRADE_FREEZE_LEVEL durchführen:

Der Typ  der Order/Position
Aktivierung nach dem Preis
Überprüfung
Buy Limit Order
 Ask
Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL
Buy Stop Order AskOpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL
Sell Limit ордер BidOpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL
Sell Stop Order BidBid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL
Buy Position
 BidTakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL
Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL
Sell Position
 AskAsk-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL
StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL

Die vollständige Beispiele der Funktionen für die Überprüfung der Orders und Positionen auf der Ebene SYMBOL_TRADE_FREEZE_LEVEL finden Sie in hinzugefügten Skripts Check_FreezeLevel.mq5 und Check_FreezeLevel.mq4.

//--- Überprüfen wir den Typ der Order
   switch(type)
     {
      //--- die Pending-Order BuyLimit
      case  ORDER_TYPE_BUY_LIMIT:
        {
         //--- Überprüfen wir die Distanz vom Eröffnungspreis bis zum Preis der Aktivierung 
         check=((Ask-price)>freeze_level*_Point);
         if(!check)
            PrintFormat("Die Order %s #%d kann man nicht modifizieren: Ask-Open=%d Punkte < SYMBOL_TRADE_FREEZE_LEVEL=%d Punkte",
                        EnumToString(type),ticket,(int)((Ask-price)/_Point),freeze_level);
         return(check);
        }
      //--- die Pending-Order BuyLimit
      case  ORDER_TYPE_SELL_LIMIT:
        {
         //--- Überprüfen wir die Distanz vom Eröffnungspreis bis zum Preis der Aktivierung 
         check=((price-Bid)>freeze_level*_Point);
         if(!check)
            PrintFormat("Ордер %s #%d kann man nicht modifizieren: Open-Bid=%d Punkte < SYMBOL_TRADE_FREEZE_LEVEL=%d Punkte",
                        EnumToString(type),ticket,(int)((price-Bid)/_Point),freeze_level);
         return(check);
        }
      break;
      //--- die Pending-Order BuyStop
      case  ORDER_TYPE_BUY_STOP:
        {
         //--- Überprüfen wir die Distanz vom Eröffnungspreis bis zum Preis der Aktivierung 
         check=((price-Ask)>freeze_level*_Point);
         if(!check)
            PrintFormat("Die Order %s #%d kann man nicht modifizieren: Ask-Open=%d Punkte < SYMBOL_TRADE_FREEZE_LEVEL=%d Punkte",
                        EnumToString(type),ticket,(int)((price-Ask)/_Point),freeze_level);
         return(check);
        }
      //--- die Pending-Order SellStop
      case  ORDER_TYPE_SELL_STOP:
        {
         //--- Überprüfen wir die Distanz vom Eröffnungspreis bis zum Preis der Aktivierung 
         check=((Bid-price)>freeze_level*_Point);
         if(!check)
            PrintFormat("Ордер %s #%d kann man nicht modifizieren: Bid-Open=%d Punkte < SYMBOL_TRADE_FREEZE_LEVEL=%d Punkte",
                        EnumToString(type),ticket,(int)((Bid-price)/_Point),freeze_level);
         return(check);
        }
      break;
     }

Sie können selbständig die Situation modellieren, wenn ein Modifikationsversuch der Pending Order innerhalb der Ebene der Halte stattfindet. Dazu öffnen Sie das Demo-Konto, auf dem eine Finanzinstrumente mit der nicht nullwertigen Ebene SYMBOL_TRADE_FREEZE_LEVEL gibt, lassen Sie den EA Test_SYMBOL_TRADE_FREEZE_LEVEL.mq5 (Test_SYMBOL_TRADE_FREEZE_LEVEL.mq4) starten und setzen Sie manuell eine Pending Order. Der EA wird selbst die Order maximal nahe zum Markt ziehen und wird beginnen, die verbotenen Modifikationsversuche zu machen. Dabei wird eine Sound mit Hilfe der Funktion PlaySound() gegeben.


Die Fehler, die bei der Arbeit mit den Symbolen auftreten, deren History der Notierungen nicht ausreichend ist

Wenn der EA oder der Indikator auf der Chart mit der ungenügenden History gestartet wird, so sind hier zwei Varianten möglich:

  1. Das Programm macht die Überprüfung auf das Vorhandensein der geforderten History über die ganze notwendige Tiefe. Wenn es zugängliche Bars weniger ist, als es erforderlich ist, so fordert das Programm die fehlenden Daten an und beendet die Arbeit bis zum Ankommen des nächsten Ticks. Dieser Weg ist der richtigste und hilft eine Menge der Fehler zu vermeiden — solche, wie zum Beispiel, die Rahmen des Massives überschreiten oder die Teilung durch Null;
  2. Das Programm macht keine Überprüfungen und beginnt direkt die Arbeit, als ob die ganze notwendige History nach allen geforderten Symbolen und Timeframes sofort auf der ersten Forderung zugänglich wäre. Solche Methode ist vieler unvorhersehbaren Fehler gefährdet.

Sie können selbständig eine solche Situation modellieren. Dazu starten Sie den geprüften Indikator oder den EA auf der Chart, dann schließen Sie das Terminal und löschen Sie die ganze History und starten Sie wieder das Terminal. Wenn nach einem solchen Neustart die Fehler im Journal nicht erschienen wurden, so beginnen Sie, die Symbole und Timeframes auf den Charts zu tauschen, auf den Ihr Programm gestartet ist. Viele Indikatoren geben die Fehler beim Start auf wöchentlich oder monatlich Timeframes, für die die Anzahl der Bars in der Regel beschränkt ist. Auch kann der Indikator oder EA beim heftigen Wechsel des Chart-Symbols, zum Beispiel, von EURUSD um CADJPY, der auf der Chart gestartet ist, auf einen Fehler anstoßen, der von der Abwesenheit für seine Berechnungen geforderten History verursacht ist.


Die Rahmen des Massives überschreiten (array out of range)

Bei der Arbeit mit den Massiven bekommt man den Zugang auf seine Elemente nach der Nummer des Indexes, das nicht unter 0 sein kann und soll weniger sein, als die Größe des Massives. Die Größe des Massives kann man mit Hilfe der FUnktion ArraySize() bekommen.

Dieser Fehler kann bei der Arbeit mit dem dynamischen Massiv auftreten, wenn seine Größe offenbar noch nicht von der Funktion   ArrayResize() verteilt ist, oder es kann unter Anwendung eines solchen Massives in den Funktionen auftreten, die die Größe an sie übergebenen Massiven selbständig feststellen. Zum Beispiel, die Funktion CopyTicks() versucht ins Massiv die geforderte Anzahl der Ticks einzuschreiben, aber wenn es Ticks weniger ist, als es gefordert wurde, so wird die Größe des erhaltenden Massives weniger als erwartet.

Die andere wahrscheinliche Methode, diesen Fehler zu bekommen — ist der Versuch, die Daten des Indikator-Puffers aufzurufen, wenn seine Größe noch nicht initialisiert ist. Erinnern wir uns, die Indikator-Puffer sind die dynamischen Massive, und ihre Größe werden vom vollziehenden System des Terminales nur nach der Initialization der Chart festgesetzt. Deswegen, wenn es zum Beispiel versucht wird, solchen Puffer in der Funktion OnInit() aufzurufen, wird es zum Fehler "array out of range" führen.


Das einfache Beispiel des Indikators, der diesen Fehler gibt, wurde in der Datei Test_Out_of_range.mq5 hinzugefügt.


Die Teilung durch Null (zero divide)

Der andere kritische Fehler ist der Versuch, in Null zu teilen. In diesem Fall wird die Ausführung des Programms sofort angehalten, der Tester zeigt im Journal den Namen der Funktion und die Nummer der Zeile im Anfangskode, auf dem der Fehler aufgetreten ist.


In der Regel, die Teilung in Null findet infolge der Situation statt, die vom Programmierer unerwartet ist, zum Beispiel, das Erhalten einer irgendwelchen Eigenschaft oder der Berechnung eines Ausdrucks mit den "schlechten" Daten.

Sie können die Teilung durch Null mit Hilfe des einfachen EAs TestZeroDivide.mq5 leicht wiedergeben, dessen Anfangscode auf dem Screenshot vorgestellt ist. Der andere kritische Fehler ist die Verwendung des unkorrekten Objekt-Zeigers. Für die Klärung des Grundes eines solchen Fehlers wird die Einrichtung auf der History helfen.


Die Sendung der Anfrage auf die Modifikation der Ebenen ohne ihre tatsächliche Veränderung

Wenn nach den Regeln des Handelssystems ist es erforderlich, die Pending Orders oder die offenen Positionen zu modifizieren, so muss man vor der Sendung der Handelsanfrage auf die Durchführung der Transaktion sicher sein, dass die angerufene Operationen die Parameter der Order oder Position tatsächlich ändern. Die Sendung der Handelsanfrage, die faktisch keine Veränderungen macht, wird als Fehler angenommen. Der Handelsserver wird als Antwort auf solche Handlung den Code der Antwort TRADE_RETCODE_NO_CHANGES=10025 (MQL5) oder den Code ERR_NO_RESULT=1 (MQL4) zurückgeben

Das Beispiel der Überprüfung für MQL5 wurde im Skript Check_OrderLevels.mq5 aufgeführt:

//--- Die Klasse für die Durchführung der Handelsoperationen
#include <Trade\Trade.mqh>
CTrade trade;
#include <Trade\Trade.mqh>
//--- Fie Klasse für die Arbeit mit Orders
#include <Trade\OrderInfo.mqh>
COrderInfo orderinfo;
//--- Die Klasse für die Arbeit mit den Positionen
#include <Trade\PositionInfo.mqh>
CPositionInfo positioninfo;
//+------------------------------------------------------------------+
//| die Überprüfung der neuen Ebene-Werte vor der Modifikation der Order         |
//+------------------------------------------------------------------+
bool OrderModifyCheck(ulong ticket,double price,double sl,double tp)
  {
//--- Wählen wir die Order nach dem Ticket
   if(orderinfo.Select(ticket))
     {
      //--- Die Größe des Punktes und des Symbol-Namens, nach dem die Pendig Order gesetzt wurde
      string symbol=orderinfo.Symbol();
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      //--- Überprüfen wir - ob es Änderungen im Eröffnungspreis gibt 
      bool PriceOpenChanged=(MathAbs(orderinfo.PriceOpen()-price)>point);
      //--- Überprüfen wir - ob es Änderungen in der Ebene StopLoss gibt
      bool StopLossChanged=(MathAbs(orderinfo.StopLoss()-sl)>point);
      //--- Überprüfen wir - ob es Änderungen in der Ebene Takeprofit gibt
      bool TakeProfitChanged=(MathAbs(orderinfo.TakeProfit()-tp)>point);
      //--- wenn es Änderungen in den Ebenen  gibt
      if(PriceOpenChanged || StopLossChanged || TakeProfitChanged)
         return(true);  // kann man diese Order modifizieren      
      //--- Änderungen gibt es nicht in den Eröffnungsebenen,StopLoss und Takeprofit 
      else
      //--- Berichten wir über den Fehler
         PrintFormat("Ордер #%d hat schon Ebene Open=%.5f SL=%.5f TP=%.5f",
                     ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit());
     }
//--- kommen bis zu Ende, Änderungen für die Order nicht gibt
   return(false);       // es gibt keinen Sinn, zu modifizieren 
  }
//+------------------------------------------------------------------------------+
//| die Überprüfung der neuen Ebene-Werte vor der Modifikation der Order         |
//+------------------------------------------------------------------------------+
bool PositionModifyCheck(ulong ticket,double sl,double tp)
  {
//--- Wählen wir die Order nach dem Ticket
   if(positioninfo.SelectByTicket(ticket))
     {
      //--- Die Größe des Punktes und des Symbol-Namens, nach dem die Pendig Order gesetzt wurde
      string symbol=positioninfo.Symbol();
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      //--- Überprüfen wir - ob es Änderungen in der Ebene StopLoss gibt
      bool StopLossChanged=(MathAbs(positioninfo.StopLoss()-sl)>point);
      //--- Überprüfen wir - ob es Änderungen in der Ebene Takeprofit gibt
      bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point);
      //--- wenn es Änderungen in den Ebenen  gibt
      if(StopLossChanged || TakeProfitChanged)
         return(true);  // diese Position kann modifiziert werden      
      //--- Änderungen gibt es nicht in den Ebenen,StopLoss und Takeprofit
      else
      //--- Berichten wir über den Fehler
         PrintFormat("Ордер #%d hat schon Ebene Open=%.5f SL=%.5f TP=%.5f",
                     ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit());
     }
//--- kommen bis zu Ende, Änderungen für die Order nicht gibt
   return(false);       // es gibt keinen Sinn, zu modifizieren 
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Die Preisebenen für die Orders und Positionen
   double priceopen,stoploss,takeprofit;
//--- Das Ticket der aktuellen Order und Position
   ulong orderticket,positionticket;
/*
   ... Erhalten wir das Ticket der Order und neue Ebenen StopLoss/Takeprofit/PriceOpen
*/
//--- Überprüfen wir die Ebenen vor der Modifizierung der Pending Order   
   if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit))
     {
      //--- die Überprüfung ist erfolgreich gelaufen 
      trade.OrderModify(orderticket,priceopen,stoploss,takeprofit,
                        orderinfo.TypeTime(),orderinfo.TimeExpiration());
     }
/*
   ... Erhalten wir das Ticket der Position und neue Ebenen StopLoss/Takeprofit
*/
//--- Überprüfen wir die Ebenen vor der Modifizierung der Position
   if(PositionModifyCheck(positionticket,stoploss,takeprofit))
     {
      //--- die Überprüfung ist erfolgreich gelaufen 
      trade.PositionModify(positionticket,stoploss,takeprofit);
     }
//---
  }

Das Beispiel der Überprüfung in MQL5 finden Sie im Skript Check_OrderLevels.mq4:

#property strict
//+------------------------------------------------------------------------------+
//| die Überprüfung der neuen Ebene-Werte vor der Modifikation der Order         |
//+------------------------------------------------------------------------------+
bool OrderModifyCheck(int ticket,double price,double sl,double tp)
  {
//--- Wählen wir die Order nach dem Ticket
   if(OrderSelect(ticket,SELECT_BY_TICKET))
     {
      //--- Die Größe des Punktes und des Symbol-Namens, nach dem die Pendig Order gesetzt wurde
      string symbol=OrderSymbol();
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      //--- Überprüfen wir - ob es Änderungen im Eröffnungspreis gibt 
      bool PriceOpenChanged=true;
      int type=OrderType();
      if(!(type==OP_BUY || type==OP_SELL))
        {
         PriceOpenChanged=(MathAbs(OrderOpenPrice()-price)>point);
        }
      //--- Überprüfen wir - ob es Änderungen in der Ebene StopLoss gibt
      bool StopLossChanged=(MathAbs(OrderStopLoss()-sl)>point);
      //--- Überprüfen wir - ob es Änderungen in der Ebene Takeprofit gibt
      bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point);
      //--- wenn es Änderungen in den Ebenen  gibt
      if(PriceOpenChanged || StopLossChanged || TakeProfitChanged)
         return(true);  // kann man diese Order modifizieren      
      //--- Änderungen gibt es nicht in den Eröffnungsebenen,StopLoss und Takeprofit 
      else
      //--- Berichten wir über den Fehler
         PrintFormat("Ордер #%d hat schon Ebene Open=%.5f SL=%.5f TP=%.5f",
                     ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit());
     }
//--- kommen bis zu Ende, Änderungen für die Order nicht gibt
   return(false);       // es gibt keinen Sinn, zu modifizieren 
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Die Preisebenen für die Orders und Positionen
   double priceopen,stoploss,takeprofit;
//--- Das Ticket der aktuellen Order 
   int orderticket;
/*
   ... Erhalten wir das Ticket der Order und neue Ebenen StopLoss/Takeprofit/PriceOpen
*/
//--- Überprüfen wir die Ebenen vor der Modifizierung der Order   
   if(OrderModifyCheck(orderticket,priceopen,stoploss,takeprofit))
     {
      //--- die Überprüfung ist erfolgreich gelaufen 
      OrderModify(orderticket,priceopen,stoploss,takeprofit,OrderExpiration());
     }
  }

Wir empfehlen auch die folgenden Artikeln zu lesen:

  1. Wie man das Erkennen und Beheben von Fehlern in einem Expert Advisor Code einfacher macht
  2. Wie man einen Zuverlässigen und Sicheren Handelsroboter in MQL4 entwickelt


Der Versuch des Importes der kompilierten Dateien (sogar EX4/EX5) und DLL

Die Programme, die durch Market verbreitet werden, müssen für die Benutzer garantiert sicher sein. Deshalb gelten alle Versuche der Verwendung DLL oder der Funktionen aus den kompilierten Dateien EX4/EX5 für einen Fehler. Solche Produkte werden auf dem Market nicht veröffentlicht.

Wenn Ihr Programm die zusätzlichen Indikatoren verwenden muss, die in der Distribution nicht gibt, verwenden Sie die Ressourcen.


Die Aufrufe zu den benutzerdefinierten Indikatoren durch iCustom()

Wenn es für die Arbeit Ihres Programms ein Aufruf zu Daten des benutzerdefinierten Indikators notwendig ist, so müssen Sie alle nötigen Indikatoren in die Ressourcen unterbringen. Die Produkte aus dem Market sollen bereit auf eine Arbeit in jeder Umgebung sein, deshalb sollen sie alles Notwendiges in der Datei EX4/EX5 haben. Die nach dem Thema empfohlenen Artikel:


Die Sendung des unzulässigen Parameters in die Funktion (compile-time error)

Diese Art der Fehler kommt selten vor, für viele von ihnen gibt es die fertigen Codes, die ermöglichen den Grund zu finden.

Konstante Werte Beschreibung
ERR_INTERNAL_ERROR 4001 Unerwartete innerer Fehler
ERR_WRONG_INTERNAL_PARAMETER 4002 Ein falscher Parameter beim inneren Aufruf der Funktion des Kundenterminales
ERR_INVALID_PARAMETER 4003 Ein falscher Parameter beim Aufruf der Systemfunktion
ERR_NOTIFICATION_WRONG_PARAMETER 4516 Der falsche Parameter für die Sendung der Benachrichtigung – in die Funktion SendNotification()   haben die leere Zeile oder NULL übertragen
ERR_BUFFERS_WRONG_INDEX 4602 Der falsche Index des Indikatorpuffers
ERR_INDICATOR_WRONG_PARAMETERS 4808 Die falsche Anzahl der Parameter bei der Erstellung des Indikators
ERR_INDICATOR_PARAMETERS_MISSING 4809 Fehlen die Parameter bei der Erstellung des Indikators
ERR_INDICATOR_CUSTOM_NAME 4810 Der erste Parameter im Massiv soll der Name des Benutzerindikators sein
ERR_INDICATOR_PARAMETER_TYPE 4811 Die falsche Art des Parameters im Massiv bei der Erstellung des Indikators
ERR_NO_STRING_DATE 5030 In der Zeile gibt es kein Datum
ERR_WRONG_STRING_DATE 5031 In der Zeile ist ein falsches Datum
ERR_TOO_MANY_FORMATTERS 5038 Formatspezifizierer sind mehr, als Parameter
ERR_TOO_MANY_PARAMETERS 5039 Parameter sind mehr, als Formatspezifizierer

In der Tabelle sind bei weitem nicht alle Fehler aufgezählt, die man während der Arbeit des gestarteten Programms finden kann.

 

Access violation

Ein solcher Fehler entsteht beim Versuch den Speicher aufzurufen, deren Zugriff nicht gestattet ist. In jedem solchen Fall muss man den Hersteller im Serwisdesk durch sein Profil oder durch die Seite im Vkontakte aufrufen. Die ausführliche Beschreibung der Wiedergabe-Schritte des Fehlers und den hinzugefügten Anfangscode wird wesentlich die Suche des Grundes eines solchen Fehlers beschleunigen und ermöglicht den Compiler des Anfangscodes zu verbessern.




Der Verbrauch der Prozessors-Ressourcen und des Speichers

Bei der Schreibung des Programms ist es wichtig, die mit der Zeit optimalen Ausführung der Algorithmen zu verwenden, denn es kann umsonst schwierig oder sogar unmöglich die Arbeit anderer im Terminal gestarteten Programme.

Es ist wichtig daran zu erinnern, dass auf jedem Symbol in der Markt-Übersicht das Terminal einen allgemeinen Strom für die Arbeit wählt, in dem alle Indikatoren und die Charts sind, die nach ihm geöffnet wurden.

Es bedeutet, dass, wenn es bei Ihnen 5 Charts nach EURUSD auf verschiedenen Timeframes geöffnet sind, und auf diesen Charts 15 Indikatoren gestartet sind, so bekommen alle diese Charts und Indikatoren einen-einzigen Strom zur Verfügung, um die Berechnungen und die Darstellung der Informationen auf den Charts durchzuführen. Deshalb kann ein nicht effektiver, viel Ressourcen fordertet Indikator die Arbeit der übrigen Indikatoren auf dem Chart verlangsamen und sogar verzögern, die Bildung der Preise aller übrigen Charts dieses Symbols.

Sie können leicht die Zeit überprüfen, die von Ihrem Algorithmus mit Hilfe der Funktion GetMicrosecondCount() verbraucht wurde. Nach Abmessungen der Zeit zwischen zwei Zeilen des Codes kann man leicht die Zeit der Ausführung in Mikrosekunden zu bekommen. Für die Übersetzung in Millisekunden (ms) muss man diese Zeit auf 1000 teilen(in 1 Millisekunde sind 1000 Mikrosekunden). Für die Indikatoren, die kritische Stelle nach der Zeit der Ausführung ist normalerweise der Verarbeiter OnCalculate(). In der Regel, die erste Rechnung des Indikators hängt vom Parameter Max. Bars im Fenster stark ab, geben Sie darin die Werte "Unlimited" und starten Sie den Indikator auf dem Symbol mit der History länger als 10 Jahre auf Timeframes M1. Wenn es der erste Start viel Zeit (zum Beispiel, mehr als 100 ms braucht), so muss der Code optimiert werden.

Das Beispiel, wie die Zeit der Ausführung des Verarbeiters OnCalculate() im Indikator ROC gemessen werden kann, der in der Distribution des Terminales im Anfangscode ist. Die Distributionen wurden im gelben Hintergrund gewählt:

//+------------------------------------------------------------------+
//| Rate of Change                                                   |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
  {
//--- check for rates count
   if(rates_total<ExtRocPeriod)
      return(0);
//--- время начала расчетов
   ulong start=GetMicrosecondCount();  
//--- preliminary calculations
   int pos=prev_calculated-1; // set calc position
   if(pos<ExtRocPeriod)
      pos=ExtRocPeriod;
//--- the main loop of calculations
   for(int i=pos;i<rates_total && !IsStopped();i++)
     {
      if(price[i]==0.0)
         ExtRocBuffer[i]=0.0;
      else
         ExtRocBuffer[i]=(price[i]-price[i-ExtRocPeriod])/price[i]*100;
     }
//--- Die Zeit des Endes der Berechnungen     
   ulong finish=GetMicrosecondCount();  
   PrintFormat("Die Funktion %s в %s verbrauchte %.1f ms",__FUNCTION__,__FILE__,(finish-start)/1000.);
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }

Sie können den verwendeten Speicher mit Hilfe der Funktion   MQLInfoInteger(MQL_MEMORY_USED) messen. Also, verwenden Sie natürlich noch den Profiler des Codes für die Suche der Ressource geforsteten Funktionen in Ihrem Programm. Wir empfehlen auch die folgenden Artikel Prinzipien der wirtschaftlichen Berechnung von Indikatoren und Zur Fehlerbehebung von MQL5-Programmen (Debugging) zu lesen.

Die Experten arbeiten in den eigenen Strömen, aber alles, was oben steht, betrifft sie nicht. Man muss den optimalen Code in jeder Art der Programme schreiben — egal, ob es ein EA, Indikatoren, Bibliotheken oder Skripts sind.


Es gibt nie viele Übersetzungen

Alle aufgeführten Ratschläge über die Überprüfungen der Indikatoren und der EAs werden nicht nur für die Veröffentlichung der Produkte im Market empfohlen, sondern auch in der normalen Praxis, wenn Sie für sich schreiben. In diesem Artikel haben wir nicht alle Fehler betrachtet, die beim Handel auf einem realen Konto vorkommen können. Hier wurden nicht die Verarbeitung-Regeln der Handelsfehler betrachtet, die beim Abbruch der Verbindung mit dem Handelsserver, Requote entstehen, oder Absagen bei Transaktionen u.s.w, die die idealen Regeln des Handelssystems verletzen können. Für diese Fälle hat jeder Hersteller der Roboter hat die Methoden, die von der Erfahrung bereits entwickelt sind.

Einem Neulingen ist es empfohlen, alle Artikeln zu lesen, die der Verarbeitung der Fehler gewidmet sind, sowie, Fragen auf dem Forum und in den Kommentaren zu diesem Artikel stellen. Andere erfahrenere Mitglieder der Gesellschaft MQL5.community werden Ihnen helfen, für Sie unverständliche Fragen zu erklären. Wir hoffen, dass im Artikel gesammelten Informationen Ihnen helfen werden, sicherere Handelsroboter in kürzeste Zeit zu erstellen.


Die nach dem Thema empfohlenen Artikel:

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

Beigefügte Dateien |
2555_en.zip (26.47 KB)
Grafische Interfaces VII: Die Tabellen Controls (Kapitel 1) Grafische Interfaces VII: Die Tabellen Controls (Kapitel 1)
Der siebte Teil der Serie über die grafischen Interfaces des Metatraders, handelt von drei Tabellen-Typen: Text-Label, Edit-Box und gerenderte Tabellen. Ein weiteres Control, welches sehr oft gebraucht wird, ist das Tab, womit es Ihnen möglich ist, Gruppen von anderen Controls anzuzeigen und zu verstecken und somit sehr effektive und platzsparende Interfaces für ihre MQL Anwendung programmieren zu können.
LifeHack für Trader: ein back-Test ist gut, und vier – ist besser LifeHack für Trader: ein back-Test ist gut, und vier – ist besser
Vor jedem Trader bei dem ersten einzelnen Test steht eine und derselbe Frage — "Welchen von vier Modus ich verwenden soll?" Jeder des angebotenen Modus hat eigene Vorteile und Besonderheiten, deshalb machen wir es einfacher — wir werden direkt alle Modus durch eine Taste starten! Im Artikel ist es vorgeführt, wie man mit Hilfe Win API und der kleinen Magie gleichzeitig alle vier Graphik des Tests sehen kann.
Fuzzy-Logik für eine manuelle Handelsstrategie Fuzzy-Logik für eine manuelle Handelsstrategie
Dieser Artikel zeigt die Möglichkeiten der Verbesserung einer manuelle Handelsstrategie durch die Verwendung der Theorie der unscharfen Mengen (fuzzy sets). Als Beispiel bieten wir eine Schritt-für-Schritt-Beschreibung der Suche nach einer Strategie und die Auswahl der Parameter, gefolgt von der Anwendung der Fuzzy-Logik, um allzu formale Kriterien für den Markteintritt zu verwischen. So erhalten wir nach einer Strategie-Modifikation flexible Bedingungen für die Eröffnung einer Position als eine angemessene Reaktion auf eine Marktsituation.
Grafische Interfaces V: Das Combobox Control (Kapitel 3) Grafische Interfaces V: Das Combobox Control (Kapitel 3)
In den ersten zwei Kapiteln des fünften Teils dieser Serie, haben wir Klassen für die Erzeugung einer Scrollbar und einer ListView entwickelt. In diesem Kapitel werden wir über die Erzeugung einer Klasse für eine ComboBox sprechen. Hierbei handelt es sich ebenfalls um ein Komponenten-Control, welches neben anderen Elementen auch Elemente enthält, die wir in den vorherigen Kapiteln des 5. Teils besprochen haben.