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

 

Если параллельно используются несколько виртуальных окружений, то можно существенно экономить на выборе окружения, если вместо SelectByHandle использовать SelectByIndex.

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

struct VIRTUAL_SYSTEM
{  
public:
  const int Handle;
  
  VIRTUAL_SYSTEM( void ) : Handle(VIRTUAL::Create()), Index(VIRTUAL::Total())
  {
  }
  
  bool SelectMe()
  {
//    return(VIRTUAL::SelectByHandle(this.Handle)); // Если много окружений - небыстро.
    return(VIRTUAL::SelectByIndex(this.Index, this.Handle)); // Если много окружений - быстро.
  }

private:
  int Index; // https://www.mql5.com/ru/forum/170952/page227#comment_43069017  
};

double GetSumProfit( VIRTUAL_SYSTEM &Virtuals[] )
{
  double Sum = 0;
  
  for (int i = ArraySize(Virtuals) - 1; i >= 0; i--)
    if (Virtuals[i].SelectMe())
      Sum += TesterStatistics(STAT_PROFIT);
      
  return(Sum);
}

VIRTUAL_SYSTEM Virtuals1[1000]; // Много виртуальных окружений.
VIRTUAL_SYSTEM Virtuals2[2000]; // Много виртуальных окружений.

#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279
#define _C(A) _B(A, 1)

void OnStart()
{
  _C(GetSumProfit(Virtuals1));
  _C(GetSumProfit(Virtuals2));
}


SelectByHandle:

GetSumProfit(Virtuals1)] = 4368 mcs.
GetSumProfit(Virtuals2)] = 78578 mcs.


SelectByIndex:

GetSumProfit(Virtuals1)] = 235 mcs.
GetSumProfit(Virtuals2)] = 503 mcs.
 
Rorschach #:
Код к скрину из параллельной ветки. В fn0() торговая система и вывод баланса в виде индикатора. Как мне объединить это и это? Торговая система будет в отдельном файле. То есть нужно что то вроде AccountInfoDouble(ACCOUNT_BALANCE).

Нужно торговую систему переписать в классический вид: OnTick в стиле MT4. Тогда легко Vitual подключить и получить величину баланса на любой момент.

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

 

Вот этим действием Вы пробросили в виртуальное окружение 9000 сгенерированных тиков.

На каждом проброшеном тике внутри сформированного виртуального окружения был вызван OnTick.

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

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

Rorschach, 2023.01.17 21:17

void OnTick()
  {
//---
   double ma[]; CopyBuffer(h,0,0,1,ma); // Работа с таймсерией реального торгового окружения. Т.е. это значение 9000 раз не менялось.
   double pr=SymbolInfoDouble(_Symbol, SYMBOL_BID); // Вот это значение менялось, т.к. оно соответствует значению тика из 9000 проброшенных.
   if(PositionsTotal()==0) // Это всегда из реального окружения, т.к. не относится к MT4-Style.
     {if(pr-ma[0]> Dev) OrderSend(_Symbol,OP_BUY ,1,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0); // Это выражение могло выполниться до 9000 раз.
      if(pr-ma[0]<-Dev) OrderSend(_Symbol,OP_SELL,1,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0);
     }
   else
     {
      if(fabs(pr-ma[0])<0.001 && OrderSelect(0,SELECT_BY_POS)) OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(),0);
     }
  }

Мы видим, что ma[0] (и PositionsTotal) ни разу за 9000 вызовов не изменилось, т.к. бралось из реального окружения - каждый раз изнутри одного вызова fn0(). Т.е. формировалось до 9000 открытых позиций, когда количество одновременно открытых ордеров  ограничено (можете поменять).

#define MAX_ORDERS 100


Далее в каждом вызове OnTimer создаете новое виртуальное торговое окружение.

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


Напишите советник без использования таймсерий.

 

Спасибо, немного накостылил и заработало


Файлы:
 
fxsaber #:

Если параллельно используются несколько виртуальных окружений, то можно существенно экономить на выборе окружения, если вместо SelectByHandle использовать SelectByIndex.

Добавлены указатели на виртуальные окружения. Это предоставляет наибольшую гибкость/удобство использования при работе одновременно с несколькими торговыми окружениями. И скорость переключения.


Производительность.

Замер производился таким скриптом.

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

struct VIRTUAL_SYSTEM
{  
public:
  const int Handle;
  
  VIRTUAL_SYSTEM( void ) : Handle(VIRTUAL::Create()),
                           Index(VIRTUAL::Total()),
                           VirtualPointer(VIRTUAL::GetHandle())
  {
  }
  
  bool SelectMe()
  {
//    return(VIRTUAL::SelectByHandle(this.Handle)); // Если много окружений - медленно
//    return(VIRTUAL::SelectByIndex(this.Index, this.Handle)); // Если много окружений - быстро.
    return(this.VirtualPointer.Select()); // Если много окружений - очень быстро.
  }

private:
  // https://www.mql5.com/ru/forum/170952/page227#comment_43069017
  int Index;
  const VIRTUAL_POINTER VirtualPointer;
};

