Librerías: Fast iBarShift and Bars for MQL5

 

Fast iBarShift and Bars for MQL5:

Los análogos más rápidos de las funciones Bars y iBarShift.

 

Autor: Nikolai Semko

 

Desde la build 1847 de MT5 el bug de cuelgue en la función Bars ha sido corregido. También se añadió la función estándar iBarShift.
Por lo tanto, para aumentar el rendimiento de estas funciones (en algún lugar en veces 10) es mejor ahora utilizar esta variante de código :

int fBars(string symbol_name,ENUM_TIMEFRAMES  timeframe,datetime start_time,datetime stop_time)
  {
   static string LastSymb=NULL;
   static ENUM_TIMEFRAMES LastTimeFrame=0;
   static datetime LastTime=0;
   static datetime LastTime0=0;
   static int PerSec=0;
   static int PreBars=0;
   static datetime LastBAR=0;
   static datetime LastTimeCur=0;
   static bool flag=true;
   static int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS);
   datetime TimeCur;
   if(timeframe==0) timeframe=_Period;
   const bool changeTF=LastTimeFrame!=timeframe;
   const bool changeSymb=LastSymb!=symbol_name;
   const bool change=changeTF || changeSymb || flag;

   LastTimeFrame=timeframe; LastSymb=symbol_name;
   if(changeTF) PerSec=::PeriodSeconds(timeframe); if(PerSec==0) { flag=true; return(0);}

   if(stop_time<start_time)
     {
      TimeCur=stop_time;
      stop_time=start_time;
      start_time=TimeCur;
     }
   if(changeSymb)
     {
      if(!SymbolInfoInteger(symbol_name,SYMBOL_SELECT))
        {
         SymbolSelect(symbol_name,true);
         ChartRedraw();
        }
     }
   TimeCur=TimeCurrent();
   if(timeframe==PERIOD_W1) TimeCur-=(TimeCur+345600)%PerSec; // 01.01.1970 - Jueves. Menos 4 días.
   if(timeframe<PERIOD_W1) TimeCur-=TimeCur%PerSec;
   if(start_time>TimeCur) { flag=true; return(0);}
   if(timeframe==PERIOD_MN1)
     {
      MqlDateTime dt;
      TimeToStruct(TimeCur,dt);
      TimeCur=dt.year*12+dt.mon;
     }

   if(changeTF || changeSymb || TimeCur!=LastTimeCur)
      LastBAR=(datetime)SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE);

   LastTimeCur=TimeCur;
   if(start_time>LastBAR) { flag=true; return(0);}

   datetime tS,tF=0;
   if(timeframe==PERIOD_W1) tS=start_time-(start_time+345599)%PerSec-1;
   else if(timeframe<PERIOD_MN1) tS=start_time-(start_time-1)%PerSec-1;
   else  // PERIOD_MN1
     {
      MqlDateTime dt;
      TimeToStruct(start_time-1,dt);
      tS=dt.year*12+dt.mon;
     }
   if(stop_time<=LastBAR)
     {
      if(timeframe<PERIOD_W1) tF=stop_time-(stop_time)%PerSec;
      else if(timeframe==PERIOD_W1) tF=stop_time-(stop_time+345600)%PerSec;
      else // PERIOD_MN1
        {
         MqlDateTime dt0;
         TimeToStruct(stop_time-1,dt0);
         tF=dt0.year*12+dt0.mon;
        }
     }
   if(change || tS!=LastTime || tF!=LastTime0)
     { PreBars=Bars(symbol_name,timeframe,start_time,stop_time); LastTime=tS; LastTime0=tF; }
   flag=false;
   return(PreBars);
  }


int fBarShift(string symb,ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   int Res=fBars(symb,TimeFrame,time+1,UINT_MAX);
   if(exact) if((TimeFrame!=PERIOD_MN1 || time>TimeCurrent()) && Res==fBars(symb,TimeFrame,time-PeriodSeconds(TimeFrame)+1,UINT_MAX)) return(-1);
   return(Res);
  }
Archivos adjuntos:
iBars.mqh  14 kb
 
Nikolai Semko:

Desde la build 1847 MT5 el bug de cuelgue en la función Bars ha sido corregido. También se añadió la función estándar iBarShift.
Por lo tanto, para aumentar el rendimiento de estas funciones (en algún lugar en veces 10) es mejor ahora utilizar esta variante de código :

Envíe el código a servicedesk, deje que lo implementen como estándar en la plataforma

 
Vitaly Muzichenko:

Enviar el código a servicedesk y que lo implementen en la plataforma como estándar.

Quién soy yo para decirles.
Este código es multiplataforma. Y lo más interesante es que no hay ganancia en MT4, por lo que la función Bars está óptimamente escrita en MT4.

 
Nikolai Semko:

Quién soy yo para decirles.
Este código es multiplataforma. Y lo interesante es que no hay ganancia en MT4, por lo que la función Bars está escrita de forma óptima en MT4.

Se sigueeste hilo. Inserte a través de bolsillo de su puesto.

Альтернативные реализации стандартных функций/подходов
Альтернативные реализации стандартных функций/подходов
  • 2016.09.01
  • www.mql5.com
