OnTick

Вызывается в экспертах при наступлении события NewTick для обработки новой котировки.

void  OnTick(void);

Возвращаемое значение

Нет возвращаемого значения

Примечание

Событие NewTick генерируется только для экспертов при поступлении нового тика по символу, к графику которого прикреплен эксперт. Функцию OnTick() бесполезно определять в пользовательском индикаторе или скрипте, поскольку событие NewTick для них не генерируется.

Событие Tick генерируется только для экспертов, но это не означает, что эксперты обязаны иметь функцию OnTick(), так как для экспертов генерируются не только события NewTick, но и события Timer, BookEvent и ChartEvent.

Все события обрабатываются одно за другим в порядке поступления. Если в очереди уже есть событие NewTick либо это событие находится в состоянии обработки, то новое событие NewTick в очередь mql5-программы не ставится.

Событие NewTick генерируется независимо от того, запрещена или разрешена автоматическая торговля (кнопка "Авто-торговля"). Запрет автоматической торговли означает только запрет на отправку торговых запросов из эксперта, работа эксперта при этом не прекращается.

Запрет автоматической торговли путем нажатия кнопки "Авто-торговля" не прерывает текущее выполнение функции OnTick().

Пример эксперта, в котором вся торговая логика помещена в функцию 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 "Пример советника, торгующего в направлении \"взрывной\" свечи"
#property description "\"Взрывная\" свеча имеет тело размером более k*ATR"
#property description "Параметр \"revers\" переворачивает направление сигнала"
 
input double lots=0.1;        // объем в лотах
input double kATR=3;          // длина сигнальной свечи в ATR
input int    ATRperiod=20;    // период индикатора ATR
input int    holdbars=8;      // сколько баров удерживаем позицию
input int    slippage=10;     // допустимое проскальзывание
input bool   revers=false;    // переворачиваем сигнал? 
input ulong  EXPERT_MAGIC=0;  // MagicNumber эксперта
//--- для хранения хендла индикатора ATR
int atr_handle;
//--- здесь будем хранить последние значения ATR и тела свечи
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- инициализируем глобальные переменные
   last_atr=0;
   last_body=0;
//--- установим правильный объем
   double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   trade_lot=lots>min_lot? lots:min_lot;   
