English Русский 中文 Español 日本語 Português
Schlafen oder nicht schlafen?

Schlafen oder nicht schlafen?

MetaTrader 4Beispiele | 1 März 2015, 11:34
1 307 0
Sergey Gridnev
Sergey Gridnev

Einleitung

Während seiner Tätigkeit erzeugt ein Expert Advisor manchmal Situationen, in denen Pausen zwischen den Operationen vorgenommen werden müssen. Dies kann sowohl durch die Notwendigkeit verursacht werden, bestimmte Intervalle zwischen wiederholten Anfragen an den Handelsserver einzuhalten (im Falle von Ausführungsfehlern) als auch durch das Warten auf ein bestimmtes Ereignis (zum Beispiel auf die Wiederherstellung der Verbindung zum Server, die Freigabe zum Handel, usw.).

Schlafen "Sleep()" oder nicht schlafen?

Für die Realisierung von Pausen hat, MQL4 eine Funktion mit der Bezeichnung Sleep() , die als Parameter den Wert des Zeitintervalls, ausgedrückt in der Anzahl von Millisekunden nimmt. Die Funktion Sleep() stoppt die Ausführung des Programmcodes und erlaubt seine Fortsetzung erst nach dem Verstreichen des vorgegebenen Zeitintervalls.

Meiner Meinung nach hat die Verwendung dieser Funktion zwei Nachteile. Erstens wird die Maschinenzeit in unpraktischer Weise genutzt: während der Pause bei Aktionen einer bestimmten Art, könnte das Programm unabhängig von diesen, die Aktionen einer anderen Art durchführen (zum Beispiel, während einer Pause beim Handel könnte das Programm einige Berechnungen durchführen, eintreffende Ticks überwachen usw.). Zweitens,was noch wichtiger ist, die Funktion Sleep() kann nicht über eigene Indikatoren abgerufen werden (siehe Dokumentation). Außerdem muss eine Programmiersprache für die Programmierung verwendet werden!

Lassen Sie uns ansehen, wie eine Zehn-Sekunden-Pause in einem MQL4-Programm realisiert wird. Ein Beispiel mit der Funktion Sleep() ist unterhalb angeführt:

if ( /* condition that requires to hold a pause */ )
   Sleep(10000); // sleep for 10 seconds

// program block to be executed upon the expiry of the pause
// ...


Als Alternative lassen Sie uns einen Programmcode mit einer zusätzlichen Variablen ansehen. Für den Fall, dass Sie eine Pause vor der Ausführung einer Aktion benötigen, sollte diese Pause durch den Wert der Ortszeit an ihrem Ende initialisiert werden. Wenn Sie den Wert der Ortszeit mit dem Wert dieser Variablen vergleichen, können Sie das tatsächliche Ende der Pause ermitteln. Um die Vorteile der Verwendung dieses alternativen Ansatzes zu genießen, sollten Sie für die Zeit des Wartens auf das Ende der Pause, eine zyklische Ausführung des Programmcodes organisieren, für welche es keine Notwendigkeit gibt, eine Pause festzulegen. Sie können dies sowohl durch die Verwendung eines Zyklus tun (zum Beispiel, while) als auch durch die entsprechende Ausführung der Funktion start() die durch Zyklen, entsprechend dem Zyklus eingehender Ticks, aufgerufen werden kann. Erstere Alternative ist für benutzerdefinierte Skripts geeignet, während Letztere für Expert Advisors (EAs) und Indikatoren geeignet ist. Beide sind unterhalb angeführt.

Alternative 1 (Verwendung des Zyklus 'while').

int _time_waiting=0;
// ...
if ( ... ) // condition that requires to hold a pause
   _time_waiting = TimeLocal() + 10; // the pause ends in 10 seconds after the current local time
while ( TimeLocal() < _time_waiting )
{ // program block to be executed cyclically while waiting for the end of the pause
   // ...
}
// program block to be executed after the end of the pause
// ...

