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

 
Forester #:

в тестере  не получается получить эти финальные сделки.

Запустите этот советник на интервале в один день (много сделок), включив в исходник Report.


 
fxsaber #:

Запустите этот советник на интервале в один день (много сделок), включив в исходник Report.


Скопировал отсюда https://www.mql5.com/ru/code/viewcode/18801/288604/report.mq5

При компиляции ошибка:
'DiapasonToString' - undeclared identifier    Report.mqh    3440    76
А там

#ifdef // __MQL5__
  static string DiapasonToString( const string Name )

Если убрать комментарий

#ifdef  __MQL5__

то компилируется.


Да - ваш OnTester был вызван. Буду разбираться, почему в моем советнике он не вызывается.

 
Forester #:

Скопировал отсюда https://www.mql5.com/ru/code/viewcode/18801/288604/report.mq5

При компиляции ошибка:
'DiapasonToString' - undeclared identifier    Report.mqh    3440    76

Обратной связи нет, не всегда есть понимание, что залито в КБ криво. Обновил.
 
fxsaber #:
Обратной связи нет, не всегда есть понимание, что залито в КБ криво. Обновил.

Спасибо.

По округлению комиссий на каждую сделку. У вас сделано без округления this.Commission = this.Lots * (ORDER_COMMISSION);, но как видно из распечаток - в тестере MQ округление идет вверх.
Тестер MQ. Лот=1

N Ticket OpenTime Type Lots Symbol OpenPrice StopLoss TakeProfit CloseTime ClosePrice Commission Swap Profit Comment Pips Slippage MagicNumber LengthTime Balance
1 1 2022.05.23 00:00:00.000 balance








+1000000.00




1000000.00
2 2 2022.05.23 00:15:00.518 buy 1.00 (211 265.00) EURUSD 1.05654

1.05606

2022.05.23 00:15:07.480 1.05611 -3.41 (-3.41)
-43.00 (-49.00)
-43 (-49) +1, +5 1 00:00:06.962 999953.59

Тестер MQ. Лот=0,01

N Ticket OpenTime Type Lots Symbol OpenPrice StopLoss TakeProfit CloseTime ClosePrice Commission Swap Profit Comment Pips Slippage MagicNumber LengthTime Balance
1 1 2022.05.23 00:00:00.000 balance








+1000000.00




1000000.00
2 2(1)/5 2022.05.23 00:15:00.518 buy 0.01 (2 112.65) EURUSD 1.05654

1.05606

2022.05.23 00:15:07.480 1.05611 -0.04 (-4.00)
-0.43 (-0.49) tp 1.05606 -43 (-49) +1, +5 1 00:00:06.962 999999.53

Если бы округляло правильно, то было бы -0,03, значит округляют вверх чем то вроде

double CeilDouble(double d, double Points){return ceil(d / Points) * Points;}// ceil(0.034/0.01)*0.01 = 0.04

где Points=1.0 / pow(10.0, DigitsCurrency); лучше 1 раз посчитать, чтобы потом не возводить степени тысячи раз. Или из таблички брать 0.1, 0,01 ....

*****************************

Еще посмотрел cвопы:
при лоте=1

76490 152960(1)/152986 2022.05.23 23:54:43.620 buy 1.00 (213 789.00) EURUSD 1.06907

1.06878

2022.05.24 00:15:49.581 1.06882 -3.42 (-3.42) -7.71 (-7.71) -25.00 (-30.00) tp 1.06878 -25 (-30) +1, +4 10 00:21:05.961 500316.23
76491 152983(1)/152990 2022.05.23 23:54:51.632 sell 1.00 (213 852.00) EURUSD 1.06914

1.06938

2022.05.24 00:15:49.701 1.06938 -3.42 (-3.42) 3.09 (3.09) -24.00 tp 1.06938 -24
1 00:20:58.069 500291.90

Свопы при лоте=0,01

76490 152960(1)/152986 2022.05.23 23:54:43.620 buy 0.01 (2 137.89) EURUSD 1.06907

1.06878

2022.05.24 00:15:49.581 1.06882 -0.04 (-4.00) -0.08 (-8.00) -0.25 (-0.30) tp 1.06878 -25 (-30) +1, +4 10 00:21:05.961 994548.98
76491 152983(1)/152990 2022.05.23 23:54:51.632 sell 0.01 (2 138.52) EURUSD 1.06914

