Ставь лайки и следи за новостями
Поставь на него ссылку - пусть другие тоже оценят
Оцени его работу в терминале MetaTrader 5
- Просмотров:
- 325
- Рейтинг:
- Опубликован:
- Обновлен:
-
Нужен робот или индикатор на основе этого кода? Закажите его на бирже фрилансеров Перейти на биржу
Альтернатива для библиотеки EAToMath https://www.mql5.com/ru/code/61283
Записывает тики в режиме по реальным тикам и считывает их в математическом вызывая вашу стратегию с каждым записанным тиком.
Причина создания: Тестер MQ, записывает файлы с тиковыми данными каждому агенту при каждом запуске оптимизатора. У меня 36 агентов записывают по 10 Гб для одного из инструментов и периода тестирования - итого 360Гб на диске в 480 Гб. Занимает времени этот процесс около 1 часа перед каждой оптимизацией. Обычные SSD имеют ресурс в 500-1000 циклов записи. Перезаписывая 360 Гб каждый раз ресурс очень быстро исчерпается. Данная библиотека записывает только 1 файл и потом все 36 агентов будут читать данные из этого одного файла. Всё это и было причиной написания библиотеки: используем только 1 файл + экономия 1 часа на запись данных каждому агенту + ускорение по сравнению с тестером MQ и даже с Virtual в режиме по реальным тикам.
Проблему исследовали одновременни с fxsaber (автором EAToMath), каждый со своей версией. Мой код мне более понятен, поэтому использую его.
Для торговых операций используется библиотека MT4Orders https://www.mql5.com/ru/code/16006
Для виртуальной торговли нужно использовать библиотеку Virtual https://www.mql5.com/ru/code/22577
Для просмотра результатов торговли можно использовать MT4Orders QuickReport https://www.mql5.com/ru/code/47816 или Report
Для сжатия тиков TickCompressor https://www.mql5.com/ru/code/66201
Для удаления возможно лишних тиков подключается библиотека Control_Trade_Sessions https://www.mql5.com/ru/code/48059 например, если котировочная сессия больше торговой. Её можно и удалить, если используются все тики. т.е. сессии совпадают.
Отличия от EAToMath:
Плюсы:
- код короче и проще, всего 5 подключаемых библиотек. При необходимости доработки - будет проще разобраться.
- данные сжимаются лучше, благодаря другому алгоритму https://www.mql5.com/ru/code/66201. При сохранении только time_msc, ask и bid - до 86% тиков сохраняются как 3 char числа, т.е. 3 байта. Средний размер на тик = 3.266 Байта при сохранении тиковых данных BTCUSDT за 2023 год.
При сохранении с объемами среднее = 4.835 Байта. И при сохранении полном тике = 8.439 Байта. Ниже будет таблица с результатами теста.
Дополнительно можно использовать встроенную ZIP архивацию. Размер файлов уменьшается еще в 2 раза. Такой файл занимает 245 Мб, при этом сумма рамеров файлов в .tcs за 2023 год занимает 364 Мб, т.е. сжатие в 1,5 раза лeчше чем у MQ. А скорость генерации тиков в математическом режиме в ~2 раза выше. См. таблицу ниже. - Вариантов сохранения больше:

- файл можно сохранять как на SSD, так и на RAM диск, сделав ссылку в системе. Файлы могут занимать много места и RAM диска может не хватать, поэтому можно выбрать сохранение на основной диск. Скорость чтения с SSD и с RAM примерно одинаковы, Читал, что SSD кеширует до 5% от полного объема самые часто запрашиваемые данные.
При чтении есть небольшой износ SSD, т.к. чаще нужно перезаписывать ячейки памяти, чем при хранении без чтения. Точных цифр не знаю, но например 1 перезапись на 10 чтений или на 1000... Но это мало значимо по сравнению с износом диска тестером MQ.
Минусы:
- Подключение Virtual нужно делать самостоятельно (инструкция по использованию тут https://www.mql5.com/ru/code/22577), EAToMath сам передаст вашу стратегию в Virtual.
Скорость работы для BidAsk варианта соизмерима с EAToMath. Другие варианты медленнее, т.к. или содержат больше данных или имеют дополнительное ZIP сжатие.
Особенности использования:
В стратегии нельзя использовать стандартные функции Symbol(), Digits() (=4), Point() (=0.0001), т.к. они выдадут дефолтные значения, а не относящиеся к тестируемому символу. Вместо них используйте _Symbol, _Digits, _Point которые переопределены на значения считанные из файла. Так же добавлены новые константы _TickSize и _TickValue с значениями от записанного символа - они нужны для правильного расчета прибыли, комиссии и свопов в валюте депозита.
Порядок работы с периодом тестирования выбранным при сохранении тиков:
- Выбрать режим тестирования по реальным тикам, нужный инструмент и даты тестирования. Переменную Task установить в один из Save и выбрать вариант сохранения тиков. Запустить тестер. После этого в указанной папке будет создан файл с тиками.
- Установить переменную Task в Run_Strategy. Режим можно оставить по реальным тикам, чтобы потом сравнить. Запустить тестер. Расчеты производятся по реальным тикам, а не из файла. Получить результат.

- Установить режим тестирования в математические расчеты. Запустить тестер. Расчеты производятся по тикам из файла. Сравнить с результатом из п.2. Должно быть одинаково, но в несколько раз быстрее.
Порядок работы с архивом:
- Создать архив со всеми тиками из истории: Выбрать режим тестирования по реальным тикам, нужный инструмент. Даты тестирования установить от <= первого тика, до >= последнего тика в имеющейся истрии . Переменную Task установить в один из Save...To_Archive и выбрать вариант сохранения тиков. Запустить тестер. После этого в указанной папке будет создана папка с именем инструмена в которой сохранятся файлы с тиками для каждого года. Последний год можно по мере необходимости перезаписывать, для этого в датах выбрать только текущий год, чтобы не перезаписывать предыдущие годы.
- Установить режим тестирования в математические расчеты. Установить переменную Task в Run_Strategy_Fron_Archive.
- В группе инпутов MathTicker: using the full archive установить:
Instrument - в название инструмента (должно совпадать с названием папки, где хранятся его тики), стартовую и конечную дату теста.

- Запустить тестер. Расчеты производятся по тикам из требуемых годовых файлов. Из за того, что работа идет не с одним файлом, а с несколькими, то это немного медленнее, т.к. тратится время на открытие и закрытие файлов. Например вместо 1.7 секунды будет 2.7 секунды на генерацию тиков за 3 года.
- Сумма тиков полученная экспертом ниже может отличаться на небольшое значение одного первого тика. При тестах на кастоминых символах в режиме реальных тиков первый тик выдает только Ask или Bid (если вы не сохраняли оба). При тесте из архива они оба восстановлены из предыдущих тиков.
Пример простейшего эксперта для оценки скорости работы:
#property tester_no_cache #include <Forester\MathTicker.mqh> // подключение торговли в математическом режиме input int rep=0;//Repeats for optimization sinput bool AddVolumes=true; void OnInit(){} void OnTick(){ static MqlTick Tick; if (SymbolInfoTick(_Symbol, Tick)){ #ifdef _MathTick_ if(MathTick.SaveTick(Tick)){ return; }//если сохраняем тики, то выход и не торгуем. #endif Strategy(Tick); } } double Sum = 0;int tk=0; void Strategy(MqlTick& Tick){ // простейшая стратегия - использована для сравнения скорости чтения с EAToMath Sum += Tick.bid+Tick.ask+(AddVolumes?Tick.volume_real:0.0); tk++; //if(tk<100){Print(Tick.time," ",Tick.ask," ",Tick.bid," ",Tick.last," ",Tick.volume_real," ",Tick.flags);} } ulong StartTime = GetMicrosecondCount(); double OnTester(){ #ifdef _MathTick_ // запуск с MathTick - он считает параметры символа из файла с тиками. Для тестов в мат режиме if(MathTick.SaveTicksEnd()){return 0;}//закрыть файл после записи тиков и выйти if(MathTick.ReadSymbolVars()){ MathTick.Ticker();//в режиме мат расчетов подаст все тики в Strategy(MqlTick &Tick). } #endif Print("ticks: ",tk); long work_time = (long)(GetMicrosecondCount() - StartTime)/1000; //return(NormalizeDouble(work_time, 1)); // для получения скорости работы и return Sum;// для сравнения результатов расчета }
Можно переключать 1 настройку:
//#define RestoreFlags // восстановить флаги тика из изменения ask, bid, volume - добавит 7% к времени генерации тиков 931 вместо 869 мс
При генерации тиков будет выведена статистика о сжатии тиков.
Ниже распечатки статистики, объемов и времени генерации тиков.
-----------
MQ тестер без объемов
pass 1 returned result 4345830621850.311523 in 0:00:08.232
| C ZIP сжатием | |
|---|---|
| AskBid. Размер файла: 225 mb -------------------- Statistics: -------------------- 3 bytes: 86.6%, 62644158 ticks 4 bytes: 0.6%, 412167 ticks 5 bytes: 12.7%, 9185484 ticks 6 bytes: 0.0%, 15274 ticks 11 bytes: 0.1%, 46214 ticks 12 bytes: 0.0%, 1 ticks 24 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 236108596 bytes. Average: 3.266 bytes per tick final balance 0.00 USD pass 10 returned result 4345830621850.311523 in 0:00:01.485 без нормализации pass 1 returned result 4345830621850.311523 in 0:00:00.892 | AskBid_Zipped. Размер файла: 106 mb -------------------- Statistics: -------------------- 3 bytes: 86.6%, 62644158 ticks 4 bytes: 0.6%, 412167 ticks 5 bytes: 12.7%, 9185484 ticks 6 bytes: 0.0%, 15274 ticks 11 bytes: 0.1%, 46214 ticks 12 bytes: 0.0%, 1 ticks 24 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 236108596 bytes. Average: 3.266 bytes per tick UnZipped size:236108596. Zipped size:111720863. ZIP compression: 47.3 % pass 10 returned result 4345830621850.311523 in 0:00:02.548 без нормализации pass 2 returned result 4345830621850.311523 in 0:00:01.890 |
MQ тестер с объемами
pass 1 returned result 4345879117123.356445 in 0:00:07.962
| C ZIP сжатием | |
|---|---|
| AskBidVolume. Размер файла: 333 mb -------------------- Statistics: -------------------- 4 bytes: 60.4%, 43684907 ticks 5 bytes: 1.1%, 809676 ticks 6 bytes: 33.5%, 24194111 ticks 7 bytes: 4.9%, 3548666 ticks 8 bytes: 0.0%, 7909 ticks 12 bytes: 0.1%, 40022 ticks 13 bytes: 0.0%, 17964 ticks 14 bytes: 0.0%, 2 ticks 19 bytes: 0.0%, 41 ticks 32 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 349571243 bytes. Average: 4.835 bytes per tick pass 1 returned result 4345879117123.356445 in 0:00:02.803 без нормализации pass 4 returned result 4345879117123.356445 in 0:00:01.659 | AskBidVolume_Zipped. Размер файла: 204 mb -------------------- Statistics: -------------------- 4 bytes: 60.4%, 43684907 ticks 5 bytes: 1.1%, 809676 ticks 6 bytes: 33.5%, 24194111 ticks 7 bytes: 4.9%, 3548666 ticks 8 bytes: 0.0%, 7909 ticks 12 bytes: 0.1%, 40022 ticks 13 bytes: 0.0%, 17964 ticks 14 bytes: 0.0%, 2 ticks 19 bytes: 0.0%, 41 ticks 32 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 349571243 bytes. Average: 4.835 bytes per tick UnZipped size:349571243. Zipped size:214897079. ZIP compression: 61.5 % pass 2 returned result 4345879117123.356445 in 0:00:04.260 без нормализации pass 2 returned result 4345879117123.356445 in 0:00:03.096 |
| All. Размер файла: 582 mb -------------------- Statistics: -------------------- 8 bytes: 61.5%, 44494583 ticks 9 bytes: 33.5%, 24194111 ticks 10 bytes: 4.9%, 3548666 ticks 11 bytes: 0.0%, 7909 ticks 15 bytes: 0.1%, 40022 ticks 16 bytes: 0.0%, 17964 ticks 17 bytes: 0.0%, 2 ticks 22 bytes: 0.0%, 41 ticks 44 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 610166056 bytes. Average: 8.439 bytes per tick pass 2 returned result 4345879117123.356445 in 0:00:03.768 без нормализации pass 1 returned result 4345879117123.356445 in 0:00:02.256 | All_Zipped. Размер файла: 245 mb -------------------- Statistics: -------------------- 8 bytes: 61.5%, 44494583 ticks 9 bytes: 33.5%, 24194111 ticks 10 bytes: 4.9%, 3548666 ticks 11 bytes: 0.0%, 7909 ticks 15 bytes: 0.1%, 40022 ticks 16 bytes: 0.0%, 17964 ticks 17 bytes: 0.0%, 2 ticks 22 bytes: 0.0%, 41 ticks 44 bytes: 0.0%, 1 ticks Total: 72303299 ticks, 610166056 bytes. Average: 8.439 bytes per tick UnZipped size:610166056. Zipped size:257105213. ZIP compression: 42.1 % pass 1 returned result 4345879117123.356445 in 0:00:05.388 без нормализации pass 10 returned result 4345879117123.356445 in 0:00:03.936 |
Размер файлов .tcs за тот же 2023 год:

Все варианты с ZIP, даже полное сохранение тиков - компактнее (от 3,5 до 1,5 раз).
Пример эксперта для виртуальной торговли и вывода отчетов:
#property tester_no_cache #include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006 #include <Forester\MathTicker.mqh> // подключение торговли в математическом режиме #define ORDER_CURRENCY_DIGITS 2 // Задание Digits для вычисления профита/комиссии/свопа при помещении в историю торгов. #define VIRTUAL_LIMITS_TP_SLIPPAGE // Лимитники и TP исполняются по первой цене акцепта - положительные проскальзывания #define ORDER_COMMISSION -0 // Задание комиссии = Lots * ORDER_COMMISSION. #include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/ru/code/22577 #define REPORT_TESTER // В тестере будут автоматически записываться отчеты #define REPORT_BROWSER // Создание отчета с запуском браузера - требует разрешения DLL. #define USE_highcharts //- You can download and try out all Highcharts products for free. Once your project/product is ready for launch, purchase a commercial license. https://shop.highcharts.com/ #include <MT4Orders_QuickReport.mqh>// enum VirtTyp {MQ_Tester=0,Virtual1=1,Virtual2=2}; sinput VirtTyp tester1=1;//Tester 1 sinput VirtTyp tester2=2;//Tester 2 input int rep=0;//Repeats for optimization bool isOptimization = false, isTester=false; double balInit=0; VIRTUAL_POINTER Virtual[10]; void OnInit(){ Virtual[0] = 0; // 0 - реальное торговое окружение Virtual[1] = VIRTUAL::Create(AccountBalance()); // Создали виртуалку 1. Virtual[2] = VIRTUAL::Create(AccountBalance()); // Создали виртуалку 2. //Virtual[tester1].Select(); isOptimization = MQLInfoInteger(MQL_OPTIMIZATION) ; isTester = MQLInfoInteger(MQL_TESTER); balInit=AccountBalance(); } void OnTick(){ //Virtual[0].Select(); VIRTUAL::NewTick();//отправить тик в текущую виртуалку static MqlTick Tick; if (SymbolInfoTick(_Symbol, Tick)){ #ifdef _MathTick_ if(MathTick.SaveTick(Tick)){ return; }//при записи тиков выйдет из функции, Strategy() не будет вызвана #endif Strategy(Tick);//trading } } void Strategy(MqlTick& Tick){ // простейшая стратегия - использована для сравнения скорости чтения с EAToMath if(Tick.ask==0 || Tick.bid==0){return;}//MQ тестер торгует при сбойном тике, Virtual нет. Запрет и для MQ if(tester1>0){Virtual[tester1].Select(); VIRTUAL::NewTick(Tick);}//выбрать виртуалку 1 и отправить тик if(tester2>0){Virtual[tester2].Select(); VIRTUAL::NewTick(Tick);}//выбрать виртуалку 2 и отправить тик if(isNewHour(Tick.time)){//первый тик каждого часа if(GetHour0(Tick.time) % 2==0){// купить по четным часам в тестере 1 Virtual[tester1].Select();//выбрать виртуалку 1 OrderSend(_Symbol, OP_BUY, 1, Tick.ask, 0, Tick.ask - 100 * _Point, Tick.ask + 100 * _Point); }else{//продать по нечетным часам в тестере 2 Virtual[tester2].Select();//выбрать виртуалку 2 OrderSend(_Symbol, OP_SELL, 1, Tick.bid, 0, Tick.bid + 100 * _Point, Tick.bid - 100 * _Point); } } } double OnTester(){ #ifdef _MathTick_ // запуск с MathTick - он считат параметры символа из файла с тиками. Для тестов в мат режиме if(MathTick.SaveTicksEnd()){return 0;}//return after ticks saving if(MathTick.isMath && MathTick.ReadSymbolVars()){ if(tester1==0){Alert(" >>>>>>>>> Virtual tester 1=MQ. In math mode can be used only virtual tester. <<<<<<<<");return 0;} if(tester2==0){Alert(" >>>>>>>>> Virtual tester 1=MQ. In math mode can be used only virtual tester. <<<<<<<<");return 0;} SYMBOL_BASE sb; sb.Point=_Point; sb.Digits=_Digits; sb.Symbol=_Symbol; sb.SymbolID=0; sb.TickSize=_TickSize; sb.TickValue=_TickValue / _TickSize;//this.TickValue_ /= this.TickSize_; //as in SetSymbol() in \fxsaber\Virtual\Symbol_Base.mqh Virtual[1].Select(); VIRTUAL::SetSymbolBase(sb); Virtual[2].Select(); VIRTUAL::SetSymbolBase(sb); //minFreezeLevel = _minFreezeLevel*_Point; minStopLevel = _minStopLevel*_Point; Virtual[tester1].Select(); MathTick.Ticker();//в режиме мат расчетов подаст все тики в Strategy(MqlTick &Tick). } #endif double ret_val=0; for (int v = 0 ; v <= VIRTUAL::Total(); v++){ if(Virtual[v].Select()){ if(v > 0){ VIRTUAL::Stop(); #ifdef _MathTick_ // запуск с MathTick - он считат параметры символа из файла с тиками. Для тестов в мат режиме if(MathTick.isMath){ VIRTUAL::CalcSwaps( MathTick.swapShort, MathTick.swapLong, 0, MathTick.swap3days ); }//свопы из файла с тиками else{VIRTUAL::CalcSwaps( _Symbol, 0 );} #else VIRTUAL::CalcSwaps( _Symbol, 0 );//расчитать свопы - всем сделкам один своп, т.е. если 2+ разных инструмента, то обоим будет своп основного символа #endif }// закрыть незавершенные сделки по цене последнего тика, как в тестере if( !isOptimization){QuickReport("report_"+(string)v, true, v,false,true);} Print((string)v+" AccountBalance = ",AccountBalance(), " AccountEquity = ",AccountEquity()); double prib=AccountBalance()-balInit; ret_val += prib; // }} return ret_val;// для сравнения результатов расчета } bool isNewHour (datetime &t){ static int next_h=-1; if(t < next_h){ return false; } else { next_h = (GetHour0(t)+1)*3600;return true;}} int GetHour0 (datetime &t){return((int)( t / 3600));}//current hour from 1 Jan 1971
Этот пример создает 2 виртуальные машины в которых идет разная торговля. По четным часам в одном тестере происходит покупка, в другом по нечетным часам продажа.
Сделан сложный пример с 2-мя тестерами, его можно упростить, если нужна работа с одним тестером.
Так же для контроля правильности расчетов можно выбрать тестер MQ и сравнить с результатами виртуальных тестеров. Может не совпадать только комиссия, т.к. разных комиссий придумано много, а в виртуальном тестере запрограммирован только один вариант.
OHLC Candles with Ask and Bid
Свечной график, который соединяет цену спроса и цену предложения с максимумом и минимумом свечи
Custom Bollinger Bands
Стандартный индикатор Bollinger Bands с добавлением функции усреднения
OHLC Candles with extreme tick price tracking
Это свечной график OHLC, который фиксирует максимальную цену покупки и минимальную цену продажи на каждом новом баре.
Manual Backtest Bar Replay Simulator
Простой индикатор, который может помочь вам в ручном бэктесте, просто перемещая вертикальную линию, чтобы показать скрытые бары.