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

 
Forester #:

Поставьте пожалуйста

#define MAX_ORDERS 1000
100 тоже не хватило. Памяти немного возьмет. При апдейтах не хотелось бы каждый раз искать и править.

Сотни живых ордеров в Тестере мало?

---------------------------
Тестер свопы расчитывает по умолчанию, думаю надо и в виртуальном тестере сделать так же (видимо при переносе ордера в историю). А может лучше в активых ордерах в начале новых суток, чтобы текущая эквити была точнее (добавив в ее расчет свопы). Код станет без лишних вставок. А то кто-то так и не разберется, что своп надо отдельно считать.
Сейчас делаю так в OnTester.  
for (int v = 0 ; v <= VIRTUAL::Total(); v++){
      if (VIRTUAL::SelectByIndex(v)){
         VIRTUAL::CalcSwaps();


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

------------------------------
Тестер MT отказывает в части сделок из за Market closed
Проверил спецификацию и правда на Alp... с 23:55 до 00:15 торговля закрыта.
Хорошо бы и виртуальному тестеру отклонять сделки по этому времени, для более точного соответствия.

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

И заодно и в MT4Orders, добавить проверку, чтобы и в тестерах и в реале не пытаться торговать при закрытой торговле.
Тут код с примером как сделать https://www.mql5.com/ru/forum/390928#comment_45855346
                                  #    open date               T  Prof  Pip Comis Swap
2022.05.30 23:59:30   660 2022.05.30 23:55:00 0 -0.15 -15 -0.04   0.0 должен быть отклонен по Market closed
2022.05.30 23:59:30   661 2022.05.30 23:55:00 1 -0.15 -15 -0.04   0.0 должен быть отклонен по Market closed

Сделано.

--------------------------------
Давно не интересовался расчетом комиссии. Никто так и не придумал, как автоматически ее определять? (Была идея сделать одну тестовую сделку и из нее взять комиссию)

Так и делают многие через Тестер. На реале обычно по торговому символу уже есть несколько сделок. Поэтому комиссию можно определять по последней.

П.С. при сравнении получил полное соответствие по суммам, кроме отклоненных по Market closed и 2 сделки в виртуальном имели большее проскальзывание ТП, чем в реальном. Остальные 600+ сделок точно совпали.

Надо посмотреть этот случай. Звучит, как ошибка MT5-тестера.

 
fxsaber #:

Сотни живых ордеров в Тестере мало?

Мало. С 1000 за год проходит без проблем. А с 100 и за неделю вылетает. Тут выше тоже говорили, что мало.  Себе я сделал комментарий, если что подправлю.

fxsaber #:
Надо посмотреть этот случай. Звучит, как ошибка MT5-тестера.

Добавил в распечатку время закрытия. Виртуал закрыл их в 00:05 при закрытом рынке. MQ тестер закрыл позже в разрешенное время. В общем нужен контроль открытости рынка.
Применил

#define MT4ORDERS_AUTO_VALIDATION // Торговые приказы отправляются только в случае успешной проверки на корректность

Ничего не изменилось - в виртуальном тестере осталось открытие и закрытие при закрытом рынке.

Виртуал

№   open time           open time ms  close time          close time ms T OpPrice ClPrice Prof Pt  Comis Swap  Comment
179 2022.05.27 19:35:03 1653680103606 2022.05.30 00:05:00 1653869100130 0 1.07148 1.07359 2.11 211 -0.04 -0.07
180 2022.05.27 20:35:00 1653683700178 2022.05.30 00:05:00 1653869100130 0 1.07147 1.07359 2.12 212 -0.04 -0.07
...
266 2022.05.30 00:10:00 1653869400127 2022.05.30 05:15:33 1653887733996 0 1.07346 1.07546 2.00 200 -0.04 0.0


Реал (закрылись позже, потому и проскальзывания ТП отличаются)

№   open time           open time ms  close time          close time ms T OpPrice ClPrice Prof Pt  Comis Swap  Comment
179 2022.05.27 20:35:00 1653683700178 2022.05.30 00:57:38 1653872258901 0 1.07147 1.07347 2.00 200 -0.04 -0.07 tp 1.07347
180 2022.05.27 19:35:03 1653680103606 2022.05.30 01:01:36 1653872496947 0 1.07148 1.07348 2.00 200 -0.04 -0.07 tp 1.07348

 
Forester #:

Ничего не изменилось - в виртуальном тестере осталось открытие и закрытие при закрытом рынке.

Virtual и не должен был изменяться. Это только для MT4Orders - обходит попытки торговли вне сессии.

 

Интересно, что при окончании теста MQ тестер закрывает сделки от новых к давним,  а виртуальный наоборот. Думаю сначала надо самые старые закрывать как у вас (вроде на биржах сначала исполняют ранние ордера).
Не критично, просто особенность.
MQ tester

455 2022.05.30 13:35:00 1653917700000 2022.05.30 19:59:51 1653940791989 0 1.07663 1.07863 2.00 200 -0.04 0.0 tp 1.07863
456 2022.05.30 23:50:00 1653954600100 2022.05.30 23:59:30 1653955170199 1 1.07787 1.07810 -0.23 -23 -0.04 0.0 end of test
457 2022.05.30 23:50:00 1653954600100 2022.05.30 23:59:30 1653955170199 0 1.07800 1.07794 -0.06 -6 -0.04 0.0 end of test
...
657 2022.05.30 04:55:03 1653886503106 2022.05.30 23:59:30 1653955170199 1 1.07490 1.07810 -3.20 -320 -0.04 0.0 end of test

Виртуальный тестер.

457 2022.05.30 13:35:00 1653917700000 2022.05.30 19:59:51 1653940791989 0 1.07663 1.07863 2.00 200 -0.04 0.0
458 2022.05.30 04:55:03 1653886503106 2022.05.30 23:59:30 1653955170199 1 1.07490 1.07810 -3.20 -320 -0.04 0.0 end of test
459 2022.05.30 05:15:01 1653887701418 2022.05.30 23:59:30 1653955170199 1 1.07529 1.07810 -2.81 -281 -0.04 0.0 end of test
...
661 2022.05.30 23:55:00 1653954900140 2022.05.30 23:59:30 1653955170199 1 1.07795 1.07810 -0.15 -15 -0.04 0.0 end of test

 
Forester #:

нужен контроль открытости рынка.

Тики, что вне торговой сессии, просто не пробрасывайте в Virtual. И будет полное совпадение.

#define DAY (24 * 3600)
#define WEEK 7

ENUM_DAY_OF_WEEK TimeDayOfWeek( const datetime time )
{
  return((ENUM_DAY_OF_WEEK)((time / DAY + THURSDAY) % WEEK));
}

bool SessionTrade( const string Symb, const MqlTick &Tick )
{
  datetime TimeNow = Tick.time;

  const ENUM_DAY_OF_WEEK DayOfWeek = TimeDayOfWeek(TimeNow);

  TimeNow %= DAY;

  bool Res = false;
  datetime From, To;

  for (int i = 0; (!Res) && ::SymbolInfoSessionTrade(Symb, DayOfWeek, i, From, To); i++)
    Res = ((From <= TimeNow) && (TimeNow < To));

  return(Res);
}
 
fxsaber #:

Тики, что вне торговой сессии, просто не пробрасывайте в Virtual. И будет полное совпадение.

TimeNow %= DAY;

Красиво сделано! Спасибо!

Похоже что даже перевод на зимнее/летнее время и разные часовые пояса не будут мешать.

UPD:

проверил, теперь все точно совпадает.

 
fxsaber #:

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

На мой взгляд, хоть какие-то свопы лучше, чем их отсутствие.

Если свопы расчитывать по 1 только при переносе их в историю, то производительность будет такая же, как при их расчете в конце работы. А через ifdef можно выключать и производительность совсем не изменится.

Мне их расчет в конце теста не подходит, надо именно в процессе. Добавил в HistoryOrders.mqh в ф-ю AddHistoryOrder такие строки

  void AddHistoryOrder( const ORDER_BASE &Order )
  {
    if (this.AmountHistoryOrders == this.ReserveHistoryOrders)
      this.ReserveHistoryOrders = ::ArrayResize(this.HistoryOrders, this.ReserveHistoryOrders + RESERVE_HISTORY_ORDERS);

    ORDER OrderTmp = Order;

    if (OrderTmp.IsNotNull() && this.AmountHistoryOrders < this.ReserveHistoryOrders)
    {
      OrderTmp.ToHistory();

      this.HistoryOrders[this.AmountHistoryOrders++] = OrderTmp;

      this.FlagChange = true;
      
      #ifdef ORDER_SWAP
         datetime RolloverTime=((datetime)ORDER_SWAP % 86400);//86400 sec in day
         double SwapShort=::SymbolInfoDouble(OrderTmp.GetSymbol(), SYMBOL_SWAP_SHORT), SwapLong=::SymbolInfoDouble(OrderTmp.GetSymbol(), SYMBOL_SWAP_LONG);
         int Rollover3Days = (int)::SymbolInfoInteger(OrderTmp.GetSymbol(), SYMBOL_SWAP_ROLLOVER3DAYS);
         double Swap = this.HistoryOrders[this.AmountHistoryOrders-1].SetSwap(SwapShort, SwapLong, RolloverTime, Rollover3Days);
         this.Balance += Swap;// не уверен - нужно ли
      #endif
    }

    return;
  }

А в Orders.mqh сразу после вызова AddHistoryOrder корректирую баланс на своп

        this.AddHistoryOrder(this.Orders[i]);
        
        #ifdef ORDER_SWAP
          this.Balance += this.HistoryOrders[this.AmountHistoryOrders-1].GetSwap();
        #endif

В комментарии в шапке добавил
//#define ORDER_SWAP 0 // calc swap with rollower time
Через ORDER_SWAP 0 включаю/выключаю расчет свопов и задаю время ролловера = 0 или любое нужное.

Сравнил распечатки с расчетом свопа в конце теста и с тестером MQ - абсолютное совпадение всех 3-х вариантов и по сделкам и по итоговому балансу.

AddHistoryOrder вызывается еще при AddOrder() и в для снэпшотов. Т.е. коррккцию баланса надо добавить и в них. Еще в OrderDeposit(), но свопы будут=0, можно не считать.

Будет здорово, если вы тоже внесете такие изменения в библиотеку.

 
Forester #:

Если свопы расчитывать по 1 только при переносе их в историю

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

Подумаю над этим компромиссным решением. Спасибо.

 
fxsaber #:

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

Подумаю над этим компромиссным решением. Спасибо.

Только наверное не совсем верно добавлять своп к балансу, т.к. иногда ордер не будет добавляться в историю и получится добавление свопа от предыдущей сделки.
void AddHistoryOrder( const ORDER_BASE &Order )
....
if (OrderTmp.IsNotNull() && this.AmountHistoryOrders < this.ReserveHistoryOrders){...}

Т.е. если ордер нулевой. Второе условие можно удалить, т.к. решено выше увеличением массива.

Как то надо проверять, видимо тоже через IsNotNull(). Или прямо из AddHistoryOrder () изменить баланс вызывающей функции, может сделать через return swap;?

        #ifdef ORDER_SWAP
          this.Balance += (this.Orders[i].IsNotNull() ? this.HistoryOrders[this.AmountHistoryOrders-1].GetSwap() : 0.0);
        #endif
 
Forester #:
Только наверное не совсем верно
Не помню свои коды. Во время просмотра придет решение.
Причина обращения: