Caractéristiques du langage mql5, subtilités et techniques - page 36

 

à quoi mène un démarrage à froid dans un cas comme celui-ci.

2017.04.17 00:27:51.705 Core 1  GOLD-6.17: generate 48836 ticks in 0:00:00.000, passed to tester 48984 ticks
2017.04.17 00:27:51.705 Core 1  GOLD-9.17: generate 3184 ticks in 0:00:00.000, passed to tester 35192 ticks

et c'est ce dont il s'agit.

2017.04.17 00:22:16.126 Trade   2017.04.07 10:00:00   deal performed [#247  buy 1.00 GOLD-9.17 at 0.0]

Maintenant, exécutez-le à nouveau

2017.04.17 00:31:51.123 Core 1  GOLD-6.17: passed to tester 48984 ticks
2017.04.17 00:31:51.123 Core 1  GOLD-9.17: passed to tester 35192 ticks

et le résultat du test est complètement différent


Dossiers :
 

@Renat Fatkhullin, fournir des preuves solides que le testeur est précis et prêt à être utilisé.

Où sont les critères clairs de validation du testeur ? Où se trouve la reproductibilité à 100 % et la concordance avec le point de référence ?

Où est l'argumentation à toute épreuve de vos paroles ?


Je propose que TOUS vos experts en validation pour le testeur soient publiés dans le domaine public. Je suggère de payer les personnes qui écrivent les EAs qui échouent au testeur. Et les inclure dans la base du vérificateur après avoir modifié le testeur.


Le testeur est brut et tout le monde le prouve. Pourquoi si vous voulez trouver un bug chez le testeur, il est trouvé très rapidement ? Pourquoi 16 ans d'expérience dans l'écriture de plateformes ne nous permettent pas d'écrire un testeur auquel on peut faire confiance ? Chaque construction suscite un seul sentiment chez le testeur : la perplexité.

 
kaus_bonus:

Avec la publication de la version 1583, nous reviendrons sur le problème de la non-concordance des ticks dans l'historique avec les ticks dans le testeur sur les tickers d'actions à faible liquidité.


Le Service Desk vous a-t-il répondu que le problème a été résolu ? La dernière réponse a été "nous y travaillons".

Le problème n'a pas encore été résolu. Malheureusement, tout ne dépend pas des développeurs, une partie du problème dépend de la qualité des ticks sur le serveur de commerce.

Nous sommes en train de faire le tri. Attendez, s'il vous plaît.

 

Voici un script de contrôle, par exemple. Il vérifie la correspondance entre les ticks et les barres minutes. Il n'est pas encore optimisé. Elle peut être accélérée en demandant des ticks dans une gamme plus large. Mais dans cette forme, c'est plus clair, car il demande des ticks pour chaque minute séparément.

//+------------------------------------------------------------------+
//|                                                    TestTicks.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//--- input parameters
input datetime InpBeginDate=D'2017.01.01 0:00:00';
input datetime InpEndDate=D'2017.12.31 0:00:00';
input bool     InpFullLogs=false;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   MqlRates rates[];
   MqlTick  ticks[];
   datetime begin_date,end_date=(datetime)SymbolInfoInteger(_Symbol,SYMBOL_TIME);
   datetime prev_date,cur_date; 
   int      cnt_rates,cnt_ticks;
   int      i,j,book_depth=(int)SymbolInfoInteger(_Symbol,SYMBOL_TICKS_BOOKDEPTH);
   int      bars_absent=0,bars_absent_wrong=0,tickminutes_absent=0;
   int      bars_volume=0,bars_highlow=0;
   string   str_ticks=(book_depth>0)?" bid/ask":" last/volume";
//--- настроим даты
   if(InpEndDate<end_date && InpEndDate>InpBeginDate)
      end_date=InpEndDate;
   end_date/=60;
   end_date*=60;
   end_date--;
   if(InpBeginDate>=end_date)
      begin_date=end_date-24*3600;
   else
     {
      begin_date=InpBeginDate;
      begin_date/=60;
      begin_date*=60;
     }
//---
   cnt_rates=CopyRates(_Symbol,PERIOD_M1,begin_date,end_date,rates);
   Print(cnt_rates," M1 bars from ",begin_date," to ",end_date);
   for(i=0; i<cnt_rates; i++)
     {
      if(IsStopped())
        {
         Print("stopped on ",i," at ",rates[i].time);
         break;
        }
      if(i==0)
         prev_date=begin_date-60;
      else
         prev_date=rates[i-1].time;
      cur_date=rates[i].time;
      Comment(cur_date,"  ",i+1," / ",cnt_rates,"\n",tickminutes_absent,"  ",bars_volume,"  ",bars_highlow,"  ",bars_absent_wrong);
      //--- отсутствуют минутки
      if(cur_date-prev_date>60)
        {
         prev_date+=60;
         cnt_ticks=CopyTicksRange(_Symbol,ticks,COPY_TICKS_ALL,prev_date*1000,cur_date*1000-1);
         if(cnt_ticks>0)
           {
            datetime next_minute=(ticks[0].time/60+1)*60;
            int absent=1;
            int trades=0,infos=0;
            for(j=0; j<cnt_ticks; j++)
              {
               if((ticks[j].flags&(TICK_FLAG_BID|TICK_FLAG_ASK))!=0)
                  infos++;
               if((ticks[j].flags&(TICK_FLAG_LAST|TICK_FLAG_VOLUME))!=0)
                  trades++;
               //--- считаем реально отсутствующие минутки
               if(ticks[j].time>=next_minute)
                 {
                  next_minute=(ticks[j].time/60+1)*60;
                  absent++;
                 }
              }
            //--- тики не соответствуют барам
            if((book_depth<1 && infos>0) ||
               (book_depth>0 && trades>0))
              {
               Print(cnt_ticks," ticks between ",prev_date," and ",cur_date," (",absent," M1 bars absent)");
               if(InpFullLogs)
                  for(j=0; j<cnt_ticks; j++)
                    {
                     Print(ticks[j].time,".",IntegerToString(ticks[j].time_msc%1000,3,'0'),
                           " Bid=",DoubleToString(ticks[j].bid,_Digits),
                           " Ask=",DoubleToString(ticks[j].ask,_Digits),
                           " Last=",DoubleToString(ticks[j].last,_Digits),
                           " Flags=",ticks[j].flags,
                           " Volume=",ticks[j].volume);
                    }
               //--- счётчик отсутствующих баров
               bars_absent_wrong+=absent;
              }
            else
              {
               if(InpFullLogs)
                  Print(cnt_ticks,str_ticks," ticks between ",prev_date," and ",cur_date," (",absent," M1 bars)");
               //--- счётчик отсутствующих баров
               bars_absent+=absent;
              }
           }
        }
      cnt_ticks=CopyTicksRange(_Symbol,ticks,COPY_TICKS_ALL,cur_date*1000,(cur_date+60)*1000-1);
      if(cnt_ticks<=0 && !IsStopped())
        {
         if(InpFullLogs)
            Print("Ticks absent for M1 ",cur_date," last_error=",GetLastError());
         tickminutes_absent++;
        }
      //--- проверим качество тиков
      if(cnt_ticks>0)
        {
         double high_trades=0.0,low_trades=0.0;
         double high_infos=0.0,low_infos=0.0;
         int    trades=0,infos=0;
         //--- сначала соберём статистику
         for(j=0; j<cnt_ticks; j++)
           {
            if((ticks[j].flags&(TICK_FLAG_BID|TICK_FLAG_ASK))!=0)
              {
               if(ticks[j].bid>0.0)
                 {
                  if(high_infos==0.0)
                     high_infos=ticks[j].bid;
                  else
                    {
                     if(high_infos<ticks[j].bid)
                        high_infos=ticks[j].bid;
                    }
                  if(low_infos==0.0)
                     low_infos=ticks[j].bid;
                  else
                    {
                     if(low_infos>ticks[j].bid)
                        low_infos=ticks[j].bid;
                    }
                 }
               infos++;
              }
            if((ticks[j].flags&(TICK_FLAG_LAST|TICK_FLAG_VOLUME))!=0)
              {
               if(ticks[j].last>0.0)
                 {
                  if(high_trades==0.0)
                     high_trades=ticks[j].last;
                  else
                    {
                     if(high_trades<ticks[j].last)
                        high_trades=ticks[j].last;
                    }
                  if(low_trades==0.0)
                     low_trades=ticks[j].last;
                  else
                    {
                     if(low_trades>ticks[j].last)
                        low_trades=ticks[j].last;
                    }
                 }
               trades++;
              }
           }
         //--- потом сверим с минутным баром
         double point=pow(10.0,-_Digits);
         double high,low;
         int    volume;
         bool   error=false;
         //--- это биржевой инструмент?
         if(book_depth>0)
           {
            high=high_trades;
            low=low_trades;
            volume=trades;
           }
          else
           {
            high=high_infos;
            low=low_infos;
            volume=infos;
           }
         if(MathAbs(low-rates[i].low)>=point)
           {
            error=true;
            bars_highlow++;
           }
         else
           {
            if(MathAbs(high-rates[i].high)>=point)
              {
               error=true;
               bars_highlow++;
              }
            else
              {
               if(volume!=rates[i].tick_volume)
                 {
                  error=true;
                  bars_volume++;
                 }
              }
           }
         //--- надо вывести сообщение об ошибке
         if(error && InpFullLogs)
            Print(rates[i].time," ticks (",DoubleToString(high,_Digits)," ",DoubleToString(low,_Digits)," ",volume,
                  ") mismatch with M1 bar (",DoubleToString(rates[i].high,_Digits)," ",DoubleToString(rates[i].low,_Digits)," ",rates[i].tick_volume,")");
        }
     }
//---
   if(tickminutes_absent>0)
      Print("real ticks absent for ",tickminutes_absent," M1 bars");
   if(bars_volume>0)
      Print("tick volumes not matched for ",bars_volume," M1 bars");
   else
      Print("all the tick volumes matched for all M1 bars");
   if(bars_highlow>0)
      Print("tick prices not matched for ",bars_volume," M1 bars");
   else
      Print("all the tick prices matched for all M1 bars");
   if(bars_absent_wrong>0)
      Print(bars_absent_wrong," M1 bars absent in total while real ticks present");
//--- тут всё нормально, есть тики, которые не формируют бары, поэтому баров и не должно быть
   if(bars_absent>0 && InpFullLogs)
      Print(bars_absent," M1 bars absent while",str_ticks," ticks present");
//--- очистим коммент
   Comment("");
  }
//+------------------------------------------------------------------+
Dossiers :
TestTicks.mq5  17 kb
 
Slawa:

Voici un script de contrôle, par exemple. Il vérifie la correspondance entre les ticks et les barres minutes. Il n'est pas encore optimisé. Elle peut être accélérée en demandant des ticks dans une gamme plus large. Mais il est plus clair dans cette forme, car il demande des ticks pour chaque minute séparément.

Merci. Une petite remarque.
book_depth=(int)SymbolInfoInteger(_Symbol,SYMBOL_TICKS_BOOKDEPTH);
Ce n'est pas ainsi que l'on définit l'appartenance à une bourse de valeurs mobilières - de nombreuses chaînes de diffusion de devises.


J'ai obtenu le résultat suivant sur Metaquotes-Demo

Test2 (Si-6.17,M1)      6 M1 bars from 2017.04.17 00:00:00 to 2017.04.17 10:05:59
Test2 (Si-6.17,M1)      9 bid/ask ticks between 2017.04.17 00:00:00 and 2017.04.17 10:00:00 (9 M1 bars)
Test2 (Si-6.17,M1)      all the tick volumes matched for all M1 bars
Test2 (Si-6.17,M1)      all the tick prices matched for all M1 bars
Test2 (Si-6.17,M1)      9 M1 bars absent while bid/ask ticks present

C'est bon ?

 
Slawa:

Le service après-vente vous a-t-il dit que le problème avait été résolu ? La dernière réponse a été "c'est en cours d'investigation".

Le problème n'a pas encore été résolu. Malheureusement, tout ne dépend pas des développeurs, une partie du problème dépend de la qualité des ticks téléchargés sur le serveur de commerce.

J'ai compris. Attendez, s'il vous plaît.


Je ne me plains pas.

Dans le SD, la plainte portait sur autre chose - des tics incohérents.

et ici a montré un nouveau bug - exécution dans le testeur à 0 sur la première course à froid, qui est apparu après avoir utilisé tous les ticks dans le testeur.

 
kaus_bonus:


Je ne me plains pas.

l'application en SD est pour une autre raison - des tics incohérents.

et a montré ici un nouveau bug - exécution dans le testeur au prix 0 lors de la première exécution à froid, qui est apparu après avoir utilisé tous les ticks dans le testeur.

Ça vient du même endroit. Le problème avec les tiques est le même.

Le cas que vous décrivez ne s'est jamais produit auparavant ? Non.

D'où vient-il ? Dans le processus de résolution du problème de la correspondance des tiques

 
fxsaber:
Merci. Une petite noteCe n'est pas une façon de définir l'affiliation au forex/à la bourse - nombreux sont ceux qui diffusent la pile forex.



Qu'est-ce que cela a à voir avec le fait que l'échange ne soit pas un échange ?

si une pile forex est diffusée, cela signifie que les barres sont construites par des ailettes.

 
Slawa:

Qu'est-ce que la bourse a à voir là-dedans ?

si un tumblr est diffusé, cela signifie que les barres sont construites sur des palmes.

Quels flippers sur le forex ? Ouvrez la démo ici FIBOGroup-MT5 Server.
 
fxsaber:
Que sont les flippers dans le forex ? Ouvrez la démo ici FIBOGroup-MT5 Server.

Si la profondeur du marché est transmise, les barres sont construites sur la base des flippers, sinon elles sont construites sur la base des offres.

Je comprends votre question. Dernièrement, en raison de l'expansion de la fonctionnalité des tics, il existe des paramètres - "toujours construire par les ailerons", "toujours construire par les offres", "construire en fonction de la traduction de la pile".

Les deux premiers paramètres ne sont pas pris en compte dans ce script. Il est calculé à l'"ancienne".