Alternative 2 (Verwendung des Zyklus, aufgerufen durch die Funktion start()).

static int _time_waiting=0;
// ...
if ( ... ) // condition that requires to hold a pause
   _time_waiting = TimeLocal() + 10; // the pause ends in 10 seconds after the current local time
if ( TimeLocal() >= _time_waiting )
{ // program block to be executed after the end of the pause
   // ...
}
// program block to be executed at every tick, not related to waiting for the end of the pause
// ...


Der wesentliche Unterschied zwischen den dargestellten Alternativen ist, dass die Alternative 1 garantiert, dass die Ausführung des Programmblocks für die Dauer der Pause gestoppt wird, während Alternative 2 dies nicht tut. Dies ist mit der Tatsache verbunden, dass der Tick-Flow aus irgendwelchen Gründen, ohne Neustart, unterbrochen werden kann. Außerdem wird bei der Alternative 2 die Variable _time_waiting als statisch beschrieben, wodurch ihr Wert zwischen den start() Funktionsaufrufen beibehalten wird, was bei Alternative 1 nicht erforderlich ist.

Die etwas längeren Codes bei den Alternativen, im Vergleich zur Realisierung der Pause durch den Sleep() Funktionsaufruf, sind der Preis dafür, die Ausfallzeiten loszuwerden. Allerdings erzeugt der Umstand, dass es keine Ausfallzeit gibt, das Problem der wiederholten Verwendung der Variablen _time_waiting im Programmcode, da Sie ihn nicht mit einem Wert initalisieren können, solange die vorhergehende Pause nicht abgelaufen ist. Dieses Problem kann auf mindestens zwei Arten gelöst werden, wobei die Wahl der einen oder anderen Alternative vom Stil des Programmierers und seinen Vorlieben abhängt:

1) Sie können Ihre eigene Variable für jede Gruppe von Bedingungen verwenden, um die Ablaufzeit der entsprechenden Pause zu speichern; oder

2) Sie können die Variable _time_waiting als eine Anordnung beschreiben.

Ich nehme an, dass es sinnvoll ist, eine kleine Bibliothek hinsichtlich der Realisierung von Timer-Funktionen anzulegen. Dieser Timer muss eine ausreichende Menge an Zählervariablen und Initialisierungsfunktionen zum Hinzufügen und Löschen der kontollierten Ausschnitte haben. Außerdem können Sie sowohl einen Countdown (rückwärtslaufende Uhr) als auch einen Aufwärtszähler (Stoppuhr) realisieren. Ein Beispiel, wie eine solche Bibliothek zu realisieren ist, ist diesem Artikel angehängt (Datei namens ExLib_Timer.mq4 inklusive dem Quelltext). Eine Header-Datei, die die Prototypen der realisierten Funktionen enthält, ist unterhalb angegeben:

#import "ExLib_Timer.ex4"
//
// Note.
// The counter identifier <CounterID> can take any values except "0",
// since "0" is reserved for the designation of nonactivated counters
// in a general array.
//
void timer_Init();
// start initialization
//
int timer_NumberTotal();
// request for the total amount of timer counters
// Return:
//    total amount of counters
//
int timer_NumberUsed();
// request for the amount of activated counters
// Return:
//    amount of activated counters
//
int timer_NumberFree();
// request for the amount of nonactivated (free) counters
// Return:
//    amount of free counters
//
void timer_ResetAll();
// resetting (zeroing) all counters
//
bool timer_Reset(int CounterID);
// resetting (zeroing) a counter by ID
// Parameters:
//    <CounterID> - counter identifier
// Return:
//    true  - resetted
//    false - no counter with such ID is found
//
void timer_DeleteAll();
// deletion of all counters
//
bool timer_Delete(int CounterID);
// deleting a counter by ID
// Parameters:
//    <CounterID> - counter identifier
// Return:
//    true  - deleted
//    false - no counter with such ID is found
//

bool timer_StartWaitable(int CounterID, int timeslice);
// starting a counter of the "wait timer" type
// Parameters:
//    <CounterID> - counter identifier (if it is not available, a counter is added)
//    <timeslice> - wait period (seconds)
// Return:
//    true  - started
//    false - no free counters
//
bool timer_StartStopwatch(int CounterID);
// starting a counter of the "stopwatch" type
// Parameters:
//    <CounterID> - counter identifier (if it is not available, a counter is added)
// Return:
//    true  - started
//    false - no free counters
//
int timer_GetCounter(int CounterID);
// request for the indications of the counter with ID <CounterID>
// Return:
//    for a counter of the "stopwatch" type, it is the amount of seconds elapsed since the start
//    for a counter of the "wait timer" type, it is the amount of seconds left till the end of wait period
// Note:
//    in case of no counter with ID <CounterID>, -1 is returned
//
int timer_GetType(int CounterID);
// request for a counter with ID <CounterID>
// Parameters:
//    <CounterID> - counter identifier
// Return:
//     1 - counter of the "stopwatch" type
//    -1 - counter of the "wait timer" type
//     0 - no counter with such ID is found
//
int timer_GetCounterIDbyPOS(int CounterPOS);
// request for a counter ID by its position among the activated ones
// Parameters:
//    <CounterPOS> - the number of the counter position among the activated ones
// Return:
//    counter identifier or "0" if a nonexisting position is specified
// Note:
//    <CounterPOS> can take the values ranging from 0 up to the amount of the activated counters,
//    returned by function timer_NumberUsed(). Otherwise, it returns 0
//
#import

Die Unterschiede zwischen dem Sleep() Funktionsaufruf und der alternativen Realisierung einer Pause durch Einträge in ein Protokoll wird klar und deutlich durch einen kleinen Expert Advisor demonstriert, dessen Text unterhalb angeführt ist. Die alternative Realisierung der Pause wird durch den Eingangsparameter Use_Sleep - "true" um Sleep() zu nutzen, oder durch "false" um Sleep() zu verweigern, festgelegt.

#include "include/ExLib_Timer.mqh"
// --
//---- input parameters
extern bool Use_Sleep = false;
// =true  - using function "Sleep()"
// =false - using a timer
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   timer_Init();
   if ( Use_Sleep )
      Print("init(). * Using function Sleep() *");
   else
      Print("init(). * Using a timer *");
   timer_StartWaitable(101, 10);
   timer_StartStopwatch(102);
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
   timer_DeleteAll();
   Comment("");
   return(0);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   Comment("Waitable:",timer_GetCounter(101)," / Stopwatch:",timer_GetCounter(102));
   Print("start() - initial block -");
// --
   if ( Use_Sleep )
   {
      //  - using function "Sleep()" -
      Sleep( 10000 ); // sleep for 10 seconds
      // program block to be executed after the pause ends
      Print("start() - block to be executed after the pause -");
   }
   else
   {
      //  - using a timer -
      if ( timer_GetType(101) == 0 )
         timer_StartWaitable(101, 10); // sleep for 10 seconds
        
      if ( timer_GetCounter(101) == 0 )
      {
         // program block to be executed after the pause ends
         timer_Delete(101);
         Print("start() - block to be executed after the pause -");
      }
   }
// --
   Print("start() - end block -");
   return(0);
}

Neben dem oben angeführten EA gibt es zwei weitere Demo-EAs, die diesem Artikel angehängt sind:
Ex_Timer_OrderLimits_TrailByTime.mq4 demonstriert, wie nachziehende SL und TP durch Zeit realisiert werden, und
Ex_Timer_OrderSend_wMinTimeLimit.mq4 demonstriert, wie man in einem festgelegten Zeitraum eines aktuellen Charts, eine Order nicht öfter als einmal platziert.

Kleinere Nachteile oder "Ein Löffel voll Teer"?

