Pause zwischen Trades

Andrey Khatimlianskii | 5 November, 2015


1. Obligatorisch oder freiwillig?

    Im Kundenterminal MetaTrader 3 war unmöglich, zwei Trades mit einem Zeitintervall von weniger als 10 Sekunden zu tätigen. Bei der Entwicklung des Terminals MT 4 kam das Unternehmen MetaQuotes den Wünschen von Händlern entgegen, und diese Begrenzung wurde aufgehoben. Es gibt tatsächlich Situationen, wo mehrere Trades einer nach dem anderen akzeptabel sind (Verschiebung des Stop-Loss-Levels für mehrere Positionen, Löschung offener Orders usw.) Einige Händler haben das aber falsch verstanden und begannen Killer-Experten zu schreiben, die mehrere Positionen ohne Pause eine nach der anderen öffnen. Zum Ergebnis wurde gesperrtes Konto oder im besten Fall schlechte Beziehungen zum Makler.

    Dieser Artikel ist nicht für solche Händler. Er soll denjenigen helfen, die den Handel komfortabel für sich und seinen Makler gestalten wollen.

2. Ein Expert Advisor oder mehrere - Was ist der Unterschied?

    Wenn Sie nur ein Terminal gestartet haben und da nur ein Expert Advisor arbeitet, ist es am einfachsten, eine Pause einzulegen. Dafür muss eine globale Variable erstellt werden (eine an der globalen Ebene angegebene Variable; nicht verwechseln mit Globalen Variablen des Terminals); die Zeit des letzten Trades ist in dieser Variablen zu speichern. Vor jedem Trade muss natürlich geprüft werden, ob genug Zeit nach dem letzten Tradeversuch vergangen ist.

    Dies wird folgendermaßen aussehen:

datetime LastTradeTime = 0;
int start()
 {
  // prüfen, ob man in den Markt eingehen muss 
  ...
  // Stop-Loss-Levels, Take Profit und Lotgröße berechnen 
  ...
  // prüfen, ob genug Zeit seit dem letzten Trade vergangen ist 
  if(LocalTime() - LastTradeTime < 10)
   {
    Comment("Seit dem letzten Trade sind weniger als 10 Sekunden vergangen!",
            " Dieser Expert Advisor wird nicht handeln!"); 
    return(-1);
   }
 
  // Position eröffnen
  if(OrderSend(...) < 0)
   {
    Alert( "Fehler bei Positioneröffnung № ", GetLastError() );
    return(-2);
   }
    
  // Zeit des letzten Trades speichern
  LastTradeTime = LocalTime();
 
  return(0);
 }
   

    Dieses Beispiel ist nur für einen Expert Advisor in einem Terminal geeignet. Wenn man noch einen oder mehrere Experten parallel dazu startet, werden diese die zehnsekundige Pause nicht einhalten. Sie werden nicht wissen, wann der andere Expert Advisor handelte. Jeder Experte hat eine eigene lokale Variable LastTradeTime. Die Lösung dieses Problems ist offensichtlich: man muss eine Globale Variable erstellen und die Zeit des Trades in ihr speichern. Hier geht es gerade um die Globale Variable des Terminals, zu der alle Experten den Zugang haben werden.

3. Funktion _PauseBeforeTrade()

    Da der Pausecode für alle Experten gleich ist, scheint logisch, ihn als eine Funktion zu erstellen. Das macht ihn leicht handhabbar und das Codevolumen - minimal.

    Vor dem Schreiben eines Codes definieren wir präziser die Aufgabe, denn dies erspart uns Zeit und Kraft. Also, was gehört zu Funktionsaufgaben:

    Wenn die Funktion feststellt, dass nach dem letzten Trade nicht genug Zeit vergangen ist, muss sie warten. Die Funktion Sleep() ermöglicht das Warten und prüft die IsStopped(). D.h. wenn man den Experten während des "Schlafs" löscht, wird dieser weder hängen noch zwangsweise beendet.

    Damit man über mehr Informationen verfügt, wird jede Sekunde während des "Schlafs" anzeigt, wie lange man noch warten muss.

    Es ergibt sich Folgendes:

extern int PauseBeforeTrade = 10; // Pause zwischen Trades in Sekunden 
 
