OnTick

É chamada em EAs quando ocorre o evento NewTick para processar uma nova cotação.

void  OnTick(void);

Valor retornado

Sem valor retornado

Observação

O evento NewTick é gerado apenas para EAs após a chegada de um novo tick do símbolo cujo EA é anexado ao gráfico. É inútil definir a função OnTick() no indicador personalizado ou no script, pois o evento NewTick não é gerado para eles.

O evento Tick é gerado apenas para EAs, mas isso não significa que os EAs precisam ter a função OnTick(), porque não apenas os eventos NewTick são gerados para EAs, mas também os eventos Timer, BookEvent e ChartEvent.

Todos os eventos são processados um após o outro na ordem em que são recebidos. Se na fila já houver um evento NewTick ou este evento estiver no estado de processamento, o novo evento NewTick não será colocado na fila do programa MQL5.

O evento NewTick é gerado independentemente de se a negociação automática está habilitada ou desabilitada (o botão "Negociação automática"). Ao desabilitar a negociação automática, será apenas desativado o envio de solicitações de negociação a partir do EA, ao mesmo tempo, o EA continua trabalhando.

Ao desativar a negociação automática clicando no botão "Negociação automática", não se interrompe a execução atual da função OnTick().

Exemplo de EA em que toda a lógica de negociação é colocada na função 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 "Exemplo de EA que opera segundo a direção da vela \"detonante\""
#property description "O corpo da vela \"detonante\" tem um tamanho maior que k*ATR"
#property description "O parâmetro \"revers\" inverte a direção do sinal"
 
input double lots=0.1;        // volume em lotes
input double kATR=3;          // tamanho da vela de sinal no ATR
input int    ATRperiod=20;    // período do indicador ATR
input int    holdbars=8;      // número de barras para manter a posição
input int    slippage=10;     // derrapagem admissível
input bool   revers=false;    // invertemos o sinal? 
input ulong  EXPERT_MAGIC=0;  // MagicNumber do EA
//--- para armazenar o identificador do indicador ATR
int atr_handle;
//--- aqui vamos armazenar os últimos valores do ATR e o corpo da vela
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- inicializamos as variáveis globais
   last_atr=0;
   last_body=0;
//--- definimos o volume correto
   double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   trade_lot=lots>min_lot? lots:min_lot;   