//--- создадим хендл индикатора ATR
   atr_handle=iATR(_Symbol,_Period,ATRperiod);
   if(atr_handle==INVALID_HANDLE)
     {
      PrintFormat("%s: не удалось создать iATR, код ошибки %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- успешная инициализация эксперта
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- сообщим код завершения работы эксперта
   Print(__FILE__,": Код причины деинициализации = ",reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- торговый сигнал
   static int signal=0; // +1 означает сигнал на покупку, -1 означает сигнал на продажу
//--- проверим и закроем старые позиции, открытые более holdbars баров назад 
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- проверим появление нового бара
   if(isNewBar())
     {
      //--- проверим наличие сигнала      
      signal=CheckSignal();
     }
//--- если открыта неттинговая позиция, то сигнал пропускаем - ждем, пока она закроется
   if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
     {
      signal=0;
      return// выходим из обработчика события NewTick и не входим в рынок до появления нового бара
     }
//--- для хеджингового счета каждая позиция живет и закрывается раздельно
   if(signal!=0)
     {
      //--- сигнал на покупку
      if(signal>0)
        {
         PrintFormat("%s: Есть сигнал на покупку! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- сигнал на продажу
      if(signal<0)
        {
         PrintFormat("%s: Есть сигнал на продажу! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- конец функции OnTick
  }
//+------------------------------------------------------------------+
//| Проверяет наличие торгового сигнала                              |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0 означает отсутствие сигнала
   int res=0;
//--- получим значение ATR на предпоследнем завершенном баре (индекс бара равен 2)
   double atr_value[1];
   if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
     {
      last_atr=atr_value[0];
      //--- получим данные последнего закрытого бара в массив типа MqlRates
      MqlRates bar[1];
      if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
        {
         //--- вычислим размер тела бара на последнем закрытом баре
         last_body=bar[0].close-bar[0].open;
         //--- если тело последнего бара (с индексом 1) превышает предыдущее значение ATR (на баре с индексом 2), то торговый сигнал получен
         if(MathAbs(last_body)>kATR*last_atr)
            res=last_body>0?1:-1; // для растущей свечи положительное значение
        }
      else
         PrintFormat("%s: Не удалось получить последний бар! Ошибка",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("%s: Не удалось получить значение индикатора ATR! Ошибка",__FUNCTION__,GetLastError());
//--- если включен реверсивный режим торговли
   res=revers?-res:res;  // если нужно, то развернем сигнал (вместо 1 вернем -1, а вместо -1 вернем +1)
//--- вернем значение торгового сигнала
   return (res);
  }
//+------------------------------------------------------------------+
//|  Возвращает true при появлении нового бара                       |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // храним время открытия текущего бара
//--- получим время открытия нулевого бара
   datetime currbar_time=iTime(_Symbol,_Period,0);
//--- если время открытия изменилось, значит появился новый бар
   if(bartime!=currbar_time)
     {
      bartime=currbar_time;
      lastbar_timeopen=bartime;
      //--- нужно ли выводить в лог информацию о времени открытия нового бара      
      if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
        {
         //--- выведем сообщение о времени открытия нового бара
         PrintFormat("%s: new bar on %s %s opened at %s",__FUNCTION__,_Symbol,
                     StringSubstr(EnumToString(_Period),7),
                     TimeToString(TimeCurrent(),TIME_SECONDS));
         //--- получим данные о последнем тике
         MqlTick last_tick;
         if(!SymbolInfoTick(Symbol(),last_tick))
            Print("SymbolInfoTick() failed, error = ",GetLastError());
         //--- выведем время последнего тика с точностью до миллисекунд
         PrintFormat("Last tick was at %s.%03d",
                     TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
        }
      //--- у нас есть новый бар
      return (true);
     }
//--- нового бара нет
   return (false);
  }
//+------------------------------------------------------------------+
//| Покупка по рынку с заданным объемом                              |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- покупаем по рыночной цене
   return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Продажа по рынку с заданным объемом                              |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- продаем по рыночной цене
   return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Закрытие позиций по времени удержания в барах                    |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
  {
   int total=PositionsTotal(); // количество открытых позиций   
//--- перебор всех открытых позиций
   for(int i=total-1; i>=0; i--)
     {
      //--- параметры позиции
      ulong  position_ticket=PositionGetTicket(i);                                      // тикет позиции
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // символ 
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber позиции
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // время открытия позиции
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // сколько баров назад была открыта позиция
 
      //--- если позиция живет уже долго, а также MagicNumber и символ совпадают
      if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
        {
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // количество знаков после запятой
         double volume=PositionGetDouble(POSITION_VOLUME);                              // объем позиции
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // тип позиции
         string str_type=StringSubstr(EnumToString(type),14);
         StringToLower(str_type); // понижаем регистр текста для правильного форматирования сообщения
         PrintFormat("Закрываем позицию #%I64u %s %s %.2f",
                     position_ticket,position_symbol,str_type,volume);
         //--- установка типа ордера и отправки торгового запроса
         if(type==POSITION_TYPE_BUY)
            MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
         else
            MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
        }
     }
  }
//+------------------------------------------------------------------+
//| Подготовка и отправка торгового запроса                          |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
  {
//--- объявление и инициализация cтруктур
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   if(type==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- параметры запроса
   request.action   =TRADE_ACTION_DEAL;                     // тип торговой операции
   request.position =pos_ticket;                            // тикет позиции, если закрываем
   request.symbol   =Symbol();                              // символ
   request.volume   =volume;                                // объем 
   request.type     =type;                                  // тип ордера
   request.price    =price;                                 // цена совершения сделки
   request.deviation=slip;                                  // допустимое отклонение от цены
   request.magic    =magicnumber;                           // MagicNumber ордера
//--- отправка запроса
   if(!OrderSend(request,result))
     {
      //--- выведем информацию о неудаче
      PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
                  request.symbol,EnumToString(type),volume,request.price,GetLastError());
      return (false);
     }
//--- сообщим об успешной операции
   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   return (true);
  }

Смотри также

Функции обработки событий, Выполнение программ, События клиентского терминала, OnTimer, OnBookEvent, OnChartEvent