/////////////////////////////////////////////////////////////////////////////////
// int _PauseBeforeTrade()
//
// Die Funktion setzt anhand der globalen Variablen  LastTradeTime lokale 
// setzen.
// Wenn die lokale Zeit im Startmoment kleiner ist, als der Wert der LastTradeTime + 
// PauseBeforeTrade, wartet die Funktion.
// Wenn die globale Variable LastTradeTime nicht existiert, wird diese durch die Funktion erstellt.
// Return-Codes:
//  1 - erfolgreiche Beendigung
// -1 - der Experte wurde vom Benutzer unterbrochen (der Experte ist vom Chart gelöscht, 
//      das Terminal ist geschlossen, die Chartperiode-  oder -symbol änderten sich, ... )
/////////////////////////////////////////////////////////////////////////////////
int _PauseBeforeTrade()
 {
  // es ist unnötig, während des Tests Pause einzuhalten - einfach die Funktion beenden
  if(IsTesting()) 
    return(1); 
  int _GetLastError = 0;
  int _LastTradeTime, RealPauseBeforeTrade;
 
  //+---------------------------------------------------------------------------+
  //| Prüfen, ob die globale Variable existiert, wenn nicht dann eine erstellen |
  //+---------------------------------------------------------------------------+
  while(true)
   {
    // wenn der Expert Advisor vom Benutzer gestoppt wurde, beenden. 
    if(IsStopped()) 
     { 
      Print("Der Expert Advisor wurde vom User gestoppt!"); 
      return(-1); 
     }
    // prüfen, ob die globale Variable existiert
    // wenn ja, den Zyklus verlassen 
    if(GlobalVariableCheck("LastTradeTime")) 
      break;
    else
     // wenn die GlobalVariableCheck FALSE geliefert hat, heißt das, entweder existiert die Variable nicht oder bei   
     // der Überprüfung ist ein Fehler aufgetreten
     {
      _GetLastError = GetLastError();
      // wenn es sich doch um einen Fehler handelt, die Information ausgeben, 0,1 Sekunden abwarten und  
      // die Überprüfung neu anfangen 
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableCheck(\"LastTradeTime\")-Error #",
              _GetLastError );
        Sleep(100);
        continue;
       }
     }
    // wenn kein Fehler besteht, heißt das, dass die globale Variable nicht existiert; versuchen, sie zu erstellen.
    // wenn GlobalVariableSet > 0, dann wurde die globale Variable erfolgreich erstellt. 
    // Funktion beenden 
    if(GlobalVariableSet("LastTradeTime", LocalTime() ) > 0) 
      return(1);
    else
     // wenn GlobalVariableSet einen Wert <= 0 lieferte, dann ist bei der Erstellung der Variablen  
     // ein Fehler aufgetreten
     {
      _GetLastError = GetLastError();
      // Information ausgeben, 0,1 Sekunde abwarten und neu anfangen 
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ", 
              LocalTime(), ") - Error #", _GetLastError );
        Sleep(100);
        continue;
       }
     }
   }
  //+---------------------------------------------------------------------------------------+
  //| Wenn die Funktion diesen Punkt erreicht hat, heißt das, dass die globale Variable     |
  //| existiert.                                                                            |
  //| warten, bis LocalTime() > LastTradeTime + PauseBeforeTrade sein wird                  |
  //+---------------------------------------------------------------------------------------+
  while(true)
   {
    // wenn der Expert Advisor vom Benutzer gestoppt wurde, beenden. 
    if(IsStopped()) 
     { 
      Print("Expert Advisor wurde vom Benutzer gestoppt!"); 
      return(-1); 
     }
    // den Wert der globalen Variablen bekommen
    _LastTradeTime = GlobalVariableGet("LastTradeTime");
    // wenn dabei ein Fehler auftritt, Information anzeigen, 0,1 Sekunde abwarten und  
    // neu anfangen
    _GetLastError = GetLastError();
    if(_GetLastError != 0)
     {
      Print("_PauseBeforeTrade()-GlobalVariableGet(\"LastTradeTime\")-Error #", 
            _GetLastError );
      continue;
     }
    // Sekunden seit dem letzten Trade zählen, 
    RealPauseBeforeTrade = LocalTime() - _LastTradeTime;
    // wenn weniger als PauseBeforeTrade Sekunden vergangen sind,
    if(RealPauseBeforeTrade < PauseBeforeTrade)
     {
      // Information anzeigen, eine Sekunde abwarten und erneut überprüfen
      Comment("Pause zwischen Trades. geblieben sind ", 
               PauseBeforeTrade - RealPauseBeforeTrade, " Sekunden" );
      Sleep(1000);
      continue;
     }
    // wenn mehr als PauseBeforeTrade vergangen sind, den Zyklus beenden
    else
      break;
   }
  //+---------------------------------------------------------------------------------------+
  //| Wenn die Funktion diesen Punkt erreicht hat, heißt das, dass die globale Variable     |
  //| existiert,  und die lokale Zeit die LastTradeTime + PauseBeforeTrade     überschreitet|
  //| Lokale Zeit für die globale Variable LastTradeTime setzten                            |
  //+---------------------------------------------------------------------------------------+
  while(true)
   {
    // wenn der Expert Advisor vom Benutzer gestoppt wurde, beenden. 
    if(IsStopped()) 
     { 
      Print("Der Experte wurde vom Benutzer beendet!"); 
      return(-1);
     }

    // Lokale Zeit für die globale Variable LastTradeTime   
    // setzen.
    // Wenn erfolgreich - beenden
    if(GlobalVariableSet( "LastTradeTime", LocalTime() ) > 0) 
     { 
      Comment(""); 
      return(1); 
     }
    else
    // wenn die GlobalVariableSet einen Wert <= 0 geliefert hat, dann ist ein Fehler aufgetreten
     {
      _GetLastError = GetLastError();
      // Information ausgeben, 0,1 Sekunde abwarten und neu anfangen 
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ", 
              LocalTime(), " ) - Error #", _GetLastError );
        Sleep(100);
        continue;
       }
     }
   }
 }


