Библиотеки: OnTickMulti

 

OnTickMulti:

Мультисимвольный OnTick.

OnTickMulti

Автор: fxsaber

 
Мультисимвольное виртуальное окружение.
Мультисимвольное виртуальное окружение.
  • www.mql5.com
Данный пост посвящен дополнительному функционалу библиотеки виртуального окружения Virtual : Мультисимвольность. Теперь можно торговать в VIrtual не по одному символу, а по любым в одном виртуальном
 
   if (prev_calculated)
    EventChartCustom(Chart, 0, Index, 0, NULL);
Вы можете пропустить тики, если событие не поставлено в очередь. Бывает (в основном на VPS или медленном компьютере).
 
Alain Verleyen #:
Вы можете пропустить тики, если событие не поставлено в очередь. Бывает (в основном на VPS или медленном компьютере).

К сожалению, даже простые советники с одной только функцией OnTick пропускают тики. Для боевых советников используют CopyTicks-функции и другие ухищрения, чтобы работать без пропуска тиков.

Данная библиотека гарантировано не пропускает тики только в Тестере. Все точно также, как с OnTick.

 
Ниже код чужого простого советника, на котором вызвался показать применение OnTickMulti.
/*
// https://www.mql5.com/ru/blogs/post/755348
#define VIRTUAL_TESTER_MULTI // Запуск в виртуальном торговом окружении OnTickMulti
#define VIRTUAL_LIMITS_TP_SLIPPAGE // Лимитники и TP исполняются по первой цене акцепта - положительные проскальзывания
#define VIRTUAL_CLOSEALL_BYEND // Закрывает принудительно все ордера в конце тестирования
// #define VIRTUAL_ALTERNATIVE // Альтернативная скорость расчетов
*/

#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006
#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
*/

input group "Trading"
input double             LotSize=0.01;
input double             TPdist=0.1;                        // TP (%)
input double             SLdist=0.2;                        // SL (%)
input long               MyMagic=123;

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

// Мультисимвольный OnTick.
void OnTickMulti( const string &Symb, const int &Index )
{
  TradeStep(Symb, Index);
}

double OnTester()
{
   return AccountInfoDouble(ACCOUNT_BALANCE);
}

int GetHour( const datetime time )
{
  return((int)(time / 3600) % 24);
}

void TradeStep( const string &symbol, const int &Index )
{
   if(GetHour(TimeTradeServer()) < 2)
      return;

   DoTrade(symbol, Index);
}

bool IsMySymbol( const string &Symb, const int &Index )
{
  return(OnTickMulti.IsOnlySymbolBase ||
         (
        #ifdef __VIRTUAL__
          VIRTUAL::GetHandle() ? (OrderSymbolID() == Index) : // https://www.mql5.com/ru/forum/282062/page52#comment_51051261
        #endif // #ifdef __VIRTUAL__
          (OrderSymbol() == Symb)));
}

void DoTrade(const string &symbol, const int &Index )
{
   int total=OrdersTotal();
   bool haveBuy=false;
   bool haveSell=false;
   for(int i=0; i<total; i++)
   {
      if(OrderSelect(i, SELECT_BY_POS) &&
         OrderMagicNumber()==MyMagic &&
         IsMySymbol(symbol, Index))
      {
         int type=OrderType();
         if(type==OP_BUY)
            haveBuy=true;
         if(type==OP_SELL)
            haveSell=true;
      }
   }
   
   if(!haveBuy)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0+TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0-SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_BUY,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         MyMagic);
   }

   if(!haveSell)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_BID);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0-TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0+SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_SELL,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         MyMagic);
   }
}


Настройки Тестера.



Ускорение.

Можно ускорить, если раскомментировать вначале несколько строк.


Замеры.

Конфигурация Результат
Without Virtual.mqh. shortest pass 0:00:13.184, longest pass 0:00:15.031, average pass 0:00:13.633
With Virtual.mqh, inVirtualTester = false. shortest pass 0:00:14.735, longest pass 0:00:16.384, average pass 0:00:15.081
With Virtual.mqh, inVirtualTester = true. shortest pass 0:00:05.872, longest pass 0:00:05.964, average pass 0:00:05.919
With Virtual.mqh, inVirtualTester = true + VIRTUAL_ALTERNATIVE. shortest pass 0:00:06.172, longest pass 0:00:07.791, average pass 0:00:06.524

Советник предельно простой (0-2 открытых позиций по каждому символу с фиксированными SL/TP, без отложенных ордеров), поэтому в таком варианте можно добиться ускорения лишь в 2.5 раза.


TickValue+Swap+Commission.

Выше тесты делались в режиме по пипсам (см. скрин настроек), чтобы не пересчитывать TickValue на каждом тике, подключая для этого другие символы. В этом режиме результаты идентичные.

Если нужно ускорение с полным фаршем, то надо использовать это решение.

OnTickMulti - с добавленными пересчетом прибыли в валюту депозита, свопами, комисссией в % за лот.
OnTickMulti - с добавленными пересчетом прибыли в валюту депозита, свопами, комисссией в % за лот.
  • 2023.12.25
  • www.mql5.com
Текущий вариант OnTickMulti https://www.mql5.com/ru/code/47647 считает прибыль в валюте каждого символа или можно получить в пипсах. Но на общий баланс они влияют в другой пропорции, согласно текущему
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: OnTickMulti

fxsaber, 2024.03.18 18:36

void DoTrade(const string &symbol, const int &Index )
{
   int total=OrdersTotal();
   bool haveBuy=false;
   bool haveSell=false;
   for(int i=0; i<total; i++)
   {
      if(OrderSelect(i, SELECT_BY_POS) &&
         (OrderMagicNumber()==Index))
      {
         int type=OrderType();
         if(type==OP_BUY)
            haveBuy=true;
         if(type==OP_SELL)
            haveSell=true;
      }
   }
   
   if(!haveBuy)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0+TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0-SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_BUY,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         Index);
   }

   if(!haveSell)
   {
      double price=SymbolInfoDouble(symbol,SYMBOL_BID);
      int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      double tp=NormalizeDouble(price*(1.0-TPdist/100.0), digits);
      double sl=NormalizeDouble(price*(1.0+SLdist/100.0), digits);
      OrderSend(
         symbol,
         OP_SELL,
         LotSize,
         price,
         0,
         sl,
         tp,
         NULL,
         Index);
   }
}

Конфигурация Результат
Without Virtual.mqh. shortest pass 0:00:13.184, longest pass 0:00:15.031, average pass 0:00:13.633

Выше выделил в коде простой способ ускорения мультивалютного советника без каких-либо Virtual-библиотек.

Конфигурация Результат
Without Virtual.mqh + MagicNumberOrderSymbol   shortest pass 0:00:08.608, longest pass 0:00:10.236, average pass 0:00:08.942

Бесплатное ускорение в 1.5 раза!

 

Проверил замедление Тестера при переходе от моносимвольного режима в мультисимвольный. Делал это не совсем идеально - советник пустышка.


Моносимвольный советник.

#property tester_no_cache

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

const ulong StartTime = GetMicrosecondCount();
int AmountTicks = 0;

double OnTester()
{
  return((double)(GetMicrosecondCount() - StartTime));
//  return(AmountTicks);
//  return((double)AmountTicks / (GetMicrosecondCount() - StartTime));
}

void OnTick()
{
  AmountTicks++;
}
Configuration (OnTick) TimeLength (mcs) AmountTicks  Performance (ticks/mcs)
 EURUSD 1079331 9927153 9.19
 GBPUSD 1229032 11309740 9.20
 USDJPY 1307322 11986756 9.16
 USDCHF 1121541 10359511 9.23
 AUDUSD 1175578 10758136 9.15

Хорошо видно, что производительность Тестера в виде количества тиков в единицу времени не зависит от символа (режим по пипсам).


Мультисимвольный советник.

#property tester_no_cache

input group "Benchmark: https://www.mql5.com/ru/forum/282062/page49#comment_50801337"
input int inRange = 0;

#include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/ru/code/47647

const ulong StartTime = GetMicrosecondCount();
int AmountTicks = 0;

double OnTester()
{
  return((double)(GetMicrosecondCount() - StartTime));
//  return(AmountTicks);
//  return((double)AmountTicks / (GetMicrosecondCount() - StartTime));
}

// Мультисимвольный OnTick.
void OnTickMulti( const string &Symb, const int &Index )
{
  AmountTicks++;
}
Configuration (OnTickMulti) TimeLength (OnTickMulti) TimeLength (OnTick) AmountTicks   Performance (OnTickMulti) Performance (OnTick) 
EURUSD
3455901 1079331 9927153  2.87  9.19
EURUSD, GBPUSD
6617085 2308363
21236893  3.20  9.19
EURUSD, GBPUSD, USDJPY
9188781 3615685 33223649  3.61  9.18
EURUSD, GBPUSD, USDJPY, USDCHF
11517804 4737226 43583160  3.78  9.20
EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD
16058223 5912804 54341296  3.38  9.19

Производительность слабо зависит от количества символов, но при этом ниже в три раза.


Вывод.

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

 
Добавлен Apart-режим.
Мультивалютный Apart-режим.
Мультивалютный Apart-режим.
  • www.mql5.com
Большинство мультивалютных советников представляют из себя портфель независимых (по логике торговых сигналов) друг от друга ТС, где если связь и есть, то за счет ММ - все ТС оказывают влияние на общие