OnTick() EA Function Skips Ticks - page 2

 
Hello Hello.
Please, I have the same problem of different ticks between live and backtest .
My EA code ex:
//
ontick()
{
Print(marketinfoBid)
}
///
I launch my EA live for a minute and I display all the prices per tick.
When I run my MT4 backtest over the same period, I get a different result.

Do you have an idea please, I'm lost

Thank you so much.
[Deleted]  
Amine Tazi #: Hello Hello. Please, I have the same problem of different ticks between live and backtest . My EA code ex: I launch my EA live for a minute and I display all the prices per tick. When I run my MT4 backtest over the same period, I get a different result. Do you have an idea please, I'm lost. Thank you so much.

That is expected behaviour when ticks arrive during the processing of the OnTick() events.

On MT4, there is nothing you can do about it as it does not have a Tick Data history like on MT5, where you would CopyTicks to access all the tick data.

Documentation on MQL5: Timeseries and Indicators Access / CopyTicks
Documentation on MQL5: Timeseries and Indicators Access / CopyTicks
  • www.mql5.com
CopyTicks - Timeseries and Indicators Access - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 

I knew OnTick would miss a couple tick in fast market in live env but actually misses a lot even in quiet market.

sharing you a code so you can check it yourself too so ppl can enhance their logic to handle if they are coding a strategy that tick analysis is important.

  //+------------------------------------------------------------------+
  //| OnTickBehaviorTest EA                                            |
  //+------------------------------------------------------------------+
  #define _DigitsPrc    _Digits                                                            // number of digits after the decimal point in the symbol's price. ES/MES: 2 decimal digits (5321.25)
  #define _DigitsVol    (int) MathLog10(1.0/SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP)) // number of digits after the decimal point in the symbol's volume step. ES/MES: 0 decimal digits (VOLUME_STEP = 1.0)
  input bool i_bLogAllTicks = true; // Log individual tick details
  
  void OnTick(){
    MqlTick stTick; if(!SymbolInfoTick(_Symbol, stTick)) return;
    if((stTick.flags & TICK_FLAG_LAST) == 0) return;
    if(stTick.last == 0.0) return;
  
    static ulong s_ulSeed        = 0;
    static ulong s_ulOnTickCount = 0; s_ulOnTickCount++;
           ulong  ulCurrentMsc   = (ulong)stTick.time_msc;
           double dLst           = stTick.last;
           double dVol           = stTick.volume_real;
  
//    PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f]", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol);
  
    // First OnTick: seed only
    if(s_ulSeed == 0){
      s_ulSeed = ulCurrentMsc;
      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] seed initialized=%s", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(s_ulSeed));
      return;
    }
  
    // same timestamp, skip
    if(ulCurrentMsc == s_ulSeed){
//      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] duplicate, skip", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol);
//      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] duplicate msc=%s == seed, skip", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(ulCurrentMsc));
      return;
    }
  
    // diff timestamp, copy missed ticks
    MqlTick aTicks[];
    ulong   ulFrom = s_ulSeed;
    ulong   ulTo   = ulCurrentMsc - 1;
  
    int iCopied = CopyTicksRange(_Symbol, aTicks, COPY_TICKS_TRADE, ulFrom, ulTo); // COPY_TICKS_TRADE = LAST ticks only
  
    if(iCopied < 0){
      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] CopyTicksRange(from:%s to:%s) => ERROR=%d", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(ulFrom), f_sTimeMscToStr(ulTo), GetLastError());
    }else
    if(iCopied == 0){
      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] CopyTicksRange(from:%s to:%s) => copied=0, no miss", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(ulFrom), f_sTimeMscToStr(ulTo));
    }else
    if(iCopied == 1){
      PrintFormat("▶ OnTick #%llu %s [Lst=%.*f, Vol=%.*f] CopyTicksRange(from:%s to:%s) => copied=1, no miss", s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(ulFrom), f_sTimeMscToStr(ulTo));
      if(i_bLogAllTicks) PrintFormat("  [0] %s last=%.*f vol=%.*f", f_sTimeMscToStr((ulong)aTicks[0].time_msc), _DigitsPrc, aTicks[0].last, _DigitsVol, aTicks[0].volume_real);
    }else{
      // check if all copied ticks share the same timestamp
      bool bSameMsc = true;
      ulong ulFirstMsc = (ulong)aTicks[0].time_msc;
      for(int i = 1; i < iCopied; i++){
        if((ulong)aTicks[i].time_msc != ulFirstMsc){ bSameMsc = false; break; }
      }
      string sMarker = bSameMsc ? "▶" : "★";
  
      PrintFormat("%s OnTick #%llu %s [Lst=%.*f, Vol=%.*f] CopyTicksRange(from:%s to:%s) => copied=%d, MISSED=%d ticks", sMarker, s_ulOnTickCount, f_sTimeMscToStr(ulCurrentMsc), _DigitsPrc, dLst, _DigitsVol, dVol, f_sTimeMscToStr(ulFrom), f_sTimeMscToStr(ulTo), iCopied, iCopied - 1);
      if(i_bLogAllTicks){
        for(int i = 0; i < iCopied; i++){
          PrintFormat("  [%d] %s last=%.*f vol=%.*f", i, f_sTimeMscToStr((ulong)aTicks[i].time_msc), _DigitsPrc, aTicks[i].last, _DigitsVol, aTicks[i].volume_real);
        }
      }
    }
  
    //--- Update seed
    s_ulSeed = ulCurrentMsc;
//    PrintFormat("  seed updated=%s", f_sTimeMscToStr(s_ulSeed));
  }
  //========================================
  // Long(time_msc)2String
  //========================================
  string f_sTimeMscToStr(const ulong ulTimeMsc){
    datetime tSec = (datetime)(ulTimeMsc / 1000);
    uint     ms   = (uint)(ulTimeMsc % 1000);
  
    return(StringFormat("%s.%03u", TimeToString(tSec, TIME_DATE|TIME_SECONDS), ms));
  }

output with ★ is when tick is skipped by OnTick. ▶ is when tick has dup timestamp

good luck guys ^_<)-★ wink