mql5语言的特点、微妙之处以及技巧 - 页 84

 
Alain Verleyen:

你能提供基准代码来证明这一点吗?

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double Bench1( const int Size, const string Str )
{
  double Tmp = 0;
  
  for (int i = 0; i < Size; i++)
    Tmp += (double)Str;

  return(Tmp);
}

double Bench2( const int Size, const string Str )
{
  double Tmp = 0;;
  
  for (int i = 0; i < Size; i++)
    Tmp += StringToDouble(Str);

  return(Tmp);
}

double Bench3( const int Size, const string Str )
{
  double Tmp = 0;
  
  for (int i = 0; i < Size; i++)
    Tmp += StringToDouble2(Str); // https://www.mql5.com/ru/forum/170952/page83#comment_7121066

  return(Tmp);
}

void OnStart()
{  
  const string Str = "123.456";
  
  BENCH(Print(Bench1(1 e7, Str)));
  BENCH(Print(Bench2(1 e7, Str)));
  BENCH(Print(Bench3(1 e7, Str)));
}


结果(释放)

1234559999.924436
Time[Print(Bench1(1 e7,Str))] = 1656182
1234559999.924436
Time[Print(Bench2(1 e7,Str))] = 1639179
1234559999.924436
Time[Print(Bench3(1 e7,Str))] = 147382


当你在剖析模式下运行时,你会得到这样的结果

1234559999.924436
Time[Print(Bench1(1 e7,Str))] = 1757705
1234559999.924436
Time[Print(Bench2(1 e7,Str))] = 1877177
1234559999.924436
Time[Print(Bench3(1 e7,Str))] = 4578266

不幸的是,在这种情况下,分析器不能被信任。

 
fxsaber:


结果 (释放)


如果我在剖析模式下运行,我得到的结果是这样的

在这种情况下,不仅不可能相信剖析器,而且Bench1的运行速度比Release-version快10倍!

谢谢你的提醒。

结果 (释放)

Time [Bench1( 1 e7,Str)] = 1680754
Time [Bench2( 1 e7,Str)] = 1646789
Time [Bench3( 1 e7,Str)] = 143408     more then 10 times faster !!! 

通过策略用专家顾问测试。

2018.04.16 14:24:28.049    Core 1    OnTester result 39725470 (µs bench1)
2018.04.16 14:26:14.629    Core 1    OnTester result 39270950 (µs bench2)
2018.04.16 14:27:13.566    Core 1    OnTester result 20467067 (µs bench3)

又快了2倍(但不超过10倍,这当然是由于编译器的优化)。

附加的文件:
170952.mq5  6 kb
 
Alain Verleyen:

与战略顾问一起测试。

2018.04.16 14:24:28.049    Core 1    OnTester result 39725470 (µs bench1)
2018.04.16 14:26:14.629    Core 1    OnTester result 39270950 (µs bench2)
2018.04.16 14:27:13.566    Core 1    OnTester result 20467067 (µs bench3)

它仍然快2倍(但不超过10倍,这显然是由于编译器的优化)。

你测量的仍然是生成tick的时间,而不仅仅是OnTick的计算。

这里只有OnTick的测量

#define  PROFILER_OnTick // Замеряет чистое время выполнения всех OnTick - немного замедляет общую работу
#include <TesterBenchmark.mqh> // https://www.mql5.com/ru/code/18804

input int bench=1;// between 1 and 3

void OnTick()
{
  static const string Str = "123.456";

  switch(bench)
  {
    // https://www.mql5.com/ru/forum/170952/page84#comment_7121207
    case 1 : Bench1(1, Str); break;
    case 2 : Bench2(1, Str); break;
    case 3 : Bench3(1, Str); break;
  }  
}


长椅1

i = 0 Pass = 0 OnTester = 3.729 s.: OnTick Profiler: Count = 7197033, Interval = 1.895 s., 3796990.9 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 3.843 s.: OnTick Profiler: Count = 7197033, Interval = 1.950 s., 3690523.1 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795


长椅3

i = 0 Pass = 0 OnTester = 2.280 s.: OnTick Profiler: Count = 7197033, Interval = 0.631 s., 11404799.6 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 2.340 s.: OnTick Profiler: Count = 7197033, Interval = 0.640 s., 11242184.6 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795


以三倍的系数。你不可能因为多次调用BenchX函数而获得10倍的速度。StringToDouble2本身确实快10倍。

 
fxsaber:

你测量的仍然是生成ticks的时间,而不仅仅是计算OnTick。

...

你是对的。

我真的很惊讶,它的速度是10倍,然而你的函数 只能在你知道字符串包含一个有效的双倍值时使用。

2018.04.16 17: 14: 16.183 170952_180416 (EURUSD, H1) StringToDouble2 (abcdef) = 5456784.0

 
阿列克谢-维亚兹米 金。

谢谢你,但这个脚本的保存方式也不正确。

在我的显示器上,右侧的限制用一条垂直线标记,而截图远远超出了这条线。

我将引用服务台的答案。

在这种情况下,应该从字面上理解ChartScreenShot 的帮助。

align_mode=ALIGN_RIGHT

[in] 狭义截图输出的模式。枚举ENUM_ALIGN_MODE 的值。ALIGN_RIGHT表示对准右边界(从末端输出)。ALIGN_LEFT指定左对齐。

这意味着,当你指定ALIGN_RIGHT对齐方式时,图表将被强行滚动到右边界,这相当于执行命令

ChartNavigate(0,CHART_END,0);

这种行为是多年前建立的(所以在历史上),当时还没有ChartNavigate()函数。设置align_mode=ALIGN_RIGHT可以保证图表的右边界正好被移除。

当ChartNavigate()函数被添加时,ChartScreenShot 函数的行为没有被改变。

