OnTick

La fonction est appelée dans les EA lorsque l'évènement NewTick se produit pour gérer une nouvelle cotation.

void  OnTick(void);

Valeur de Retour

Aucune valeur de retour

Note

L'évènement NewTick n'est généré que pour les EA lorsqu'un nouveau tick est reçu pour le symbole auquel l'Expert Advisor est attaché. Il est inutile de définir la fonction OnTick() dans un indicateur personnalisé ou dans un script puisque l'évènement NewTick n'est pas généré pour eux.

L'évènement Tick n'est généré que pour les Expert Advisors, mais cela ne signifie pas que les Expert Advisors ont besoin de la fonction OnTick(), puisque les évènements Timer, BookEvent et ChartEvent sont également générés pour les Expert Advisors en plus de NewTick.

Tous les évènements sont gérés les uns après les autres dans l'ordre de réception. Si la queue contient déjà l'évènement NewTick ou que cet évènement est déjà en cours de traitement, alors le nouvel évènement NewTick n'est pas ajouté dans la queue de l'application mql5.

L'évènement NewTick est généré indépendamment du mode d'auto-trading. Le trading automatique désactivé signifie l'interdiction d'envoyer des demandes de trade depuis un EA. Le fonctionnement de l'EA n'est pas stoppé.

Désactier le trading automatique en appuyant sur le bouton AutoTrading n'interrompt pas l'exécution de la fonction OnTick() en cours.

Exemple d'un EA avec sa logique de trading entièrement dans la fonction 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 "EA exemple tradant dans la direction de la bougie \"explosive\""
#property description "Une bougie "Explosive\" a la taille de son corps supérieure à k*ATR"
#property description "Le paramètre \"revers\" renverse la direction du signal"
 
input double lots=0.1;        // volume en lots
input double kATR=3;          // longueur de la bougie de signal dans l'ATR
input int    ATRperiod=20;    // période de l'ATR
input int    holdbars=8;      // nombre de barre pour tenir la position
input int    slippage=10;     // slippage autorisé
input bool   revers=false;    // renversement de signal ? 
input ulong  EXPERT_MAGIC=0;  // nombre magique de l'EA
//--- pour stocker le handle de l'ATR
int atr_handle;
//--- nous stockerons ici les dernières valeurs de l'ATR et le corps de la bougie
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- initialisation des variables globales
   last_atr=0;
   last_body=0;
//--- définit le volume correct
   double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   trade_lot=lots>min_lot? lots:min_lot;   