NormalizeDouble Результат 1123275 и 1666643 в пользу MyNormalizeDouble (Optimize=1). Без оптимизации - быстрее раза в четыре (на память...
 
fxsaber:

Este hilo está siendo monitorizado. Introduce tu mensaje por el bolsillo.

De acuerdo. Pero por alguna razón no está funcionando a través del bolsillo. No funciona. Es a través del enlace.

 
Nikolai Semko:

Por lo tanto, para aumentar la velocidad de estas funciones (unas 10 veces) es mejor utilizar ahora esta variante de código :

¿No te estás precipitando con la velocidad? Sobre todo teniendo en cuenta la enorme cantidad de comprobaciones de todo tipo que hay en tu código. Me da pereza entrar en la esencia del asunto, pero me cuesta creer que semejante desbarajuste funcione rápido.

 
Alexey Navoykov:

¿No estás exagerando con lo de la velocidad? Sobre todo teniendo en cuenta la enorme cantidad de comprobaciones de todo tipo que hay en tu código. Me da pereza entrar en su esencia, pero me cuesta creer que semejante desastre funcione rápido.

Más te vale ser demasiado vago para escribir este mensaje. ))

Específicamente adjunté un indicador a estas funciones para la prueba de velocidad.

La función Bars se ejecuta en microsegundos, y las comprobaciones, operaciones aritméticas(incluso calcular la raíz cuadrada de un número binario) en menos de un nanosegundo:

void OnStart()
  {
   ulong t;
   double sum=0;
   t=GetMicrosecondCount();
   for (double i=1; i<2;i+=0.000001 ) sum+=sqrt(i);
   t=GetMicrosecondCount()-t;
   Print("Suma de 1.000.000 raíces = " + DoubleToString(sum,18)+ " por " + IntegerToString((int)t) + "microsegundos".); 
  }


2018.06.14 19:23:31.188 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1990 микросекунд
2018.06.14 19:26:30.814 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1946 микросекунд
2018.06.14 19:26:34.188 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1946 микросекунд
2018.06.14 19:26:36.344 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1973 микросекунд

De esta prueba de velocidad podemos ver que 1 millón de ciclos para calcular sumas de raíces de números binarios se ejecuta en 2000 microsegundos.
Así que un ciclo se ejecuta en 2 nanosegundos. Un ciclo es 1 comprobación, dos sumas de números binarios, un cálculo de la raíz cuadrada de un número binario.

Archivos adjuntos:
 
Nikolai Semko:

Más vale que te dé pereza escribir este post. ))

Específicamente adjunté un indicador de prueba de velocidad a estas funciones.

La función Barras se ejecuta en microsegundos, mientras que las comprobaciones, las operaciones aritméticas(incluso el cálculo de la raíz cuadrada de un número binario) son inferiores a un nanosegundo:

De esta prueba de velocidad se desprende que 1 millón de ciclos para calcular sumas de raíces de números binarios se ejecuta en 2000 microsegundos.
Por tanto, un ciclo se ejecuta en 2 nanosegundos. Un ciclo es 1 comprobación, dos sumas de números binarios, un cálculo de la raíz cuadrada de un número binario.

Todavía no he puesto builds nuevos, así que no puedo reproducirlo. Entiendo que tu función está optimizada para un caso especial, que es el representado en tu indicador. El símbolo no cambia, el timeframe tampoco, etc. Por eso, supongo, la función Bars se llama una vez allí. Y tanto el símbolo como el timeframe están estúpidamente puestos como constantes. Por eso es muy posible que el compilador haya optimizado toda tu función, desechando todo lo innecesario.

En resumen, las pruebas son incorrectas. Debería haber un array de símbolos y un array de periodos, y deberías ejecutar tu función sobre todos ellos. Entonces podremos hablar de algo.

 
Alexey Navoykov:

Todavía no he instalado nuevas builds, así que no puedo reproducirlo. Entiendo que tu función está optimizada para un caso especial, que es el representado en tu indicador. El símbolo no cambia, el timeframe tampoco, etc. Por lo tanto, supongo, la función Bars se llama una vez. Y tanto el símbolo como el timeframe están estúpidamente configurados como constantes. Por lo tanto, es muy posible que el compilador haya optimizado toda tu función, desechando todo lo innecesario.

En resumen, las pruebas se realizan de forma incorrecta. Debería haber un array de caracteres y un array de periodos. Deberías ejecutar tu función a través de todos ellos. Entonces podremos hablar de algo.

Nada de esto es un caso especial: ¡"El símbolo no cambia, el plazo tampoco"!

¿Por qué - usted tiene un montón de tales indicadores o Asesores Expertos, que cambian constantemente TF y símbolos?
Por supuesto, usted tiene razón. Si cada llamada de Barras será acompañada por un cambio de TF o símbolo, entonces el estándar trabajará más rápido. Aunque en este caso sólo tiene que sustituir las variables estáticas con una matriz de variables estáticas del mismo tamaño que el número de TFs. Pero considero esto como un caso especial. Pero esta solución de este caso especial tiene derecho a vivir si es necesario. Tal vez tenga sentido modificar el código para estos casos. А ... Eso es probablemente lo que usted estaba hablando.

Y sobre las constantes - gracias por notarlo. Lo corregí porque los parámetros en la función original no son constantes. Nada ha cambiado en términos de velocidad.

 
Nikolai Semko:

¿Tienes muchos indicadores de este tipo o Expert Advisors que cambian constantemente TFs y símbolos?

Bueno, sí, bastantes. Estoy centrado en el análisis de carteras y el trading de carteras. Sin embargo, cuando se trata de cálculos grandes, iBarShift es inapropiado ahí, porque trabajamos con arrays. De hecho, iBarShift y otras funciones similares están pensadas para llamadas raras.Es irracional ponerlas en bucle. Simplemente cogemos el array en CopyTime y rápidamente encontramos todo. Por eso el ejemplo de prueba es de poca utilidad en la práctica real. A no ser que el codificador sea un dummy por supuesto ) Y no creo que merezca la pena molestarse por el bien de los dummies ).

Creo que sería más lógico envolver tu función en una clase. Así no tendrás que comprobar el símbolo/periodo en cada llamada. Tendrás un objeto distinto para cada serie temporal.