OnTick

Die Funktion wird von EAs aufgerufen, wenn das Ereignis NewTick eintritt, um einen neuen Preis abzuarbeiten.

void  OnTick(void);

Rückgabewert

Kein Rückgabewert

Hinweis

Das Ereignis NewTick wird nur für EAs erzeugt, wenn ein neuer Tick für ein Symbol des Charts eintrifft, auf dem der EA läuft. Es macht keinen Sinn, die Funktion OnTick() in einem benutzerdefinierten Indikator oder einem Skript zu definieren, da für sie kein NewTick-Ereignis generiert wird.

Das Ereignis eines Ticks wird nur für EAs generiert, aber das bedeutet nicht, dass EAs die OnTick() unbedingt besitzen müssen, neben OnTick() auch die Ereignisse Timer, BookEvent und ChartEvent für EAs generiert werden.

Alle Ereignisse werden nacheinander in der Reihenfolge ihres Eintreffens behandelt. Wenn die Warteschlange bereits das Ereignis NewTick enthält, oder sich dieses Ereignis in der Verarbeitungsphase befindet, dann wird das neue Ereignis NewTick nicht in die Warteschlange des MQL5-Programms hinzugefügt.

Das Ereignis NewTick wird unabhängig davon generiert, ob der automatische Handel aktiviert ist (Schaltfläche AutoTrading). Ein deaktivierter Autohandel bedeutet nur ein Verbot des Sendens von Handelsanfragen von einem EA. Die Arbeitsweise des EAs wird nicht beeinträchtigt.

Das Deaktivieren des automatischen Handels durch Drücken der Schaltfläche AutoTrading unterbricht nicht die aktuelle Ausführung der Funktion OnTick().

Beispiel des EA mit seiner gesamten Handelslogik in der Funktion OnTick()

//+------------------------------------------------------------------+
//|                                                   TradeByATR.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Sample EA trading in the \"explosive\" candle direction"
#property description "\"Explosive\" candle has the body size exceeding k*ATR"
#property description "The \"revers\" parameter reverses the signal direction"
 
input double lots=0.1;        // Volumen in Lots
input double kATR=3;          // Länge der Signalkerze in ATR
input int    ATRperiod=20;    // Periodenlänge des ATR
input int    holdbars=8;      // Anzahl der Bars, die die Position gehalten werden soll
input int    slippage=10;     // Erlaubter Schlupf
input bool   revers=false;    // Signal umkehren? 
input ulong  EXPERT_MAGIC=0;  // Des EA's Magicnummer
//--- zum Sichern des Handles des Indikators ATR
int atr_handle;
//--- hier werden die letzten Werte des ATR und die Kerzenkörper gesichert
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Expert Initialisierungsfunktion                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initialisierung der Globalen Variablen
   last_atr=0;
   last_body=0;
//--- Setzen des korrekten Volumens
   double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   trade_lot=lots>min_lot? lots:min_lot;   