//--- crée le handle de l'indicateur ATR
   atr_handle=iATR(_Symbol,_Period,ATRperiod);
   if(atr_handle==INVALID_HANDLE)
     {
      PrintFormat("%s: échec de la création de iATR, code d'erreur %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- initialisation réussie de l'EA
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Fonction de dé-initialisation de l'Expert                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- informe du code de fin de l'exécution de l'EA
   Print(__FILE__,": Raison de la désinitialisation = ",reason);
  }
//+------------------------------------------------------------------+
//| Fonction de tick de l'Expert                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- signal de trading
   static int signal=0; // +1 signifie un signal d'achat, -1 signifie un signal de vente
//--- vérifie et ferme les anciennes positions ouvertes plus de 'holdbars' barres auparavant
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- vérifie si c'est une nouvelle barre
   if(isNewBar())
     {
      //--- vérifie la présence d'un signal 
      signal=CheckSignal();
     }
//--- si une position de type netting est ouverte, ignore le signal - attends jusqu'à sa fermeture
   if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
     {
      signal=0;
      return// sors de la fonction NewTick et n'entre pas sur le marché avant qu'une nouvelle barre n'apparaisse
     }
//--- pour un compte de type hedging, chaque position est conservée et fermée séparément
   if(signal!=0)
     {
      //--- signal d'achat
      if(signal>0)
        {
         PrintFormat("%s: Signal d'achat ! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- signal de vente
      if(signal<0)
        {
         PrintFormat("%s: Signal de vente ! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- fin de la fonction OnTick
  }
//+------------------------------------------------------------------+
//| Vérifie la présence d'un nouveau signal de trading               |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0 signifie aucun signal
   int res=0;
//--- récupère la valeur de l'ATR sur l'avant dernière barre (l'indice de la barre est 2)
   double atr_value[1];
   if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
     {
      last_atr=atr_value[0];
      //--- récupère les données de la dernière barre fermée dans le tableau d'éléments de type MqlRates
      MqlRates bar[1];
      if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
        {
         //--- calcule la taille du corps de la dernière barre complétée
         last_body=bar[0].close-bar[0].open;
         //--- si le corps de la dernière barre (avec l'indice 1) est supérieur à la valeur précédente de l'ATR (sur la barre d'indice 2), un signal de trading est reçu
         if(MathAbs(last_body)>kATR*last_atr)
            res=last_body>0?1:-1; // valeur positive pour une bougie haussière
        }
      else
         PrintFormat("%s: Impossible de recevoir la dernière barre ! Erreur",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("%s: Impossible de recevoir la valeur de l'ATR ! Erreur",__FUNCTION__,GetLastError());
//--- si le mode de trading renversé est activé
   res=revers?-res:res;  // retourne le signal si nécessaire (retourne -1 au lieu de 1 et vice versa)
//--- retourne la valeur du signal de trading
   return (res);
  }
//+------------------------------------------------------------------+
//|  Retourne 'true' lorsqu'une nouvelle barre apparaît              |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // stocke l'heure d'ouverture de la barre courante
//--- récupère l'heure d'ouverture de la barre zéro
   datetime currbar_time=iTime(_Symbol,_Period,0);
//--- si l'heure d'ouverture change, une nouvelle barre est arrivée
   if(bartime!=currbar_time)
     {
      bartime=currbar_time;
      lastbar_timeopen=bartime;
      //--- affiche les données de l'heure d'ouverture de la nouvelle barre dans le journal     
      if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
        {
         //--- affiche un message avec l'heure d'ouverture de la nouvelle barre
         PrintFormat("%s: nouvelle barre sur %s %s ouverte à %s",__FUNCTION__,_Symbol,
                     StringSubstr(EnumToString(_Period),7),
                     TimeToString(TimeCurrent(),TIME_SECONDS));
         //--- récupère les données du dernier tick
         MqlTick last_tick;
         if(!SymbolInfoTick(Symbol(),last_tick))
            Print("Echec de SymbolInfoTick(), erreur = ",GetLastError());
         //--- affiche l'heure du dernier tick en millisecondes
         PrintFormat("Le dernier tick était à %s.%03d",
                     TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
        }
      //--- nous avons une nouvelle barre
      return (true);
     }
//--- aucune nouvelle barre
   return (false);
  }
//+------------------------------------------------------------------+
//| Achète au prix du marché avec le volume spécifié                 |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- achète au prix du marché
   return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Vends au prix du marché avec le volume spécifié                 |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- vends au prix du marché
   return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Ferme les positions détenues trop longtemps (en barres)          |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
  {
   int total=PositionsTotal(); // nombre de positions ouvertes
//--- itère sur les positions ouvertes
   for(int i=total-1; i>=0; i--)
     {
      //--- paramètres de la position
      ulong  position_ticket=PositionGetTicket(i);                                      // ticket de la position
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // symbole 
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber de la position
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // heure d'ouverture de la position
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // depuis combien de barres une position est-elle ouverte
 
      //--- si la position est trop vieille et que le MagicNumber et le symbole correspondent
      if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
        {
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // nombre de décimales
         double volume=PositionGetDouble(POSITION_VOLUME);                              // volume de la position
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // type de la position
         string str_type=StringSubstr(EnumToString(type),14);
         StringToLower(str_type); // mets le texte en minuscules
         PrintFormat("Ferme la position #%I64u %s %s %.2f",
                     position_ticket,position_symbol,str_type,volume);
         //--- définit le type de l'ordre et envoie une demande de trade
         if(type==POSITION_TYPE_BUY)
            MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
         else
            MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
        }
     }
  }
//+------------------------------------------------------------------+
//| Prépare et envoie une demande de trade                           |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
  {
//--- déclare et initialise les structures
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   if(type==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- paramètres de la demande
   request.action   =TRADE_ACTION_DEAL;                     // trading operation type
   request.position =pos_ticket;                            // position ticket if closing
   request.symbol   =Symbol();                              // symbole
   request.volume   =volume;                                // volume 
   request.type     =type;                                  // type de l'ordre
   request.price    =price;                                 // prix du trade
   request.deviation=slip;                                  // déviation du prix autorisée
   request.magic    =magicnumber;                           // MagicNumber de l'ordre
//--- envoie une demande
   if(!OrderSend(request,result))
     {
      //--- affiche les informations de l'échec
      PrintFormat("OrderSend %s %s %.2f à %.5f, erreur %d",
                  request.symbol,EnumToString(type),volume,request.price,GetLastError());
      return (false);
     }
//--- information sur l'opération réussie
   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   return (true);
  }

Voir également

Fonctions de gestion des évènements, Exécution du programme, Evènements du terminal client, OnTimer, OnBookEvent, OnChartEvent