1.06938

2022.05.24 00:15:49.701 1.06938 -0.04 (-4.00) 0.03 (3.00) -0.24 tp 1.06938 -24
1 00:20:58.069 994548.73

Матматически правильно и оба в пользу ДЦ. В вашем тестере так же - через NormalizeDouble .
Еще 2 символа проверил - у обоих математически правильно (например для NZDUSD  -0,0148 округляет к -0,01, т.е. в убыток ДЦ, а -0,0175 к -0,02), т.е. свопам в тестере MQ применено NormalizeDouble (). Но это тестер, а как в реальности на реальном счете - надо кому-то проверить. Возможно тут недоработка тестера, если ДЦ все-таки всегда в прибыль себе округляют.

37495 74974(1)/74995 2022.05.23 23:51:50.294 sell 0.01 (1 293.29) NZDUSD 0.64655

0.64680

2022.05.24 00:16:06.560 0.64674 -0.02 (-2.00) -0.01 (-1.00) -0.19 (-0.25) tp 0.64680 -19 (-25) 0, +6 4 00:24:16.266 995894.69
37496 73368(1)/75000 2022.05.23 22:36:04.186 buy 0.01 (1 292.44) NZDUSD 0.64638

0.64603

2022.05.24 00:16:07.007 0.64606 -0.02 (-2.00) -0.02 (-2.00) -0.32 (-0.36) tp 0.64603 -32 (-36) +1, +3 7 01:40:02.821 995894.33

 
Forester #:

По округлению комиссий на каждую сделку. У вас сделано через NormalizeDouble(d, dig), судя по справке он округлит математически, но как видно из распечаток округление идет вверх.

Еще 2 символа проверил - у обоих математически правильно (например для NZDUSD  -0,0148 округляет к -0,01, т.е. в убыток ДЦ, а -0,0175 к -0,02), т.е. свопам нужно NormalizeDouble (). Но это тестер, а как в реальности на реальном счете - надо кому-то проверить. Возможно тут недоработка тестера, если ДЦ все-таки всегда в прибыль себе округляют.

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

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

fxsaber, 2023.11.23 19:39

Сам тестирую в режиме по пипсам. Там свопов нет. И быстрее пашет.

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

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


Virtual совсем ничего не округляет, и так правильно. Report, конечно, показывать всю длину double не может, поэтому комиссию 0.1234 покажет, как 0.123, а не 0.12.


Попробуйте выставить одним OrderSend BuyLimit = Ask, TP = Bid. И увидите различия с тестером. Не эталон он, к сожалению.


ЗЫ  Когда говорил такое,

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

MQL5 Ордера истории

fxsaber, 2023.11.21 13:41

Никто на этом форуме не в состоянии это дописать до рабочего состояния.

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

 
Forester #:

Да - ваш OnTester был вызван. Буду разбираться, почему в моем советнике он не вызывается.

Разобрался с OnTester() .
1) В  вашем последнем примере используется #define VIRTUAL_TESTER в нем мой OnTester() не вызывается, а только ваш. Нашел почему: в конце вашего OnTester() надо вставить   OldOnTester2();

#ifndef BESTINTERVAL_ONTESTER

double OnTester()
{Print ("OnTester virtual");
  VIRTUAL::SelectByHandle(VirtualHandle);

#ifdef VIRTUAL_CLOSEALL_BYEND
  VIRTUAL::Stop();
#endif // VIRTUAL_CLOSEALL_BYEND
  OldOnTester2();  //     <<<<<<<<<<------------------------- надо вставить   OldOnTester2();
/* делать это в основном OnTester()
#ifdef VIRTUAL_ONTESTER_FORMULA
  return(VIRTUAL_ONTESTER_FORMULA);
#else // VIRTUAL_ONTESTER_FORMULA
  return(::AccountEquity());
#endif // VIRTUAL_ONTESTER_FORMULA
*/
}

#define OnTester OldOnTester2

#endif // BESTINTERVAL_ONTESTER

Результат

2023.11.26 13:34:03.334    2022.05.30 23:59:30   OnTester virtual
2023.11.26 13:34:03.334    2022.05.30 23:59:30   OnTester main

2) Я в своем коде подключаю виртуальный тестер, как в примере из КБ т.е. без #define VIRTUAL_TESTER и библиотечный OnTester() не запускается и не завершает открытые сделки в конце теста по VIRTUAL_CLOSEALL_BYEND. Видимо надо вызывать оба OnTester() независимо от VIRTUAL_TESTER

Перенес наверх от #ifdef VIRTUAL_TESTER в таком виде:

#ifndef BESTINTERVAL_ONTESTER
double OnTester(){
Print ("OnTester virtual");

  for (int v = 0 ; v <= VIRTUAL::Total(); v++){
#ifdef VIRTUAL_CLOSEALL_BYEND
      if (VIRTUAL::SelectByIndex(v)){
         VIRTUAL::NewTick(); VIRTUAL::Stop(); //последний тик для стопов // закрыть незавершенные сделки
      }
#endif // VIRTUAL_CLOSEALL_BYEND

  OldOnTester2();
/* делать это в основном OnTester()
#ifdef VIRTUAL_ONTESTER_FORMULA
  return(VIRTUAL_ONTESTER_FORMULA);
#else // VIRTUAL_ONTESTER_FORMULA
  return(::AccountEquity());
#endif // VIRTUAL_ONTESTER_FORMULA
*/

   }
   return 0.0;//заглушка, все нужное вернется из OldOnTester2()из цикла
}
#endif // BESTINTERVAL_ONTESTER

#define OnTester OldOnTester2

но не компилируется, т.к. не видит OldOnTester. Я с переименованием функций не знаком, тут наверное у вас лучше получится решить эту задачу.

 
Forester #:

1) В  вашем последнем примере используется #define VIRTUAL_TESTER в нем мой OnTester() не вызывается, а только ваш. Нашел почему: в конце вашего OnTester() надо вставить   OldOnTester2();

Этот макрос нужен, чтобы сходу добавить в советник возможность тестирования в виртуалке. Поэтому только свой OnTester без запуска чужого (который может быть и не задан даже).

2) Я в своем коде подключаю виртуальный тестер, как в примере из КБ т.е. без #define VIRTUAL_TESTER и библиотечный OnTester() не запускается и не завершает открытые сделки в конце теста по VIRTUAL_CLOSEALL_BYEND. Видимо надо вызывать оба OnTester() независимо от VIRTUAL_TESTER

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


В Вашем случае целесообразно

  1. В OnTick в начале прописать VIRTUAL::NewTick(); - делаете, похоже.
  2. В OnDeinit в начале прописать VIRTUAL::Stop();


Использовал в этом коде макросы, потому что девственный MQL4-style. Вставил макросы, чтобы сразу запахало без рутины прописывания пунктов выше.

 
fxsaber #:
без рутины прописывания пунктов выше.

Лучше рутина, чем когда своя функция вообще не вызывается. Я бы в основной OnTester() вставлял бы вызов виртуального типа VIRTUAL::OnTester (). В общем как с  VIRTUAL::NewTick();

Есть предложение по ускорению. Orders.mqh IsChange() строка 80. Если у вас например 90 ордеров, и закрылся один из них, например 5-й, то потом код все ордера выше сместит их копированием 6->5, 7->6 ... 90->89. Работает, но долго.
Можно просто переместить последний на место удаленного 90->5. Вместо 85 копирований, всего 1 (может и несколько, если они все на 1 тике закрылись).
Вот так

    bool IsChange( void )
  {
    bool Res = false;
    double Profit = 0;
    for (int i = 0; i < this.AmountOrders; i++)
    {
      Res |= this.Orders[i].IsChange(this.CurrentTick) && !this.Orders[i].IsClosed();

      if (this.Orders[i].IsClosed())
      {
        #ifdef ORDER_COMMISSION
           this.Balance += this.Orders[i].GetProfit() + this.Orders[i].GetCommission();
        #else // ORDER_COMMISSION
           this.Balance += this.Orders[i].GetProfit();
        #endif // ORDER_COMMISSION
        #ifdef ORDER_SWAP
          if(this.Orders[i].IsNotNull()){//проверка как в AddHistoryOrder()
             datetime RolloverTime=((datetime)ORDER_SWAP % 86400);//86400 sec in day
             double SwapShort=::SymbolInfoDouble(this.Orders[i].GetSymbol(), SYMBOL_SWAP_SHORT), SwapLong=::SymbolInfoDouble(this.Orders[i].GetSymbol(), SYMBOL_SWAP_LONG);
             int Rollover3Days = (int)::SymbolInfoInteger(this.Orders[i].GetSymbol(), SYMBOL_SWAP_ROLLOVER3DAYS);
             this.Orders[i].SetSwap(SwapShort, SwapLong, RolloverTime, Rollover3Days);
             this.Balance += this.Orders[i].GetSwap();
          }
        #endif
        this.AddHistoryOrder(this.Orders[i]);
        
        this.Orders[i--] = this.Orders[--this.AmountOrders];
      }
      else
      {
      #ifdef ORDER_COMMISSION
        Profit += this.Orders[i].GetFullProfit();
      #else // ORDER_COMMISSION
        Profit += this.Orders[i].GetProfit();
      #endif // ORDER_COMMISSION
      }
    }

    this.Equity = this.Balance + Profit;
    this.FlagChange |= Res;
    return(Res);
  }