因此,如果你想获得理想的效果(图表不会被滚动到右边缘),请为align_mode参数使用ALIGN_LEFT值。

 
Alain Verleyen:

你的函数 只有在你知道字符串包含一个有效的双倍值时才能使用。

2018.04.16 17: 14: 16.183 170952_180416 (EURUSD, H1) StringToDouble2 (abcdef) = 5456784.0

修正了它,现在它像原来一样工作了

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{    
  const string Str[] = {"123.456", "-asdf1234", "12as", ".34 a", "..23", "1.."};

  for (int i = 0; i < ArraySize(Str); i++)
  {
    PRINT(Str[i]);
    
    PRINT((double)Str[i]);
    PRINT(StringToDouble2(Str[i])); // https://www.mql5.com/ru/forum/170952/page83#comment_7121066
    
    Print("");
  }
}
 

关于交易、自动交易系统和交易策略测试的论坛

mql5语言的特点、微妙之处以及技巧

fxsaber, 2018.04.16 13:23

double StringToDouble2( const string Str, const uint StartPos = 0 )

如果你删除了高亮的常数,函数的执行时间将增加一倍。这表明,编译器并不总是创建最佳代码,需要这种提示。

 
fxsaber:

如果我们去掉标记的const,该函数的运行时间将增加一倍。这表明编译器并不总是创建一个最佳的代码,需要这种提示。

有意思,谢谢你。

请不要在已经收到答案后再编辑你的代码,我没有收到你的更新通知。

 
fxsaber:

如果我们去掉标记的const,该函数的运行时间将增加一倍。这表明编译器并不总是创建一个最佳的代码,需要这种提示。

非常有趣...
对为什么会发生这种情况有什么想法吗?

机制是什么?

 

为了确定用MQL5拍摄的屏幕截图的宽度,其中包括某个时期的所有条形图,下面提供了解决方案。

一个奇特的现象是,在不同的图表近似度下,屏幕截图的宽度必须得到纠正。

实际的 "系数 "在有刻度和无刻度的变体中是不同的(具体对我来说)。

 if (Use_Shakala==false)
 
 {
   ChartSetInteger(0,CHART_SHOW_PRICE_SCALE ,0);//Показывать или нет ценовую шкалу
   int TotalPixel=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);   // Ширина графика в пикселях
   int WidthBar=int(1<<ChartGetInteger(0,CHART_SCALE));            // сколько пикселей между барами
   int FirstBar=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);   // номер первого (левого) бара на экране
   int VisibleBars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);     // количество видимых баров на экране
   int BarNr= FirstBar-(Shift_Start-Shift_Stop)*(-1);              // номер искомого бара, допустим на 12 баров правее самого левого бара 
   int LeftPixelOfBar=((FirstBar-BarNr)>=VisibleBars || FirstBar<BarNr)?(-1):((FirstBar-BarNr)*WidthBar);  // левый пиксель искомого бара, если бара нет на экране тогда -1
   int RightPixelOfBar =(LeftPixelOfBar<0)?(-1):LeftPixelOfBar+WidthBar-1;                                 //правый пиксель искомого бара, если бара нет на экране тогда -1
   if (RightPixelOfBar>=TotalPixel) RightPixelOfBar=TotalPixel-1;  // проверяем не за пределами ли экрана 

      if (Zoom==0)ZoomX=6;
      if (Zoom==1)ZoomX=5;
      if (Zoom==2)ZoomX=5;
      if (Zoom==3)ZoomX=4;
      if (Zoom==4)ZoomX=2;
      if (Zoom==5)ZoomX=0;

  pp=WidthBar*((Shift_Start-Shift_Stop)*(-1)+2)+ZoomX;
}

  if (Use_Shakala==true)
  {
   ChartSetInteger(0,CHART_SHOW_PRICE_SCALE ,1);//Показывать или нет ценовую шкалу
   int TotalPixel=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);   // Ширина графика в пикселях
   int WidthBar=int(1<<ChartGetInteger(0,CHART_SCALE));            // сколько пикселей между барами
   int FirstBar=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);   // номер первого (левого) бара на экране
   int VisibleBars=(int)ChartGetInteger(0,CHART_WIDTH_IN_BARS);     // количество видимых баров на экране
   int BarNr= FirstBar-(Shift_Start-Shift_Stop)*(-1);              // номер искомого бара, допустим на 12 баров правее самого левого бара 
   int LeftPixelOfBar=((FirstBar-BarNr)>=VisibleBars || FirstBar<BarNr)?(-1):((FirstBar-BarNr)*WidthBar);  // левый пиксель искомого бара, если бара нет на экране тогда -1
   int RightPixelOfBar =(LeftPixelOfBar<0)?(-1):LeftPixelOfBar+WidthBar-1;                                 //правый пиксель искомого бара, если бара нет на экране тогда -1
   if (RightPixelOfBar>=TotalPixel) RightPixelOfBar=TotalPixel-1;  // проверяем не за пределами ли экрана 

      if (Zoom==0)ZoomX=1;
      if (Zoom==1)ZoomX=1;
      if (Zoom==2)ZoomX=1;
      if (Zoom==3)ZoomX=3;
      if (Zoom==4)ZoomX=2;
      if (Zoom==5)ZoomX=0;    
  pp=WidthBar*((Shift_Start-Shift_Stop)*(-1)+2-0.5)+ZoomX+Schkala;
  
  }
//pp 		 - ширина скриншота
//Shift_Start    - номер левого бара, который целиком должен попасть на скрин
//Shift_Stop     - номер правого бара, который целиком должен попасть на скрин
//Schkala        - ширина цифровой шкалы по методу fxsaber
//Zoom           - степень приближение экрана