double GetSumProfit( VIRTUAL_SYSTEM &Virtuals[] )
{
  double Sum = 0;
  
  for (int i = ArraySize(Virtuals) - 1; i >= 0; i--)
    if (Virtuals[i].SelectMe())
      Sum += TesterStatistics(STAT_PROFIT);
      
  return(Sum);
}

VIRTUAL_SYSTEM Virtuals1[1000]; // Много виртуальных окружений.
VIRTUAL_SYSTEM Virtuals2[2000]; // Много виртуальных окружений.

#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279
#define _C(A) _B(A, 1)

void OnStart()
{
  _C(GetSumProfit(Virtuals1));
  _C(GetSumProfit(Virtuals2));
}


Результаты замеров на обеих платформах.

Method MQL4_LengthTime MQL5_LengthTime
VIRTUAL::SelectByHandle 9728  mcs
97326  mcs
4612  mcs
77569  mcs
VIRTUAL::SelectByIndex
389  mcs
869  mcs
247  mcs
525  mcs
VirtualPointer.Select() 19  mcs
36  mcs

8 mcs
13 mcs

Полностью перешел на указатели.

 
fxsaber #:

Добавлены указатели на виртуальные окружения. Это предоставляет наибольшую гибкость/удобство использования при работе одновременно с несколькими торговыми окружениями.

Пример работы с несколькими виртуальными окружениями.

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

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

string Example()
{
  string Str = NULL;
  VIRTUAL_POINTER Pointers[10];
  
  // Создали виртуальные окружения и привязали их к указателям.
  for (int i = 1; i < 10; i++)
  {
    Pointers[i] = VIRTUAL::Create(i * 123.45 ); // Создали окружение и привязали указатель.
    
    // Вошли в него, выполнили SetID и вышли.
    _VP(Pointers[i], VIRTUAL::SetID("Virtual_" + AccountInfoString(ACCOUNT_SERVER) + "_" + (string)VIRTUAL::GetHandle()));
  }
    
  _VSP(Pointers[5]) // Вошли в "пятое" виртуальное окружение.

  VIRTUAL::NewTick();

  // Открыли позицию в "пятом" окружении.
  if (OrderSelect(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0, VIRTUAL::GetID() + "_Example"), SELECT_BY_TICKET))
  {
    _VSP(Pointers[3]) // Вошли в "третье" виртуальное окружение.

    VIRTUAL::NewTick();
    
    // Выставили лимитник в "третьем" окружении.
    OrderSend(_Symbol, OP_BUYLIMIT, 1, Ask - 1000 * _Point, 0, 0, 0, VIRTUAL::GetID() + "_Example");
    
    Str += "\n\n" + VIRTUAL::GetID() + "\n" + VIRTUAL::ToString(); // Собрали данные "третьего" окружения.
  } // Вышли из "третьего" виртуального окружения, оказавшись в предыдущем - "пятом".
  
  // Вошли в "восьмое" окружение, собрали данные и вышли из него, попав в предыдущее - "пятое".
  Str += "\n\n" + _VP(Pointers[8], VIRTUAL::GetID() + "\n" + VIRTUAL::ToString(1));

  Str += "\n\n" + VIRTUAL::GetID() + "\n" + VIRTUAL::ToString(); // Собрали данные "пятого" окружения.
  
  return(Str);
} // Вышли из "пятого" окружения, оказавшись в предыдущем.

#define TOSTRING(A) #A + " = " + (string)(A) + " "

void OnStart()
{
  Print(Example());
  
  // Сколько всего окружений и где сейчас находимся.
  Print("\n\n" + TOSTRING(VIRTUAL::Total()) + TOSTRING(VIRTUAL::GetHandle()));
}


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

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

// "Третье" виртуальное окружение.
Virtual_RannForex-Server_3
 time = 2023.01.26 10:42:31.347 bid = 1.09190 ask = 1.09191 last = 0.00000 volume = 0 774 TICK_FLAG_BID TICK_FLAG_ASK FLAG_UNKNOWN (768)

// Живой лимитник "третьего" окружения.
#11 2023.01.26 10:42:31.347 buy limit 1.0 EURUSD 1.08191 0.00000 0.00000 1.09191 0.00 0.00 0.00 Virtual_RannForex-Server_3_Example 0 - 00:00:00

Balance = 370.35, Equity = 370.35, Profit = 0.00, 2023.01.26 - 2023.01.26 10:42:31


// "Восьмое" виртуальное окружение.
Virtual_RannForex-Server_8
 time = 1970.01.01 00:00:00.000 bid = 0.00000 ask = 0.00000 last = 0.00000 volume = 0 2048 FLAG_UNKNOWN (2048)