Leider kann die gegebene Bibliothek die Funktion Sleep() nicht vollständig ersetzen. Es gibt hier zwei Nachteile, die dem Leser zur Kenntnis gebracht werden müssen.

Wenn Sie die Funktion Sleep() verwenden, erfolg die Programmausführung unmittelbar nachdem die Pause vorüber ist. Wenn Sie einen Timer verwenden, wird es nur fortgesetzt, sobald der erste Tick nach der Pause eintrifft. Dies kann dazu führen, dass der verzögerte Block zu spät ausgeführt wird oder wie bereits oben erwähnt wurde, dass er überhauptnicht ausgeführt wird (beispielsweise im Falle eines kritischen Fehlers beim Übertragungskanal).

Zweitens können Sie bei der Funktion Sleep() eine Pause mit Schritten von 0,1 Sek einstellen, während beim Timer nur 1-Sekunden-Schritte möglich sind.

Fazit

Wie so oft sind die oben angeführten Vorteile der Realisierung der alternativen Pause gegenüber der Vewendung der Sleep() Funktion nicht unfehlbar, denn es gibt einige Feinheiten. Alles hat seine Stärken und Schwächen, und diese hängen vom verfolgten Zweck ab. Sleep() oder keine Sleep() Funktion, auf was zu verzichten und was zu bevorzugen - dies kann nicht allgemein entschieden werden, sondern muss im Rahmen des Projekts bewertet werden.

Anhänge:

Funktionen-Bibliothek:

  • ExLib_Timer.mqh - Header-Datei;
  • ExLib_Timer.mq4 - Quelltext.

Beispiele der Nutzung:

  • Ex_Timer_SleepOrNot.mq4 - ein Expert Advisor, der die Unterschiede zwischen den Alternativen der Realisierung von Pausen deutlich demonstriert;
  • Ex_Timer_OrderLimits_TrailByTime.mq4 - ein EA, der nachziehende SL und TP durch Zeit demonstriert;
  • Ex_Timer_OrderSend_wMinTimeLimit.mq4 - ein EA, der das einmalige Platzieren von Orders in einem festgelegten Zeitraum eines aktuellen Charts demonstriert.

Wichtig! Die EAs von "Ex_Timer_OrderLimits_TrailByTime" und "Ex_Timer_OrderSend_wMinTimeLimit" sind nur für die Verwendung auf Demo-Konten vorgesehen!

Übersetzt von Russisch durch MetaQuotes Software Corp.
Ursprünglicher Artikel: /ru/articles/1558

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

Besonderheiten von Expert Advisors Besonderheiten von Expert Advisors
Expert Advisors im Handelssystem MetaTrader 4 schreiben und testen
Die gleichzeitige Anzeige der einigen Indikatoren-Signale von vier Timeframes Die gleichzeitige Anzeige der einigen Indikatoren-Signale von vier Timeframes
Beim manuellen Handel, im Unterschied mit einem mechanischen Handel, muss der Trader ständig auf die Werte einiger Indikatoren beachten. Wenn es die Indikatoren zum Beispiel, zwei oder drei gibt, und für den Handel eine Timeframe gewählt ist, so ist es gar keine unkomplizierte Aufgabe. Und wie man sonst so machen soll, wenn es die Indikatoren - fünf oder sechs gibt, und die Handelsstrategie verpflichtet, die Signale auf einigen Timeframes zu berücksichtigen?
Pause zwischen Trades Pause zwischen Trades
In diesem Artikel geht es darum, wie man eine Pause zwischen Trades einlegt, wenn mehrere Expert Advisors in einem MT 4 Terminal arbeiten. Die Zielgruppe des Artikels bilden Nutzer, die bereits Grundkenntnisse über das Terminal und Programmieren in MQL4 haben.
Die Individualpsychologie eines Traders Die Individualpsychologie eines Traders
Das Verhalten des Traders auf dem Finanzmarkt. Die persönliche Sammlung des Autors aus dem Buch von A. Elder "Trading for a Living".