//--- Erstellen des Handles des Indikators ATR
   atr_handle=iATR(_Symbol,_Period,ATRperiod);
   if(atr_handle==INVALID_HANDLE)
     {
      PrintFormat("%s: failed to create iATR, error code %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- Erfolgreiche Initialisierung des EA
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Information über das Ende der Arbeit des EAs
   Print(__FILE__,": Deinitialization reason code = ",reason);
  }
//+------------------------------------------------------------------+
//| Tick-Funktion des Experten                                       |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Handelssignal
   static int signal=0; // +1 heißt Kaufsignal, -1 Verkaufssignal
//--- Prüfen und Schließen alter Positionen, die vor mehr als 'holdbars' eröffnet wurden
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- Prüfen auf eine neue Bar
   if(isNewBar())
     {
      //--- Prüfen auf ein Signal
      signal=CheckSignal();
     }
//--- Wenn eine Netting-Position eröffnet wurde - warten bis sie geschlossen wurde
   if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
     {
      signal=0;
      return// die Ereignisbehandlung von NewTick beenden und kein Markteintritt vor dem nächsten Tick
     }
//--- für ein Hedging-Konto wird jede Position separat gehalten und geschlossen
   if(signal!=0)
     {
      //--- Kaufsignal
      if(signal>0)
        {
         PrintFormat("%s: Buy signal! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- Verkaufssignal
      if(signal<0)
        {
         PrintFormat("%s: Sell signal! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- Ende der Funktion OnTick
  }
//+------------------------------------------------------------------+
//| Prüfen auf ein neues Handelssignal                               |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0 beutet klein Signal
   int res=0;
//--- Abfrage des Wertes der ATR der vorletzten kompletten Bar (Indes der Bar ist 2)
   double atr_value[1];
   if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
     {
      last_atr=atr_value[0];
      //--- Datenabfrage der letzten geschlossenen Bar von Array des Typs MqlRates
      MqlRates bar[1];
      if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
        {
         //--- Berechnen der Körpergröße der letzten, vollständigen Kerze
         last_body=bar[0].close-bar[0].open;
         //--- wenn der Körper der letzten Bar (mit Index 1) den vorherigen ATR-Wert überschreitet (auf der Bar mit Index 2), wird ein Handelssignal empfangen.
         if(MathAbs(last_body)>kATR*last_atr)
            res=last_body>0?1:-1; // positiver Wert der Aufwärtskerze
        }
      else
         PrintFormat("%s: Failed to receive the last bar! Error",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("%s: Failed to receive ATR indicator value! Error",__FUNCTION__,GetLastError());
//--- falls der umgekehrte Handelsmodus aktiviert ist
   res=revers?-res:res;  // Signal umkehren, wenn nötig (Rückgabe von -1 statt 1 und vice versa)
//--- Rückgabe des Wertes des Handelssignals
   return (res);
  }
//+------------------------------------------------------------------+
//|  Rückgabe von 'true' wenn eine neue Bar erscheint                |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // Sichern der Eröffnungszeit der aktuellen Bar
//--- Abfrage der Eröffnungszeit der Bar Null
   datetime currbar_time=iTime(_Symbol,_Period,0);
//--- Wenn sich die Eröffnungszeit änderte, gibt es eine neue Bar
   if(bartime!=currbar_time)
     {
      bartime=currbar_time;
      lastbar_timeopen=bartime;
      //--- Eintragen der Eröffnungszeit der neuen Bar in das Log
      if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
        {
         //--- Anzeige der Nachricht mit der Eröffnungszeit der neuen bar
         PrintFormat("%s: new bar on %s %s opened at %s",__FUNCTION__,_Symbol,
                     StringSubstr(EnumToString(_Period),7),
                     TimeToString(TimeCurrent(),TIME_SECONDS));
         //--- Datenabfrage beim letzten Tick
         MqlTick last_tick;
         if(!SymbolInfoTick(Symbol(),last_tick))
            Print("SymbolInfoTick() failed, error = ",GetLastError());
         //--- Anzeige der Zeit des letzten Ticks bis zur Millisekunde
         PrintFormat("Last tick was at %s.%03d",
                     TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
        }
      //--- wir haben eine neue Bar
      return (true);
     }
//--- keine neue Bar
   return (false);
  }
//+------------------------------------------------------------------+
//| Kauf zum Marktpreis mit angegebenen Volumen                    |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- Kauf zum Marktpreis
   return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Verkauf zum Marktpreis mit angegebenen Volumen                |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- Verkauf zum Marktpreis
   return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Position schließen wegen der Haltezeit                           |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
  {
   int total=PositionsTotal(); // Anzahl der offenen Positionen
//--- Iterieren über die offenen Position
   for(int i=total-1; i>=0; i--)
     {
      //--- Parameter der Position
      ulong  position_ticket=PositionGetTicket(i);                                      // Ticketnummer der Position
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // Symbol 
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber der Position
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // Eröffnungszeit der Position
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // wie viele Bars vorher wurde die Position eröffnet
 
      //--- wenn die Lebenszeit der Position lang genug ist, und MagicNummer und Symbol übereinstimme
      if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
        {
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // Dezimalstellen
         double volume=PositionGetDouble(POSITION_VOLUME);                              // Volumen der Position
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type
         string str_type=StringSubstr(EnumToString(type),14);
         StringToLower(str_type); // Kleinschreibung für das korrekte Nachrichtenformat
         PrintFormat("Close position #%I64u %s %s %.2f",
                     position_ticket,position_symbol,str_type,volume);
         //--- Setzen des Auftragsart und Senden der Handelsanfrage
         if(type==POSITION_TYPE_BUY)
            MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
         else
            MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
        }
     }
  }
//+------------------------------------------------------------------+
//| Vorbereiten und Senden der Handelsanfrage                        |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
  {
//--- Deklarieren und Initialisieren der Strukturen
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   if(type==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- Abfrage der Parameter
   request.action   =TRADE_ACTION_DEAL;                     // Typ der Handelsoperation
   request.position =pos_ticket;                            // Ticketnummer der zu schließenden Position
   request.symbol   =Symbol();                              // Symbol
   request.volume   =volume;                                // Volumen 
   request.type     =type;                                  // Auftragsart
   request.price    =price;                                 // Handelspreis
   request.deviation=slip;                                  // erlaubter Schlupf vom Preis
   request.magic    =magicnumber;                           // MagicNumber des Auftrags
//--- Senden einer Anfrage
   if(!OrderSend(request,result))
     {
      //--- Datenanzeige im Fehlerfall
      PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
                  request.symbol,EnumToString(type),volume,request.price,GetLastError());
      return (false);
     }
//--- Information über eine erfolgreiche Operation
   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   return (true);
  }

Siehe auch

Ereignisbearbeiter, Durchführung der Programme, Ereignisse des Client-Terminals, OnTimer, OnBookEvent, OnChartEvent