Balance = 987.60, Equity = 987.60, Profit = 0.00, 2023.01.26 - 1970.01.01 00:00:00
#8 2023.01.26 10:42:31.000 balance 0.0 0 0 0 2023.01.26 10:42:31.000 0 0.00 0.00 987.60 0 - 00:00:00 // Балансовая операция "восьмого" окружения.

// "Пятое" виртуальное окружение.
Virtual_RannForex-Server_5
 time = 2023.01.26 10:42:31.347 bid = 1.09190 ask = 1.09191 last = 0.00000 volume = 0 1286 TICK_FLAG_BID TICK_FLAG_ASK FLAG_UNKNOWN (1280)

// Открытая позиция "пятого" окружения.
#10 2023.01.26 10:42:31.347 buy 1.0 EURUSD 1.09191 0.00000 0.00000 1.09190 0.00 0.00 -1.00 Virtual_RannForex-Server_5_Example 0: -1 (-1) - 00:00:00

Balance = 617.25, Equity = 616.25, Profit = -1.00, 2023.01.26 - 2023.01.26 10:42:31

// Всего девять виртуальных окружений, находимся в реальном окружении.
VIRTUAL::Total() = 9 VIRTUAL::GetHandle() = 0 
 
fxsaber #:

Пример работы с несколькими виртуальными окружениями.

Одно из боевых применений.

  • В советнике находится пять ТС.
  • Каждая ТС имеет три виртуальных окружения: V1 - торговля без фильтра, V2 - наложение фильтра на V1 и синхронизация с реальным окружением для открытия позиций, V3 - торговля без каких-либо остановок и  синхронизация с реальным окружением для закрытия позиций.

Итого активны 15 виртуальных окружений в советнике. Поэтому максимально быстрая и удобная работа необходима.


В некоторых сценариях использования в Терминале могут постоянно работать несколько сотен виртуальных окружений, временно - тысячи.

 
Обновлен: 2022.06.20 18:12

Сама библиотека не была обновлена?

 
traveller00 #:

Сама библиотека не была обновлена?

Обновлены Orders.mqh и Virtual.mqh.

 

Пояснение по сохранению OrderSelect-выбора окружением.

  1. В текущем окружении сделали OrderSelect. Например, там возвращается какой-то OrderTicket.
  2. Заходили в другие окружения, где тоже делали OrderSelect.
  3. Вернулись в окружение из п.1. Так вот выбранный ордер в п.1 остается выбранным. Например, OrderTicket совпадет с тем, что в п.1.

Пример, показывающий такое поведение.

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

bool PrintOrder() { OrderPrint(); return(true); }

// Открывает и выбирает позицию.
bool OpenPosition( const string Symb )
{
  bool Res = false;
  MqlTick Tick;
  
  if (_V(0, SymbolInfoTick(Symb, Tick))) // Взяли реальный тик.
  {
    if (VIRTUAL::GetHandle()) // Если виртуальное окружение,
      VIRTUAL::NewTick(Tick); // пробросили в него тик.
      
    // Открыли и выбрали позицию.
    Res = OrderSelect(OrderSend(Symb, OP_SELL, 1, Tick.bid, 0, 0, 0, "Handle = " + (string)VIRTUAL::GetHandle()), SELECT_BY_TICKET);
  }

  return(Res);  
}

void OnStart()
{
  // Создали виртуальные окружения.
  VIRTUAL::Create();
  VIRTUAL::Create();    

  // Во всех окружениях открыли и выбрали позицию.
  for (int i = VIRTUAL::Total(); i >= 0; i--)
    _VI(i, OpenPosition(SymbolName(i, true)));
    
  // Без выбора позиций пробуем распечатать ранее выбранные позиции в каждом окружении.
  for (int i = VIRTUAL::Total(); i >= 0; i--)
    _VI(i, PrintOrder());    
}


Результат.

#3 2022.12.09 23:59:59.960 sell 1.0 LTCUSD 17113.10500 0.00000 0.00000 17115.81700 0.00 0.00 -271200.00 Handle = 2 0: -271200 (-271200) - 00:00:00
#4 2022.12.09 23:59:43.814 sell 1.0 LTCUSD 76.17000 0.00000 0.00000 76.22000 0.00 0.00 -5000.00 Handle = 1 0: -5000 (-5000) - 00:00:00
#50357375298 2023.02.16 11:10:00.926 sell 1.00 GBPNOK 12.27017 0.00000 0.00000 12.27463 0.00 0.00 -40.92 Handle = 0 0

Видим, что в каждом окружении выбор соответствует последнему OrderSelect, сделанному в соответствующем окружении.


Грубо говоря, OrderSelect одного окружения не влияет на ранее выбранный ордер из другого окружения.

Если совсем кратко, все работает правильно.