Библиотеки: MathTicker - генератор тиков в математическом режиме - страница 8

 
fxsaber #:
Запускаю этот советник


с такими настройками (из архива символов).


В логе такое.


Проблема только с символами из архива.

Нужно установить даты на которых надо тестировать и которые записаны в архиве:

У вас с 1970 по 1970

 

В январе сделал обновление. Только что закачал в кодобазу.
Изменения:

1) Добавлен

sinput double MathBalance = 10000;// Initial balance

но в библиотеке напрямую не используется. А используется в вызывающей программе. Добавил сюда, т.к. посчитал это оптимальным вариантом - если используется архив в мат. режиме - значит нужно и начальный баланс иметь.


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

sinput double MathSwapLong = 0;//Swap Long
sinput double MathSwapShort = 0;//Swap Short
enum dayOfWeek {Sunday=0,Monday=1,Tuesday=2,Wednesday=3,Thursday=4,Friday=5,Saturday=6};
sinput dayOfWeek  MathSwap3days = 3;//Swap 3 days

Если нужно считать свопы записанные в архиве, то они доступны тут (так было в предыдущей версии). Сейчас закомментированы.

#define __swapShort  MathTick.swapShort;
#define _swapLong  MathTick.swapLong;
#define _swap3days  MathTick.swap3days;
Но использовать устаревшие свопы нет смысла - они регулярно меняются. Лучше подставлять текущие свопы из спецификации символа. Так тесты в мат. режиме будут очень близки к тестам в тестере от MQ. Разница в сумме свопов будет только при округлении центов.
 
Aleksei Kuznetsov #:

2) Откзался от считывания свопов из архива.

Склоняюсь в сторону хранения всех свойств символа в JSON-файле, который делает сам MT5.
 
Aleksei Kuznetsov #:

Нужно установить даты на которых надо тестировать и которые записаны в архиве:

У вас с 1970 по 1970

Вроде, уже почти стандарт, что если задан ноль - то вся история.
 
Aleksei Kuznetsov #:

сделал обновление.

Штатное обнуление.
      ArrayResize(this.Ticks,this.TicksPerBlock);
//      this.TicksFill0(this.Ticks,this.TicksPerBlock);//заполнить 0, чтобы не делать это на каждом тике
      ::ZeroMemory(this.Ticks);
 
#ifdef MathTicker_optimize
   input group "MathTicker Optimization best number of files and ticks"
   input int inRepeats=5;
   input int inTicksLen=30000;//optimize best number of ticks per read from file 
#else // #ifdef MathTicker_optimize
   int inTicksPerBlock=30000;//30000 2.04 10000 2.1 
#endif // #ifdef MathTicker_optimize 

Возможно, статический массив ускорит дело.

class MathTicker{
   int hs,hr,TicksPerBlock,_TickItems; int Task,ticks,nextSize,ticksTotal; string path;
public: //Compression_ = 0: no compression, 1: Forex/CFD, 2: Exchange
   double Point_,TickSize_,TickValue_,VolumeStep_,swapShort,swapLong; int Digits_,minFreezeLevel_,minStopLevel_, prev_year,Selected_year,swap3days; string Symbol_,Selected_Instrument; datetime Selected_Start_Date,Selected_End_Date; bool isMath; 
   TickCompressor TickCompr;
   MqlDateTime dateStruct;
   MqlTick Ticks[30000];
   uchar Archive[];
 
fxsaber #:
Штатное обнуление.
fxsaber #:

Возможно, статический массив ускорит дело.

Теоретически быстрее. Обновил.
Ускорение на уровне погрешности.

Старый
2026.02.11 11:35:51.742    pass 8 returned result 514165380.744476 in 0:00:07.788
2026.02.11 11:35:51.742    optimization finished, total passes 11
2026.02.11 11:35:51.752    optimization done in 0 minutes 24 seconds
2026.02.11 11:35:51.752    shortest pass 0:00:07.714, longest pass 0:00:08.174, average pass 0:00:07.930

Новый вариант

2026.02.11 11:39:50.482    pass 10 returned result 514165380.744476 in 0:00:07.749
2026.02.11 11:39:50.482    optimization finished, total passes 11
2026.02.11 11:39:50.492    optimization done in 0 minutes 24 seconds
2026.02.11 11:39:50.492    shortest pass 0:00:07.659, longest pass 0:00:08.392, average pass 0:00:08.033

 
Aleksei Kuznetsov #:

Ускорение на уровне погрешности.

Делается лишний шаг - заполнение массива и пробег по нему.

            tick=TickCompr.DeCompress(this.Archive,Ticks, this.nextSize, 0); //распаковать блок и перезаписать в Ticks
            this.nextSize =ns;
            //this.nextSize=FileReadInteger(this.hr);// считать длину блока в байтах - альтернатива чтению размера в массив +4. Вдвое больше обращений к диску из за 4 байт
            if(this.Task==0){
               for (j = 0; j < (uint)tick; j++){ Strategy(Ticks[j]); } //стратегия  

Архитектурно быстрее будет так.

int Pos = 0;

while (TickCompr.NextTick(this.Archive, Pos, Tick)) // bool TickCompressor::NextTick( const uchar &Archive[], int &Pos, MqlTick &Tick ); // Pos сдвигается внутри.
  Strategy(Tick);


ЗЫ Сам делаю именно так.

        for (uint j = 0; j < Size; j++)
          if (this.TicksShort.Decompress(Ticks[j], this.Tick))
          {
            VIRTUAL::NewTick_NoCheck(this.Tick);

            ::OnTickOriginal_EAToMath();
 
fxsaber #:

Делается лишний шаг - заполнение массива и пробег по нему.

Архитектурно быстрее будет так.


ЗЫ Сам делаю именно так.

Сам пользуюсь блоками сжатыми в ZIP. Их можно только целиком распаковать. Так же тики сжаты до разного числа байт. Можно конечно из тех функций делать вызовы Strategy(Tick);

Но на это надо потратить часы, чтобы понять что-куда, сделать и протестировать во всех режимах. Ради нескольких миллисекунд не готов на такие временные затраты. Мои тесты с МО 12 дней считаются - секунды не дадут ничего.
Инструмент работает - теперь его лучше не трогать.

 
Aleksei Kuznetsov #:

Сам пользуюсь блоками сжатыми в ZIP. Их можно только целиком распаковать.

Логичнее же их один раз ZIP-распаковать в OnTesterInit.