Итоговый результат совпадает
Есть смена порядка сделок в истории, для сделок закрывшихся на одном тике
Старая версия

41583 41598 2022.05.30 23:50:09.897 sell 1.00 (215 604.00) EURUSD 1.07797

1.07807

2022.05.30 23:50:12.538 1.07807

-10.00 (-14.00)
-10 (-14) +4, 0 1 00:00:02.641 871985.00
41584 41595 2022.05.30 23:50:07.877 sell 1.00 (215 598.00) EURUSD 1.07794

1.07805

2022.05.30 23:50:35.750 1.07804

-10.00 (-11.00)
-10 (-11) 0, +1 2 00:00:27.873 871975.00
41585 41596 2022.05.30 23:50:09.897 sell 1.00 (215 601.00) EURUSD 1.07797

1.07804

2022.05.30 23:50:35.750 1.07804

-7.00 (-9.00)
-7 (-9) +2, 0 3 00:00:25.853 871968.00
41586 41600 2022.05.30 23:50:12.538 buy 1.00 (215 597.00) EURUSD 1.07807

1.07790

2022.05.30 23:51:07.013 1.07790

-17.00
-17
1 00:00:54.475 871951.00

Новая версия

41583 41598 2022.05.30 23:50:09.897 sell 1.00 (215 604.00) EURUSD 1.07797

1.07807

2022.05.30 23:50:12.538 1.07807

-10.00 (-14.00)
-10 (-14) +4, 0 1 00:00:02.641 871985.00
41584 41596 2022.05.30 23:50:09.897 sell 1.00 (215 601.00) EURUSD 1.07797

1.07804

2022.05.30 23:50:35.750 1.07804

-7.00 (-9.00)
-7 (-9) +2, 0 3 00:00:25.853 871978.00
41585 41595 2022.05.30 23:50:07.877 sell 1.00 (215 598.00) EURUSD 1.07794

1.07805

2022.05.30 23:50:35.750 1.07804

-10.00 (-11.00)
-10 (-11) 0, +1 2 00:00:27.873 871968.00
41586 41600 2022.05.30 23:50:12.538 buy 1.00 (215 597.00) EURUSD 1.07807

1.07790

2022.05.30 23:51:07.013 1.07790

-17.00
-17
1 00:00:54.475 871951.00

Для оценки ускорения сделал расчет за неделю:
old
Clear Pass time: 8.456 s.
Report Generation time: 12.100 s.
2023.11.26 17:54:09.333    EURUSD,M5: 537636 ticks, 1725 bars generated. Environment synchronized in 0:00:00.049. Test passed in 0:00:21.745 (including ticks preprocessing 0:00:00.063).

new
Clear Pass time: 7.978 s.
Report Generation time: 12.068 s.
2023.11.26 17:50:08.349    EURUSD,M5: 537636 ticks, 1725 bars generated. Environment synchronized in 0:00:00.046. Test passed in 0:00:21.316 (including ticks preprocessing 0:00:00.078).


Пол секунды разница, ускорение около 6%.

П.С.
Хотя возможно не стоит это применять. Любители сравнивать распечатки (вроде меня) тестера MQ и виртуального будут озадачены не полным совпадением.

 
Forester #:

Пол секунды разница, ускорение около 6%

Спасибо, проверю предложение.

 
Forester #:

Я бы в основной OnTester() вставлял бы вызов виртуального типа VIRTUAL::OnTester ().

Нет такой функции. Более того, непонятно, зачем она может быть нужна.

Тестирование в виртуалке - это просто один из бонусов концепции виртуалки. Сценариев использования гораздо больше.