Особенности языка mql5, тонкости и приёмы работы - страница 235

 
Marat Sultanov #:
Раньше(еще в старых билдах компилятора) можно было использовать класс до его объявления:
Но теперь при компиляции получаем ошибку:
undefined class 'A' cannot be used

Если перестало работать, хорошо бы узнать, а правильно ли это.

Если делать не объекты, а указатели, то и старый вариант будет работать.

 
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());
}
 

Любителям быстрых алгоритмов. Тем кто борется за наносекунды :)


Задача: Найти время открытия бара по заданному времени и ТФ, когда точно известно, что бар в это время существует. Например, по времени открытия и закрытия позиций. 

Большинство программистов воспользуется связкой 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;
   }
}
//+------------------------------------------------------------------+

Главная сложность в этом алгоритме - это расчет времени начала месяца  (выделено зеленым цветом) Пожалуйста, не пытайтесь понять работу алгоритма. Там происходит магия, которая получилась в результате движения от простого к сложному. Обратный путь от сложного к простому пройти будет намного трудней.

Также выйгрыш в производительности обеспечивается алгоритмом получения секунд в баре из ТФ взамен стандартной функции 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 (выделено синим цветом) обусловлено текущем отсутсвием необходимой истории или вычесленных массивом ТФ, что инициирует их закачку. 
После закачи результат будет следующим:

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 #:

Любителям быстрых алгоритмов. Тем кто борется за наносекунды :)

...

😮😲😳🥴🤪

...

аа..

ммм...

ооооо....

гкхм... Не думал, что мой простой вопрос выльется вот всюдатакоевот.

Вот прям О

 
Artyom Trishkin #:

😮😲😳🥴🤪

...

аа..

ммм...

ооооо....

гкхм... Не думал, что мой простой вопрос выльется вот всюдатакоевот.

Вот прям О

да, Артем, развел ты меня на время. 
Сработал спортивный интерес. 
Надеюсь пригодится кому-нибудь, и мне в том числе. :))

 
Nikolai Semko #:

да, Артем, развел ты меня на время. 
Сработал спортивный интерес. 
Надеюсь пригодится кому-нибудь, и мне в том числе. :))

Конечно пригодится. Супер. Ещё раз спасибо тебе!

ЗЫ. Вот это позабавило: "корректно считает только до 28.02.2100 !!!!"

Что потом-то делать будем?

 
Artyom Trishkin #:

Конечно пригодится. Супер. Ещё раз спасибо тебе!

ЗЫ. Вот это позабавило: "корректно считает только до 28.02.2100 !!!!"

Что потом-то делать будем?

хаха. 
Сомневаюсь что этот алгоритм будет востребован 75 лет. Уже квантовые компьютеры наверное будут править миром, в которых совсем другое программирование. 
если честно, то лениво было учитывать полностью Григорианский календарь. 2000-й был высокостным, а 2100 уже нет.

 
Nikolai Semko #:

хаха. 
Сомневаюсь что этот алгоритм будет востребован 75 лет. Уже квантовые компьютеры наверное будут править миром, в которых совсем другое программирование. 
если честно, то лениво было учитывать полностью Григорианский календарь. 2000-й был высокостным, а 2100 уже нет.

для MN можно предрасчитанный массив использовать, там данных-то почти всего ничего

Ln2(12 месяцев * стo лет)...11 if`ов и сравнений в двоичном поиске, зато без прочих вычислений

 
Maxim Kuznetsov #:

для MN можно предрасчитанный массив использовать, там данных-то почти всего ничего

Ln2(12 месяцев * стo лет)...11 if`ов и сравнений в двоичном поиске, зато без прочих вычислений

Сложностей нет. Знаю как реализовать.
Просто реально не хочется делать то, что на 100% уверен никогда не пригодится 
 
Maxim Kuznetsov #:

для MN можно предрасчитанный массив использовать, там данных-то почти всего ничего

Ln2(12 месяцев * стo лет)...11 if`ов и сравнений в двоичном поиске, зато без прочих вычислений

а, сначала, неправильно прочитал. 
Не - ошибаешься. Не прокатит увеличение производительности. Все равно упрешься в вычисления. Да и доступ к элементам массива очень сильно тормозит алгоритм.

Причина обращения: