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:
- prüfen, ob die globale Variable erstellt wurde, wenn nicht, dann diese erstellen. Logischer und sparsamer wäre, einen Experten aus der Funktion init() zu machen, dann könnte aber der User sie löschen, und alle aktiven Experten hätten dann die Pause zwischen Trades nicht eingehalten. Deswegen wird sie im Funktionskörper platziert;
- laufende Zeit in der globalen Variablen speichern, damit andere Experten Pause einhalten;
- prüfen, ob nach dem letzten Trade genug Zeit vergangen ist. Für eine leichte Handhabung ist eine externe Variable hinzuzufügen, die eine notwendige Pausenlänge setzt. Ihren Wert kann man für jeden Expert Advisor einzeln ändern;
- Information über den Prozess und alle Fehler während des Prozesses anzeigen;
- unterschiedliche Werte je nach dem Ergebnis liefern.
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); }