4. Eingliederung in Expert Advisors und Nutzung

    Damit man die Funktionsfähigkeit prüfen könnte, wurde ein Testexperte entwickelt, der zwischen Trades Pause einhält. Die Funktion _PauseBeforeTrade() war zuerst in die Datei PauseBeforeTrade.mq4 platziert, die mit der Anweisung #include in den Experten eingeschlossen wurde.

    Achtung! Dieser Expert Advisor ist ausschließlich für die Überprüfung der Funktionsfähigkeit bestimmt! Für Trades ist er ungeeignet!

#include <PauseBeforeTrade.mq4>
 
int ticket = 0;
int start()
 {
  // wenn es keine Position gibt, die durch diesen Experten eröffnet wurde,
  if(ticket <= 0)
   {
    // Pause zwischen Trades einhalten; wenn ein Fehler aufgetreten ist, beenden.
    if(_PauseBeforeTrade() < 0) 
      return(-1);
    // Marktinformation aktualisieren
    RefreshRates();
 
    //  und versuchen, eine Position zu eröffnen
    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0, 
                       Lime);
    if(ticket < 0)
      Alert("Fehler OrderSend № ", GetLastError());
   }
  // wenn es eine Position gibt, die durch diesen Experten eröffnet wurde
  else
   {
    // Pause zwischen Trades einhalten, (wenn ein Fehler aufgetreten ist, beenden)
    if(_PauseBeforeTrade() < 0)
      return(-1);
    // Marktinformation aktualisieren
    RefreshRates();
 
    // und versuchen, die Position zu schließen
    if (!OrderClose( ticket, 0.1, Bid, 5, Lime ))
      Alert("Fehler OrderClose № ", GetLastError());
    else
      ticket = 0;
   }
  return(0);
 }

  
    Danach wurde ein Experte dem Chart EURUSD, M1 und der andere, der gleich ist, dem Chart GBPUSD, M1 hinzugefügt. Das Ergebnis hat nicht lange auf sich warten lassen: beide Experten fingen an, mit der Pause von 10 Sekunden zu handeln:







5. Eventuelle Probleme

    Wenn mehrere Expert Advisors mit einer globalen Variablen arbeiten, können Fehler auftreten. Um dies zu vermeiden, muss der Zugang zur Variablen abgegrenzt werden. Der Algotithmus dieser "Abgrenzung" ist ausführlich im Artikel "Fehler 146 ("Handelskontext ist besetzt") und wie man ihn behandelt" beschrieben, ihn werden wir auch benutzen.

   Der Expert Advisor wird endgültig folgendermaßen aussehen:

#include <PauseBeforeTrade.mq4>
#include <TradeContext.mq4>
 
int ticket = 0;
int start()
 {
  // wenn es keine Position gibt, die durch diesen Experten eröffnet wurde,
  if(ticket <= 0)
   {
    // warten bis der Handelskontext befreit ist und ihn besetzen (im Fehlerfall 
    // beenden)
    if(TradeIsBusy() < 0)
      return(-1);
    // Pause zwischen Trades einhalten
    if(_PauseBeforeTrade() < 0)
     {
      // im Fehlerfall den Handelskontext befreien und beenden
      TradeIsNotBusy();
      return(-1);
     }
    // Marktinformation aktualisieren
    RefreshRates();
 
    //  und versuchen, eine Position zu eröffnen
    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0, 
                       Lime);
    if (ticket < 0)
      Alert("Fehler OrderSend № ", GetLastError());
    // Handelskontext befreien
    TradeIsNotBusy();
   }
  // wenn es eine Position gibt, die durch diesen Experten eröffnet wurde
  else
   {
    // warten bis der Handelskontext befreit ist und ihn besetzen (im Fehlerfall 
    // beenden)
    if(TradeIsBusy() < 0)
      return(-1);
    // Pause zwischen Trades einhalten
    if(_PauseBeforeTrade() < 0)
     {
      // im Fehlerfall den Handelskontext befreien und beenden
      TradeIsNotBusy();
      return(-1);
     }
    // Marktinformation aktualisieren
    RefreshRates();
 
    // und versuchen, die Position zu schließen
    if(!OrderClose( ticket, 0.1, Bid, 5, Lime))
      Alert("Fehler OrderClose № ", GetLastError());
    else
      ticket = 0;
 
    // Handelskontext befreien
    TradeIsNotBusy();
   }
  return(0);
 }