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

 
Marat Sultanov #:
以前(甚至在较早的编译器版本中)可以在类声明之前使用它:
但现在编译时会出错:
无法使用未定义的类 'A'

如果它停止工作,最好能知道它是否正确。

如果用指针代替对象,旧版本也能正常工作。

 
fxsaber #:

如果它停止工作了,很高兴知道这样做是否正确。

如果用指针代替对象,旧版本也能正常工作。

说得好,谢谢你的提示!

是的,的确,使用指针可以完美地解决这种情况:

class A;

class B
{
   public: A * a;
   public: int Val;
};

class A
{
   public: B * b;
   public: int Test() {return b.Val + 1;}
};

//+------------------------------------------------------------------+
//|                                                                                |
//+------------------------------------------------------------------+
void OnStart()
{
   B b;
   A a;
   
   b.a = GetPointer(a);
   b.a.b = GetPointer(b);
   b.Val = 1;
   
   Print(b.a.Test());
}
 

快速算法爱好者。为纳秒而战的人:)


任务: 根据给定的时间和 TF(已知此时存在条形图),找出条形图的开仓时间。例如,通过开仓和平仓时间。

大多数程序员会使用 iTime 和 iBarShift 的组合。这将是最慢的实现方式,尤其是这种实现方式需要最新的历史上传数据或组合数组。此外,如果缺少所需的历史数据,这种方法可能会产生错误。

更高级的程序员会通过 MqlDateTime 结构和 TimeToStruct() 函数来解决这个问题。这不是一个坏的解决方案,而且足够快。

但还有第三种解决方案,其效率比前一种解决方案高出数倍:

//+------------------------------------------------------------------+
// получает время открытия виртуального бара по входному времени и Таймфрейму, вне зависимости от того, существует реальный бар или нет.
// корректно считает только до 28.02.2100 !!!!
// не является заменой iBarShift!!! Не зависит от истории баров.  
datetime getStartTimeOfBarFast(ENUM_TIMEFRAMES tf, datetime t) {
   if (tf==0) tf=_Period;

   int ts=0;
   if (tf<PERIOD_MN1) {
      ushort i_tf= ushort(tf);
      uchar _i =uchar(i_tf>>14);
      int n = i_tf & 0x0FFF;
      ts = (_i==0)?n*60:(_i==1)?n*60*60:60*60*24*7;
   }
   if (tf<PERIOD_W1) return t-t%ts;
   if (tf==PERIOD_W1) return t-(t+4*24*60*60)%ts;
   else { // Period MN1
      static int dm[12] = {0,31,61,92,122,153,184, 214, 245, 275, 306, 337};
      static int last_days = 0;
      static datetime last_result = 0;
      int days = int(t/(24*60*60));
      if (last_days!=days) {
         last_days = days;
         int d1 = (days+306+365)%1461;
         int y = d1/365;
         datetime t1 = t - t%(24*60*60) - d1*24*60*60;
         int m = 0;
         if (d1==1460) {
            m=11;
            y--;
         };
         int d = d1-y*365+1;
         if (d!=31) if (d==276) m = 9;
            else m = int (d/30.68);
         if (m<0 || m>11) return -1;
         last_result = t1+y*365*24*60*60+dm[m]*24*60*60;
      }
      return last_result;
   }
}
//+------------------------------------------------------------------+

这种算法的主要难点在于计算月初的时间(绿色高亮部分)。这里面有魔法,是从简单到复杂的结果。从复杂到简单的反向路径会更难走。

从 TF 而不是标准的 PeriodSeconds() 函数中获取条形图中的秒数的算法也带来了性能上的提升--用黄色标出。


我附上了一个测试脚本,用于计算和比较所有三种方法的性能:

2023.11.14 12:15:29.145 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_MN1========
2023.11.14 12:15:29.146 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 21.20 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:29.146 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 6.10 наносекунд - Быстрый расчет
2023.11.14 12:15:29.147 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 142.00 наносекунд - Расчет через iBarShift
2023.11.14 12:15:29.147 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:34.226 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_MN1========
2023.11.14 12:15:34.227 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 19.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:34.227 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 6.70 наносекунд - Быстрый расчет
2023.11.14 12:15:34.228 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 127.50 наносекунд - Расчет через iBarShift
2023.11.14 12:15:34.228 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_W1========
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 2.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:39.857 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 98.30 наносекунд - Расчет через iBarShift
2023.11.14 12:15:39.857 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:52.770 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H2========
2023.11.14 12:15:52.771 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000355999200, время выполнения 1 иттерации = 4.10 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:52.771 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000355999200, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:54.255 timeToStartMonth (EURUSD,M1)    контрольная сумма - 0, время выполнения 1 иттерации = 148466.50 наносекунд - Расчет через iBarShift
2023.11.14 12:15:54.255 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_M4========
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000391999920, время выполнения 1 иттерации = 3.60 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000391999920, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:59.864 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000017286960, время выполнения 1 иттерации = 110555.70 наносекунд - Расчет через iBarShift
2023.11.14 12:15:59.864 timeToStartMonth (EURUSD,M1)    ========================================================================

