Библиотеки: Virtual - страница 28

 
Igor Makanu:

ОК, тогда вообще для простого юзера ничего не нужно делать со своим исходным ЕА

Думаю, много есть реализаций виртуальных окружений. Virtual выделяет только эта фишка.

 

поковырялся в КБ, вспомнил как делал автоподключение ))

в качестве разминки добавил немного макросов, работает без проблем

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

#define VIRTUAL_ON

#ifdef VIRTUAL_ON
#define INS_VIRTUALOnInit if(!VIRTUAL::SelectByHandle(VIRTUAL::Create())) return(INIT_FAILED);
int OnInit(void){INS_VIRTUALOnInit; ::INSOnInit_(); return(INIT_SUCCEEDED);}
#define INS_VIRTUALOnTick VIRTUAL::NewTick();
void OnTick(void){INS_VIRTUALOnTick; ::INSOnTick_(); Comment(VIRTUAL::ToString());}
#ifdef OnInit
#undef OnInit
#endif // OnInit
#ifdef OnTick
#undef OnTick
#endif // OnTick
#define OnInit INSOnInit_
#define OnTick INSOnTick_
#endif // VIRTUAL_ON
 
Igor Makanu:

поковырялся в КБ, вспомнил как делал автоподключение ))

в качестве разминки добавил немного макросов, работает без проблем

Можно еще проще.

void OnTick(void){VIRTUAL::NewTick(::INSOnTick_); Comment(VIRTUAL::ToString());}
 
fxsaber:

Можно еще проще.

ну да

видел, что у Вас перегрузок методов много, но пока нет необходимости их изучать


в общем эта библиотека очень крутая и функциональная!


ЗЫ: DB Browser (SQLite) для работы с SQLite (бесплатно, гугл) полностью освободил мой ЕА от input-переменных, и в добавок могу на лету в БД параметры ЕА модифицировать и мониторить.... очень функционально, получилось, так сказать все из коробки и штатными средствами работает и графические интерфейсы оказались не нужны

 

В общем, голую максимально быструю (без каких-либо проверок) реализацию ядра делаете для Тестера.

Далее переход в боевой режим всегда одинаковый: запустили ядро в виртуалке, оттуда копиром на реал.


ТС становятся лаконичными, быстрыми и надежными.

 
Igor Makanu:

ЗЫ: DB Browser (SQLite) для работы с SQLite (бесплатно, гугл) полностью освободил мой ЕА от input-переменных, и в добавок могу на лету в БД параметры ЕА модифицировать и мониторить.... очень функционально, получилось, так сказать все из коробки и штатными средствами работает и графические интерфейсы оказались не нужны

Примеров бы. Есть мысли использования БД, но пока лень перебивает мотивацию.

 
fxsaber:

Примеров бы. Есть мысли использования БД, но пока лень перебивает мотивацию.

все возможности БД не знаю, да и не вижу смысла изучать подробно, но SQLite действительно лайт

пользуюсь парой тройкой запросов - в DB Browser (SQLite) создал тестовую БД в 2 клика и там же есть вкладка SQL где можете создать и проверить запрос

суть запросов очень проста и читаемая, вот читаю настройки ЕА , выбираю таблицу и указываю символ

const int handleDB = DatabaseOpen(FileName, DATABASE_OPEN_READONLY | DATABASE_OPEN_COMMON);
int request = DatabasePrepare(handleDB,
                                 "SELECT COUNT(*) "
                                 "FROM \"ExpertSetting\" "
                                 "WHERE Currency = \'" + sym + "\'");

ответ получаю количество ( count ) - у меня в качестве уникального ключа текстовое поле MD5 (хэш) сформированного из настроек ЕА в тестере (заодно БД сама проверяет, чтобы дубликатов не было - ключ уникальный)

читаю это значение (количество строк)

