Данный пост посвящен дополнительному функционалу библиотеки виртуального окружения Virtual:
Мультисимвольность.
Теперь можно торговать в VIrtual не по одному символу, а по любым в одном виртуальном окружении. И таких окружений может быть любое количество (ограничения только по памяти). Это позволяет, например, значительно проще создавать копиры с тех же криптобирж. Сценариев применения много. Здесь же остановимся на применении данного функционала в MT5-Тестере.
Тестер.
Для проверки корректности работы мультисимвольного торгового окружения возьмем такой советник (на базе этого).
#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006 #define VIRTUAL_TESTER_MULTI // Запуск в виртуальном торговом окружении OnTickMulti #define VIRTUAL_LIMITS_TP_SLIPPAGE // Лимитники и TP исполняются по первой цене акцепта - положительные проскальзывания #define VIRTUAL_CLOSEALL_BYEND // Закрывает принудительно все ордера в конце тестирования #include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/ru/code/47647 #define REPORT_TESTER // В тестере будут автоматически записываться отчеты #define REPORT_BROWSER // Создание отчета с запуском браузера - требует разрешения DLL. #include <Report.mqh> // https://www.mql5.com/ru/code/18801 // https://www.mql5.com/ru/forum/282062/page46#comment_50705106 input group "EA's inputs" input int inAmount = 5; input int inOffset = 5; input int inRange = 0; bool OrdersBuy[]; bool OrdersSell[]; void OnInit() { ArrayResize(OrdersBuy, inAmount + 1); ArrayResize(OrdersSell, inAmount + 1); } // Мультисимвольный OnTick. void OnTickMulti( const string &Symb, const int &Index ) { MqlTick Tick; if (SymbolInfoTick(Symb, Tick)) { const double Offset = inOffset * SymbolInfoDouble(Symb, SYMBOL_POINT); ArrayInitialize(OrdersBuy, false); ArrayInitialize(OrdersSell, false); for (uint i = OrdersTotal(); (bool)i--;) if (OrderSelect(i, SELECT_BY_POS) && (OnTickMulti.IsOnlySymbolBase || (// VIRTUAL::GetHandle() ? (OrderSymbolID() == Index) : // https://www.mql5.com/ru/forum/282062/page52#comment_51051261 (OrderSymbol() == Symb)))) { const ulong Magic = OrderMagicNumber(); switch (OrderType()) { case OP_BUY: OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.bid + Magic * Offset, 0); OrdersBuy[Magic] = true; break; case OP_SELL: OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.ask - Magic * Offset, 0); OrdersSell[Magic] = true; break; case OP_BUYLIMIT: OrderModify(OrderTicket(), Tick.ask - Magic * Offset, 0, 0, 0); OrdersBuy[Magic] = true; break; case OP_SELLLIMIT: OrderModify(OrderTicket(), Tick.bid + Magic * Offset, 0, 0, 0); OrdersSell[Magic] = true; break; } } for (int i = 1; i <= inAmount; i++) { if (!OrdersBuy[i]) OrderSend(Symb, OP_BUYLIMIT, 1, Tick.ask - i * Offset, 0, 0, 0, NULL, i); if (!OrdersSell[i]) OrderSend(Symb, OP_SELLLIMIT, 1, Tick.bid + i * Offset, 0, 0, 0, NULL, i); } } } double OnTester() { return(AccountInfoDouble(ACCOUNT_BALANCE)); }
Торговая логика советника в коде начинается с выделенной строки. Если кратко, то он просто держит несколько лимитников по обе стороны от цены. Когда лимитник срабатывает - начинает аналогично держать TP-уровень. И так по каждому заданному символу.
Результат запуска в Тестере создаст удобный HTML-отчет результатов торговли.
Виртуальное окружение.
Для запуска в виртуальном окружении нужно установить следующий входной параметр.
Сравнение сгеренированных HTML-отчетов Тестером (по тикам в режиме по пипсам) показывает идентичность результатов.
Производительность.
Время выполнения одиночного прохода в таблице (отключен Report).
MT5-Tester | MT5-Tester + Virtual | MT5-Tester + Virtual + SymbolID |
---|---|---|
11.421 sec. | 01.720 sec. | 01.157 sec. |
На данном примере применение Virtual позволило получить идентичный результат в ~6.5 (~10) раз быстрее.
Технические подробности.
С вопросами и предложениями лучше в ветку обсуждения.
Ссылка на блог автора.