与 iBarShift 的校验和不 一致 ,因为iBarShift 使用的是真实条形图。只有在 MN1 和 W1 时间框架 上,校验和才 会一致,因为这些条形图的历史记录中没有漏洞
如果在循环中使用较小的时间步长(少于一天),当算法开始工作时保存之前的计算,性能会更高:

2023.11.14 12:14:10.714 timeToStartMonth (EURUSD,M1)    =====LOOP=1000000========STEPS=1000 seconds======PERIOD_MN1========
2023.11.14 12:14:10.722 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 8.03 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:14:10.723 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 1.18 наносекунд - Быстрый расчет
2023.11.14 12:14:10.860 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 136.80 наносекунд - Расчет через iBarShift
2023.11.14 12:14:10.860 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:14:17.502 timeToStartMonth (EURUSD,M1)    =====LOOP=1000000========STEPS=1000 seconds======PERIOD_MN1========
2023.11.14 12:14:17.510 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 7.70 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:14:17.511 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 1.18 наносекунд - Быстрый расчет
2023.11.14 12:14:17.648 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 137.54 наносекунд - Расчет через iBarShift
2023.11.14 12:14:17.648 timeToStartMonth (EURUSD,M1)    ========================================================================


通过 iBarShift 算法的过高值(蓝色高亮显示)是由于当前缺乏必要的历史记录或数组计算的 TFs,因此需要将其上载。
上载后结果如下:

2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H2========
2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000379996800, время выполнения 1 иттерации = 4.60 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000379996800, время выполнения 1 иттерации = 2.60 наносекунд - Быстрый расчет
2023.11.14 12:47:06.159 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000009103200, время выполнения 1 иттерации = 129.10 наносекунд - Расчет через iBarShift
2023.11.14 12:47:06.159 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_M4========
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000411199920, время выполнения 1 иттерации = 2.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000411199920, время выполнения 1 иттерации = 1.40 наносекунд - Быстрый расчет
2023.11.14 12:47:13.903 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000038634480, время выполнения 1 иттерации = 381.30 наносекунд - Расчет через iBarShift
2023.11.14 12:47:13.903 timeToStartMonth (EURUSD,M1)    ========================================================================

附加的文件:
 
Nikolai Semko #:

快速算法爱好者。为纳秒而战的人:)

...

😮😲😳🥴🤪

...

啊...

mmm....

oooh....

gkghm...我没想到我简单的问题会变成这样

就像这样

 
Artyom Trishkin #:

😮😲😳🥴🤪

...

啊...

mmm.

ohhhh....

ahem.我没想到我简单的问题会问成这样。

呵呵。

是的,Artem,你骗了我好一阵子。
,这是一种体育兴趣。
,我希望它能对某人有用,包括我在内。:))

 
Nikolai Semko #:

是的,Artem,你欺骗了我一段时间。
,我对体育感兴趣。
,我希望它对某人有用,包括我自己。:))

当然有用。太好了。再次感谢您!

S.F. 这句话逗乐了我:"正确计数只到 28.02.2100 !!!!"。

那之后我们该怎么办?

 
Artyom Trishkin #:

当然会派上用场太好了再次感谢

S.F. 这句话逗乐了我:"只正确计算到 28.02.2100 !!!!"。

那之后我们该怎么办?


,我怀疑这种算法在 75 年内都不会过时。量子计算机可能已经统治世界了,其程序完全不同。
说实话,考虑到公历是偷懒。2000 年是高风险时期,2100 年就不是了。

 
Nikolai Semko #:


,我怀疑这种算法在 75 年内都不会过时。量子计算机可能已经统治世界了,其编程方式完全不同。
,老实说,完全考虑公历是很懒的做法。2000 年是高风险时期,2100 年就不是了。

对于 MN,你可以使用一个预先计算好的数组,里面几乎什么都没有

Ln2(12个月 * 100年)......11个if`和二进制搜索中的比较,但没有其他计算。

 
Maxim Kuznetsov #:

您可以为 MN 使用一个预先计算好的数组,那里几乎没有任何数据。

Ln2(12 个月 * 100 年)......11 个 if`'s 和二进制搜索中的比较,但没有其他计算。

没有任何困难。我知道如何实现它。
我只是不想做那些我百分之百肯定不会有用的事情。
 
Maxim Kuznetsov #:

您可以为 MN 使用一个预先计算好的数组,那里几乎没有任何数据。

Ln2(12个月 * 100年)......11个if`和二进制搜索中的比较,但没有其他计算。

啊,我一开始读错了。
不,你错了。性能提升不会起作用。你仍然会被计算卡住。而且访问数组元素会大大降低算法的速度。