程序库: 用于 MT5 的快速 iBarShift 和 Bars

 

用于 MT5 的快速 iBarShift 和 Bars:

完整且快速的函数,似于 MQL4 中的 Bars 和 iBarShift。


作者: Nikolai Semko

 

MT5 1847 版本修复了Bars 函数 挂起的错误。此外,还添加了标准 iBarShift 函数。
因此,为了提高这些函数的性能(10 倍左右),现在最好使用此代码变体:

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; // 1970年1月1日--星期四。减去4天
   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);
  }
附加的文件:
iBars.mqh  14 kb
 
Nikolai Semko:

从 1847 版 MT5 开始,Bars 函数 挂起的错误已得到修复。此外,还添加了标准 iBarShift 函数。
因此,为了提高这些函数的性能(10 倍左右) ,现在最好使用此代码变体:

将代码发送给 servicedesk,让他们在平台中将其作为标准实现

 
Vitaly Muzichenko:

将代码发送给 servicedesk,让他们将其作为标准实施到平台中。


这段代码是跨平台的。最有趣的是,在 MT4 上没有增益,因此Bars 功能 在 MT4 中得到了优化。

 
Nikolai Semko:


这段代码是跨平台的。有趣的是,在 MT4 上没有增益,因此Bars 函数 是在 MT4 上优化编写的。

我们正在跟踪此主题。通过口袋插入您的帖子。

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

本主题 受到监控。把你的帖子从口袋里放进去

好的但由于某些原因,通过口袋发帖不起作用。没用是通过链接

 
Nikolai Semko:

因此,为了提高这些函数的运行速度(大约 10 倍),现在最好使用这种代码变体:

你对速度的要求是不是有点太草率了? 特别是考虑到你的代码中存在大量的各种检查。 我懒得去研究它的本质,但我很难相信这样一团糟的代码能快速运行。

 
Alexey Navoykov:

你是不是对速度反应过激了? 尤其是考虑到你的代码中存在大量的各种检查。 我懒得深入探讨其本质,但我很难相信这样一团糟的代码能快速运行。

你最好懒得写这条信息。))

为了测试速度,我特意在这些函数中附加了一个指标。

Bars 函数以微秒为单位执行,而检查、算术运算(甚至计算二进制数的平方根)则小于纳秒:

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("1,000,000根的总和 = " + DoubleToString(sum,18)+ "为" + IntegerToString((int)t) + "微秒"。); 
  }


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 микросекунд

从这个速度测试中我们可以看到,计算二进制数根的和的 100 万次循环是在 2000 微秒内完成的。
因此,一个循环是在 2 纳秒内完成的。一个周期是 1 次检查、2 次二进制数求和、1 次二进制数平方根计算。

附加的文件:
 
Nikolai Semko:

你最好懒得写这篇文章。))

我特别为这些功能附加了一个速度测试指标。

Bars 函数的执行速度为微秒级,而检查、算术运算(甚至计算二进制数的平方根)的速度都小于纳秒级:

从这个速度测试中我们可以看到,计算二进制数根的和的 100 万个周期的执行时间为 2000 微秒。
因此,一个周期的执行时间为 2 纳秒。一个周期是 1 次检查、2 次二进制数求和、1 次二进制数平方根计算。

我还没有安装新版本,所以无法重现。据我所知,您的函数是针对一种特殊情况进行优化的,这在您的指标中有所体现。 符号不会改变,时间框架也不会改变,等等。 我想这就是为什么 Bars 函数在这里被调用一次的原因。 符号和时间框架都被愚蠢地设置为常量。 这就是为什么很有可能编译器优化了您的整个函数,扔掉了所有不必要的东西。

简而言之,测试是不正确的。 应该有一个符号数组和一个时段数组,你应该在所有这些数组上运行你的函数。 然后我们才能讨论一些问题。

 
Alexey Navoykov:

我还没有安装新版本,所以无法重现。我知道你的函数是针对一种特殊情况进行优化的,这在你的指标中有所体现。 符号不会改变,时间框架也不会改变,等等。 因此,我认为 Bars 函数只被调用一次,而符号和时间框架都被愚蠢地设置为常量。 因此,很有可能编译器优化了你的整个函数,扔掉了所有不必要的东西。

简而言之,测试的执行方式是错误的。 应该有一个字符数组和一个句点数组。 你应该把你的函数全部运行一遍。 然后我们就可以讨论一些问题了。

这些都不是特例:"符号不变,时间范围也不变"!


当然,您是对的。如果每次调用 Bars 时都伴随着 TF 或符号的变化,那么标准指标的运行速度会更快。虽然在这种情况下,你只需要用一个大小与 TF 数量相同的静态变量 数组来代替静态变量。但我认为这是一种特殊情况。但如果有必要的话,这种特殊情况下的解决方案也有其存在的价值。也许应该针对这种情况修改代码。А ...这可能就是你要说的。

关于常量--谢谢你的注意。我更正是因为原始函数中的参数不是常量。在速度方面没有任何变化。

 
Nikolai Semko:

您是否有很多这样的指标或 Expert Advisors,它们会不断改变 TF 和符号?

是的,非常多。 我专注于投资组合分析和投资组合交易。 不过,当涉及到大型计算时,iBarShift 就不合适了,因为我们使用的是数组。 事实上,iBarShift 和其他类似函数都是为罕见调用而设计的。我们只需在 CopyTime 中获取数组,然后快速找到所有内容。 这就是为什么测试示例在实际应用中用处不大的原因。 当然,除非编码者是个傻瓜)而且我认为不值得为了傻瓜而费心)。

我认为将函数封装到一个类中更合乎逻辑。 这样您就不必在每次调用时都检查符号/周期。 您将为每个时间序列拥有一个单独的对象。