//--- criamos o identificador do indicador ATR
   atr_handle=iATR(_Symbol,_Period,ATRperiod);
   if(atr_handle==INVALID_HANDLE)
     {
      PrintFormat("%s: não foi possível criar o iATR, código de erro %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- inicialização bem-sucedida do EA
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- relatamos o código de desligamento do EA
   Print(__FILE__,": Código de motivo da desinicialização = ",reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- sinal de negociação
   static int signal=0; // +1 significa um sinal de compra, -1 significa um sinal de venda
//--- verificamos e fechamos as posições abertas antigas, abertas há mais de holdbars barras atrás
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- verificamos o surgimento de uma nova barra
   if(isNewBar())
     {
      //--- verificamos a presença de sinal      
      signal=CheckSignal();
     }
//--- se aberta uma posição de 'netting', ignoramos o sinal e esperamos até que ele feche
   if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
     {
      signal=0;
      return// saímos do manipulador de eventos NewTick e não entramos no mercado até que apareça uma nova barra
     }
//--- para contas de cobertura ('hedge'), casa posição tem vida e fecha separadamente
   if(signal!=0)
     {
      //--- sinal de compra
      if(signal>0)
        {
         PrintFormat("%s: Existe um sinal de compra! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- sinal de venda
      if(signal<0)
        {
         PrintFormat("%s: Existe um sinal de venda! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- fim da função OnTick
  }
//+------------------------------------------------------------------+
//| Verificando se á sinal de negociação                             |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0 significa que não há sinal
   int res=0;
//--- obtemos o valor do ATR na penúltima barra concluída (o índice da barra igual a 2)
   double atr_value[1];
   if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
     {
      last_atr=atr_value[0];
      //--- recebemos os dados da última barra fechada numa matriz do tipo MqlRates
      MqlRates bar[1];
      if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
        {
         //--- calculamos o tamanho do corpo da barra na última barra fechada
         last_body=bar[0].close-bar[0].open;
         //--- se o corpo da última barra (com índice 1) exceder o valor anterior do ATR (na barra com índice 2), o sinal de negociação é recebido
         if(MathAbs(last_body)>kATR*last_atr)
            res=last_body>0?1:-1; // para a leva altista um valor positivo
        }
      else
         PrintFormat("%s: Não foi possível obter a última barra! Erro",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("%s: Não foi possível obter o valor do indicador ATR! Erro",__FUNCTION__,GetLastError());
//--- se estiver ativado o modo de negociação de reversão
   res=revers?-res:res;  // se necessário, revertemos o sinal (em vez de 1, retornamos -1, e, em vez de -1, retornamos +1)
//--- retornamos o valor do sinal de negociação
   return (res);
  }
//+------------------------------------------------------------------+
//|  Retornando true quando aparece uma nova barra                   |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // armazenamos o tempo de abertura da barra atual
//--- obtemos o tempo de abertura da barra zero
   datetime currbar_time=iTime(_Symbol,_Period,0);
//--- se o tempo de abertura mudar, é porque apareceu uma nova barra
   if(bartime!=currbar_time)
     {
      bartime=currbar_time;
      lastbar_timeopen=bartime;
      //--- exibir no log informações sobre o tempo de abertura da nova barra      
      if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
        {
         //--- exibimos uma mensagem sobre o tempo de abertura da nova barra
         PrintFormat("%s: new bar on %s %s opened at %s",__FUNCTION__,_Symbol,
                     StringSubstr(EnumToString(_Period),7),
                     TimeToString(TimeCurrent(),TIME_SECONDS));
         //--- obtemos os dados do último tick
         MqlTick last_tick;
         if(!SymbolInfoTick(Symbol(),last_tick))
            Print("SymbolInfoTick() failed, error = ",GetLastError());
         //--- exibimos o tempo do último tick em segundos
         PrintFormat("Last tick was at %s.%03d",
                     TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
        }
      //--- temos uma nova barra
      return (true);
     }
//--- não há nenhuma barra nova
   return (false);
  }
//+------------------------------------------------------------------+
//| Comprando a mercado com o volume especificado                    |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- compramos a mercado
   return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Vendendo a mercado com o volume definido                          |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- vendemos a mercado
   return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Fechando posições segundo o tempo de retenção nas barras         |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
  {
   int total=PositionsTotal(); // número de posições abertas   
//--- pesquisa detalhada de todas as posições abertas
   for(int i=total-1; i>=0; i--)
     {
      //--- parâmetros da posição
      ulong  position_ticket=PositionGetTicket(i);                                      // boleta da posição
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // símbolo 
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber da posição
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // tempo de abertura da posição
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // há quantos barras atrás foi aberta a posição
 
      //--- se a posição tem vivido por um longo tempo, e também o MagicNumber e o símbolo são os mesmos
      if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
        {
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // número de casas decimais
         double volume=PositionGetDouble(POSITION_VOLUME);                              // volume da posição
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // tipo de posição
         string str_type=StringSubstr(EnumToString(type),14);
         StringToLower(str_type); // reduzimos o registro do texto para uma correta formatação da mensagem
         PrintFormat("Fechamos a posição #%I64u %s %s %.2f",
                     position_ticket,position_symbol,str_type,volume);
         //--- definindo o tipo de ordem e de envio do pedido de negociação
         if(type==POSITION_TYPE_BUY)
            MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
         else
            MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
        }
     }
  }
//+------------------------------------------------------------------+
//| Preparando e enviando uma solicitação de negociação              |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
  {
//--- declaração e inicialização de estruturas
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   if(type==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- parâmetros da solicitação
   request.action   =TRADE_ACTION_DEAL;                     // tipo de operação de negociação
   request.position =pos_ticket;                            // boleta da posição, se fechada
   request.symbol   =Symbol();                              // símbolo
   request.volume   =volume;                                // volume 
   request.type     =type;                                  // tipo de ordem
   request.price    =price;                                 // preço de transação
   request.deviation=slip;                                  // desvio permitido em relação ao preço
   request.magic    =magicnumber;                           // MagicNumber da ordem
//--- envio do pedido
   if(!OrderSend(request,result))
     {
      //--- exibimos as informações sobre a falha
      PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
                  request.symbol,EnumToString(type),volume,request.price,GetLastError());
      return (false);
     }
//--- relatamos sobre a operação bem-sucedida
   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   return (true);
  }

Veja também

Funções de processamento de eventos, Execução de programas, Eventos do terminal do cliente, OnTimer, OnBookEvent, OnChartEvent