int count_md5;
   if(handleDB != INVALID_HANDLE && request != INVALID_HANDLE && DatabaseRead(request) && DatabaseColumnInteger(request, 0, count_md5))
   {

      printf("preparing to read %d records from DB", ArrayResize(SetsArr, count_md5));
      request = DatabasePrepare(handleDB,
                                "SELECT * "
                                "FROM \"ExpertSetting\" "
                                "WHERE Currency = \'" + sym + "\'");

и выбираю теперь настройки ЕА по символу  - запрос по сути тот же, но нет COUNT(*)   - вместо него выбираю все записи - чтобы не считать их в цикле, лень, БД пусть сама посчитает - не для тестера

и все в цикле начинаю читать свои настройки:

 printf("preparing to read %d records from DB", ArrayResize(SetsArr, count_md5));
      request = DatabasePrepare(handleDB,
                                "SELECT * "
                                "FROM \"ExpertSetting\" "
                                "WHERE Currency = \'" + sym + "\'");
      for(int i = 0; i < ArraySize(SetsArr) && request != INVALID_HANDLE && DatabaseRead(request); i++)
      {
         string MD5, TimeTesting, Currency;
         int isBoolRec[4];
         if(   !DatabaseColumnText(request, 0, MD5)                                    ||
               !DatabaseColumnText(request, 1, TimeTesting)                            ||
               !DatabaseColumnText(request, 2, Currency)                               ||
               !DatabaseColumnInteger(request, 3, SetsArr[i].Options.EAMagic)          ||
               !DatabaseColumnInteger(request, 6, SetsArr[i].Options.StartHour)        ||
               !DatabaseColumnInteger(request, 7, SetsArr[i].Options.EndHour)          ||
.......
	   ) request = INVALID_HANDLE;
printf("Read %d row , MD5 = %s, TimeTesting = %s, Currency = %s , BuySet = %d , SellSet = %d",


писать в БД  вообще просто - пишете INSERT INTO \"Имя_Таблицы\"  VALUES ( значение1, значени2....)"

https://www.mql5.com/ru/forum/300936/page27#comment_18047608


в общем очень все доступно в этой БД, за одну задачу можно разобраться как с ней работать  для задач записи/чтения и автоматической выборки по запросу WHERE условие 

или WHERE  условие1 AND условие2

ООП, шаблоны и макросы в mql5, тонкости и приёмы использования
ООП, шаблоны и макросы в mql5, тонкости и приёмы использования
  • 2020.03.23
  • www.mql5.com
В эту тему были перенесены комментарии, не относящиеся к "Особенности языка mql5, тонкости и приёмы работы"...
 
Igor Makanu:

все возможности БД не знаю, да и не вижу смысла изучать подробно, но SQLite действительно лайт

пользуюсь парой тройкой запросов - в DB Browser (SQLite) создал тестовую БД в 2 клика и там же есть вкладка SQL где можете создать и проверить запрос

Спасибо, буду смотреть. Открывать БД со стороны удобно.

 

После обновления MT4Orders и Virtual стал доступен снепшот-механиз работы с реальным торговым окружением. Нужно это было для ускорения большого количества ТС, работающих на одном Терминале. Или когда много ТС в одном советнике. В общем, когда много ордеров, каждый из которых принадлежит какой-то из ТС.


Сам механизм и сравнение производительности ДО/ПОСЛЕ его применения можно увидеть в следующем скрипте.

// Демонстрация влияния на производительность снепшот-механизма.
#property script_show_inputs

// #define MT4ORDERS_BENCHMARK_MINTIME 100 // Минимальное время сратабывания Алерта-производительности.
#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006
#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

#define VIRTUAL_SNAPSHOT // Снепшот-функционал. В MT5 требует подключенной MT4Orders.mqh
#include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/ru/code/22577

#include <fxsaber\Benchmark.mqh> // https://c.mql5.com/3/332/Benchmark.mqh
#define _B2(A) _BV(A, 1)

input int inAmount = 50; // Количество ТС

void DeleteAll( const int Type = OP_BUYLIMIT )
{
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() == Type) && (OrderSymbol() == _Symbol))
      OrderDelete(OrderTicket());
}

void CreateAll( const int Amount )
{
  for (int i = 1; i <= Amount; i++)
    OrderSend(_Symbol, OP_BUYLIMIT, 0.1, Ask - 1000 * _Point, 0, 0, 0, (string)i, i);  
}

void OnStart()
{
  CreateAll(inAmount); // Симулируем наличие многих ТС.
  
  Print("inAmount = " + (string)inAmount);
/*
  // Замеряем симуляцию работы многих ТС без снепшота.
  Print("\nWithout snapshot + MT5-style");
  _B2(Print(CalcMT5(inAmount)));
  _B2(Print(CalcMT5(inAmount)));
  _B2(Print(CalcMT5(inAmount)));
*/        
  // Замеряем симуляцию работы многих ТС без снепшота.
  Print("\nWithout snapshot + MT4-style");
  _B2(Print(Calc(inAmount)));
  _B2(Print(Calc(inAmount)));
  _B2(Print(Calc(inAmount)));

  // Замеряем симуляцию работы многих ТС со снепшотом.
  VIRTUAL::Snapshot(); // Создали снепшот реального торгового окружения.
  Print("\nWith snapshot + MT4-style");
  _B2(Print(Calc(inAmount)));
  _B2(Print(Calc(inAmount)));
  _B2(Print(Calc(inAmount)));
  
  DeleteAll(); // Подчистили за собой
}

// Симуляция работы с большим количеством независимых ООП-торговых систем в одном советнике.
int Calc( const int Amount )
{
  int Res = 0;
  
  for (int i = 1; i <= Amount; i++)
    if (OrderScan(_Symbol, OP_BUYLIMIT, i)) // Выбрали ордерное окружение своей ТС.
      Res += Stat();                        // Работаем с ним.
      
  return(Res);
}

int Stat() { return((int)OrderOpenTime()); }

// Находит ордер с заданными параметрами.
bool OrderScan( const string Symb, const int Type, const MAGIC_TYPE Magic = -1 )
{
  bool Res = false;
  
  for (int i = OrdersTotal() - 1; (i >= 0) && !Res; i--)
    Res = (OrderSelect(i, SELECT_BY_POS) && (OrderType() == Type) &&
          ((Magic == -1) || (OrderMagicNumber() == Magic)) && (OrderSymbol() == Symb));
          
  return(Res);  
}

Результат.

        inAmount = 50
        
        Without snapshot + MT5-style
        -1556707314
        Alert: Time[Test6.mq5 437: Print(CalcMT5(inAmount))] = 198 mсs.
        -1556707314
        Alert: Time[Test6.mq5 438: Print(CalcMT5(inAmount))] = 191 mсs.
        -1556707314
        Alert: Time[Test6.mq5 439: Print(CalcMT5(inAmount))] = 190 mсs.
        
        Without snapshot + MT4-style
        -1556707314
        Alert: Time[Test6.mq5 443: Print(Calc(inAmount))] = 8010 mсs.
        -1556707314
        Alert: Time[Test6.mq5 444: Print(Calc(inAmount))] = 8298 mсs.
        -1556707314
        Alert: Time[Test6.mq5 445: Print(Calc(inAmount))] = 9947 mсs.
        
        With snapshot + MT4-style
        -1556707314
        Alert: Time[Test6.mq5 450: Print(Calc(inAmount))] = 69 mсs.
        -1556707314
        Alert: Time[Test6.mq5 451: Print(Calc(inAmount))] = 67 mсs.
        -1556707314
        Alert: Time[Test6.mq5 452: Print(Calc(inAmount))] = 67 mсs.

На данных настройках снепшот дал ускорение в 120 раз в MT4-style. Также снепшот превзошел в три раза скорость чистого MQL5. Например, в данном случае снепшот в три раза быстрее торговой СБ Trade\Trade.mqh.


Что касается применения данного функционала в MT4, то он работает, но не дает ускорения (где-то в 1.5 раза медленнее штатного). Скорее всего, по причине того, что MQL4-компилятор дает слабый по производительности код.


Работу с MT5-историей не проверял, т.к. очевидно, что там будет еще сильнее разница.

Библиотеки: MT4Orders
Библиотеки: MT4Orders
  • 2020.09.24
  • www.mql5.com
MT4Orders: Автор: fxsaber...
 
fxsaber:

После обновления MT4Orders и Virtual стал доступен снепшот-механиз работы с реальным торговым окружением. Нужно это было для ускорения большого количества ТС, работающих на одном Терминале. Или когда много ТС в одном советнике. В общем, когда много ордеров, каждый из которых принадлежит какой-то из ТС.

На тормозных VPS данный снепшот-механизм может долго выполняться. Для примера такой советник.
#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279

#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006

#define VIRTUAL_SNAPSHOT_REFRESHTIME 1000 // Время жизни снепшота для обновления. В MT5 требует подключенной MT4Orders.mqh
#define VIRTUAL_SNAPSHOT_WITHOUT_HISTORY // Отказ от снепшота истории для повышения производительности
#include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/ru/code/22577

void OnStart()
{
  _BV(
  for (int i = 0; i < 100000; i++)
    VIRTUAL::Snapshot(); // 100 000 раз берем снепшот.
      , 1)
}


На нормальной машине такой результат.

        Alert: Time[Test9.mq5 101: for(inti=0;i<100000;i++)VIRTUAL::Snapshot();] = 3519 mсs.


На тормозном VPS.

        Alert: Time[Test6.mq5 57: for(inti=0;i<100000;i++)VIRTUAL::Snapshot();] = 1861946 mсs.


Результат очень плачевный.


Решение.

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

#include <fxsaber\Benchmark\Microseconds.mqh> // https://www.mql5.com/ru/code/31279

Этот mqh анализирует наличие тормозов на машине и делает определенную замену.


Результат на нормальной машине.

        Alert: Time[Test9.mq5 101: for(inti=0;i<100000;i++)VIRTUAL::Snapshot();] = 3759 mсs.


Результат на тормозном VPS.

        Alert: Microseconds.mqh: FreezeVPS - https://www.mql5.com/ru/forum/342090/page40#comment_18579094
        Alert: Microseconds.mqh: AvgInterval = 940 mcs. Replacement: GetMicrosecondCount -> winmm::timeGetTime.
        Alert: Time[Test6.mq5 57: for(inti=0;i<100000;i++)VIRTUAL::Snapshot();] = 4000 mсs.


Обошли тормоза!


ЗЫ Какой-то сверх-тонкий нюанс.