Bibliotheken: TesterBenchmark - Seite 4

 

Der Grund für die Hauptverlangsamung von MT5 ist die Nachahmung der vollständigen Handelsumgebung. Bei der überwiegenden Mehrheit der Expert Advisors ist eine solch genaue Simulation nicht erforderlich. Eine hervorragende Lösung für solche Expert Advisors wäre der Wechsel zu einem vereinfachten Testmodus mit einer einfachen Modellierung der Handelsumgebung. Eine solche Möglichkeit gibt es jedoch nicht. Aber wenn Sie Ihren eigenen, vereinfachten Strategietester schreiben und ihn im Modus der mathematischen Berechnungen laufen lassen, wird die Geschwindigkeit der Optimierung ein Feuerwerk sein! Ich schlage vor, dass jeder, der die Geschwindigkeit der EA-Optimierung drastisch erhöhen möchte, darüber nachdenken sollte.

 
Vasiliy Sokolov:

In CStrategy werden die Handelsoperationen direkt über CTrade durchgeführt. D.h. CStrategy hat überhaupt keine eigene Handelslogik. In dem getesteten Expert Advisor habe ich keine andere Handelslogik gesehen als das Öffnen/Schließen einer Position nach N Sekunden. CStrategy speichert auch keine historischen Positionen, so dass dieses Beispiel in CStrategy leider nicht realisierbar ist.

CTrade speichert auch keine Historie, aber das hat uns nicht daran gehindert, die Variante damit zu implementieren.

Die Tatsache, dass OOP-Code langsamer ist als prozeduraler Code, sagt mir gar nichts. Kommen wir zur Sache: Welche CTrade-Methoden sind ein Flaschenhals? Und warum? Was sagt Ihnen das Profiling dieser Methoden? Wie können Sie langsame Codeabschnitte im Tester identifizieren?

Ich habe die Gründe für die SB-Bremsen nicht analysiert, aber ich glaube nicht, dass es an OOP liegt, denn MT4Orders ist auch mit OOP geschrieben, wenn auch nur minimal. Nach einer Anfrage an den BOD haben die Entwickler die SB beschleunigt. Ich weiß nicht, ob sie die SB selbst oder den Compiler optimiert haben.

Ich analysiere zuerst absolute Bremsen, dann relative Bremsen

MetaTrader 5 verfügt über eine hervorragende Funktion zur Erstellung eines Profils für einen Expert Advisor anhand historischer Daten. Aber abgesehen von der Tatsache, dass sie langsam arbeitet (im visuellen Modus), wird das Endergebnis in relativen Einheiten angegeben, d.h. es ist unmöglich, die Leistung in absoluten Zahlen zu vergleichen.

 
Vasiliy Sokolov:

Der Grund für die Hauptverlangsamung von MT5 ist die Nachahmung der vollständigen Handelsumgebung. Bei der überwiegenden Mehrheit der Expert Advisors ist eine solch genaue Simulation nicht erforderlich. Eine hervorragende Lösung für solche Expert Advisors wäre der Wechsel zu einem vereinfachten Testmodus mit einer einfachen Modellierung der Handelsumgebung. Eine solche Möglichkeit gibt es jedoch nicht. Aber wenn Sie Ihren eigenen, vereinfachten Strategietester schreiben und ihn im Modus der mathematischen Berechnungen laufen lassen, wird die Geschwindigkeit der Optimierung ein Feuerwerk sein! Ich empfehle Ihnen, darüber nachzudenken, wenn Sie die Geschwindigkeit der EA-Optimierung drastisch erhöhen wollen.

Durch benutzerdefinierte Symbole können Sie eine Beschleunigung um Größenordnungen bei voller Simulation erreichen. Tatsächlich ist es sogar jetzt im Beta-Modus der benutzerdefinierten Symbole möglich, dies zu erreichen. Ich werde es später tun.

 
MQL5:
i = 5 Pass = 5 OnTester = 8.521 s.: Count = 15925124, 1868926.7 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


MT4Orders:

i = 2 Pass = 2 OnTester = 8.001 s.: Count = 15925124, 1990391.7 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


MQL5 erwies sich als langsamer als die Bibliothek in der gleichen MQL5 geschrieben werden! Ich begann zu untersuchen und fand den Grund, indem ich diese Ersetzung vornahm

// if (!PositionSelect(_Symbol))
  if (!PositionGetTicket(0))

Die MQL5-Variante des Expert Advisors begann, diese Leistung zu zeigen.

i = 4 Pass = 4 OnTester = 7.931 s.: Count = 15925124, 2007959.1 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


Stupid Ersatz von PositionSelect mit PositionGetTicket erhöht die Backtest-Geschwindigkeit um 7%!

MT4Orders hinkt dem maximal optimierten reinen MQL5 um weniger als ein Prozent hinterher.

 
fxsaber:

Die Plätze wurden wie folgt verteilt

  1. Pure MQL5 - 100% Leistung.

  2. SB Trade\Trade.mqh - ~84% Leistung.
Der SB ist weniger laggy geworden.

Ich habe die SB selbst optimiert (Teile der SB, die vom Expert Advisor verwendet werden), ohne ihre Funktionalität und Vielseitigkeit zu verändern. Es wurden nicht 84%, sondern 97%.

Diejenigen, die SB verwenden, beachten Sie die potenzielle Möglichkeit der Beschleunigung.

 

Es ist interessant, die Leistung desselben MT4-Mehrwährungs-Expert Advisors zu vergleichen, der auf unterschiedliche Weise konvertiert wurde.

Vollständige Konvertierung

#include <TesterBenchmark.mqh> // https://www.mql5.com/de/code/18804
#include "Spreader 2.mq5"      // https://www.mql5.com/de/code/19402


und handwerkliche (schnelle) Konvertierung

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien.

Expert Advisors: Spreader

fxsaber, 2016.09.03 11:18 AM.

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

#include "Spreader_v2.mq4" // https://www.mql5.com/de/code/9495

void OnTick()
{
  start();
}

Ergebnisse der Leistungsmessung.


Vollwertige Version

i = 1 Pass = 1 OnTester = 3.465 s.: Count = 897532, 259028.0 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


Artisanal

i = 1 Pass = 1 OnTester = 4.815 s.: Count = 897532, 186403.3 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


Der Artisanal verliert deutlich. Der Grund ist einfach - wenn man schnelle Zeitreihen will, kann man die MT4-Zeitreihen nicht frontal konvertieren

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien.

Bibliotheken: CPrice

fxsaber, 2016.08.28 10:36 AM

Schau dir eine solche Option an.

#define  DEFINE_TIMESERIE(NAME,FUNC,T)                                                                         \
  class CLASS##NAME                                                                                           \
  {                                                                                                           \
  public:                                                                                                     \
    static T Get(const string Symb,const int TimeFrame,const int iShift)                                      \
    {                                                                                                         \
      T tValue[];                                                                                             \
                                                                                                              \
      return((Copy##FUNC((Symb == NULL) ? _Symbol : Symb, _Period, iShift, 1, tValue) > 0) ? tValue[0] : -1); \
    }                                                                                                         \
                                                                                                              \
    T operator[](const int iPos) const                                                                        \
    {                                                                                                         \
      return(CLASS##NAME::Get(_Symbol, _Period, iPos));                                                       \
    }                                                                                                         \
  };                                                                                                          \
                                                                                                              \
  CLASS##NAME  NAME;                                                                                           \
                                                                                                              \
  T i##NAME(const string Symb,const int TimeFrame,const int iShift)                                           \
  {                                                                                                           \
    return(CLASS##NAME::Get(Symb,  TimeFrame, iShift));                                                        \
  }

DEFINE_TIMESERIE(Volume,TickVolume,long)
DEFINE_TIMESERIE(Time,Time,datetime)
DEFINE_TIMESERIE(Open,Open,double)
DEFINE_TIMESERIE(High,High,double)
DEFINE_TIMESERIE(Low,Low,double)
DEFINE_TIMESERIE(Close,Close,double)

Du kannst, wie in MT4, Open[bar], High[bar], Time[bar], Volume[bar], usw. aufrufen. Und auch iHigh(...), iClose(...) und andere.

Sie müssen (nicht nur für Busch, sondern auch für vollwertige Varianten) Lösungen wie diese verwenden.

Высокопроизводительная библиотека iTimeSeries
Высокопроизводительная библиотека iTimeSeries
  • Stimmen: 23
  • 2017.05.25
  • nicholishen
  • www.mql5.com
Одной из основных проблем с MQL5 до сих пор было удаление встроенных функций для работы с таймсериями. Несмотря на то, что такой подход расширил для программистов возможности разработки, он также замедлил работу из-за обязательного шага по созданию и удалению новых ячеек памяти каждый раз, когда требуется доступ к данным таймсерии.  Рассмотрим...
 
fxsaber:

Die handwerkliche eine verliert deutlich. Der Grund ist einfach - wenn Sie schnelle Zeitreihen wollen, können Sie MT4-Zeitreihen nicht direkt konvertieren.

Falsche Schlussfolgerung. Der Grund für die Bremsen ist ein ganz anderer. Fügen wir nur eine Zeile in jede der MT5-Varianten ein

#define Comment(A)

Und messen Sie erneut

  • Vollwertig

i = 1 Pass = 1 OnTester = 2.074 s.: Count = 897532, 432754.1 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 165

  • Artisanal.

i = 1 Pass = 1 OnTester = 2.310 s.: Count = 897532, 388542.0 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1653


Die Vollversion ist 67% schneller, die Artisanal-Variante ist 108% schneller! Zusammenfassend lässt sich sagen, dass der Abstand jetzt gering ist - Full-fledged ist ~11% schneller als Artisanal. Hier scheint der Grund im OOP-Overhead zu liegen.


Aber das ist nicht die Hauptsache. Mit einer einzigen Zeile haben wir es geschafft, EAs zu beschleunigen! Und das im Optimiser, wo Comment keine Rolle spielt.

 

Das wurde im Sommer zusammen mit der SD-Anwendung geschrieben. Ich bin überrascht, dass alles gleichmäßig ist! Oder ist es logisch? Wie kann man über die Supergeschwindigkeit des Testers sprechen, wenn fast alle EAs (mit SB) in der Geschwindigkeit versagen, Geld in der Cloud fressen, usw.! Anscheinend ist das normal.


Ich habe den Quellcode vereinfacht, indem ich die Arbeit mit History und MT4Orders rausgeschmissen habe. Ich habe nur noch reines MQL5 und SB

#include <TesterBenchmark.mqh>

#include <Trade\Trade.mqh> // Auskommentieren, um die Variante in reinem MQL5 zu aktivieren

input int Interval = 60;

void OnTick()
{
#ifdef   ERR_USER_INVALID_HANDLE // trade.mqh
  static CTrade Trade;
  static CDealInfo Deal;
  static CPositionInfo Position;

  if (!Position.SelectByIndex(0))
  {
    if (HistorySelect(0, LONG_MAX))
    {
      const int Total = HistoryDealsTotal() - 1;

      if ((Total >= 0) && Deal.SelectByIndex(Total) && (Deal.DealType() == DEAL_TYPE_SELL))
        Trade.Sell(1);
      else
        Trade.Buy(1);
    }
  }
  else if (TimeCurrent() - Position.Time() >= Interval)
    Trade.PositionClose(_Symbol);
#else  // ERR_USER_INVALID_HANDLE
  if (!PositionGetTicket(0))
  {
    if (HistorySelect(0, LONG_MAX))
    {
      const int Total = HistoryDealsTotal() - 1;
      MqlTradeRequest Request = {0};

      Request.action = TRADE_ACTION_DEAL;

      Request.symbol = _Symbol;
      Request.type = ((Total >= 0) && ((ENUM_DEAL_TYPE)HistoryDealGetInteger(HistoryDealGetTicket(Total), DEAL_TYPE) == DEAL_TYPE_SELL)) ?
                     ORDER_TYPE_SELL : ORDER_TYPE_BUY;;

      Request.volume = 1;
      Request.price = SymbolInfoDouble(Request.symbol, (Request.type == ORDER_TYPE_BUY) ? SYMBOL_ASK : SYMBOL_BID);

      MqlTradeCheckResult CheckResult;
      if (OrderCheck(Request, CheckResult))
      {
        MqlTradeResult Result;

        const bool AntiWarning = OrderSend(Request, Result);
      }
    }
  }
  else if (TimeCurrent() - PositionGetInteger(POSITION_TIME) >= Interval)
  {
    MqlTradeRequest Request = {0};
    MqlTradeResult Result;

    Request.action = TRADE_ACTION_DEAL;
    Request.position = PositionGetInteger(POSITION_TICKET);

    Request.symbol = PositionGetString(POSITION_SYMBOL);
    Request.type = (ENUM_ORDER_TYPE)(1 - PositionGetInteger(POSITION_TYPE));

    Request.volume = PositionGetDouble(POSITION_VOLUME);
    Request.price = PositionGetDouble(POSITION_PRICE_CURRENT);

    const bool AntiWarning = OrderSend(Request, Result);
  }
#endif // ERR_USER_INVALID_HANDLE
}


SB-Ergebnis

------
OnTesterInit
i = 0 Pass = 0 OnTester = 1.898 s.: Count = 2007057, 1057458.9 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1730
i = 1 Pass = 1 OnTester = 1.900 s.: Count = 2007057, 1056345.8 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1730
iMin = 0 Results[iMin] = 1.898 s.
iMax = 1 Results[iMax] = 1.900 s.
Amount = 2 Mean = 1.899 s. - 81.75%
OnTesterDeinit
------
Interval = 4.646 s., Count = 0, 0.0 unit/sec


Ergebnis der reinen MQL5

------
OnTesterInit
i = 0 Pass = 0 OnTester = 1.239 s.: Count = 2007057, 1619900.7 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1730
i = 1 Pass = 1 OnTester = 1.243 s.: Count = 2007057, 1614687.9 unit/sec, Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1730
iMin = 0 Results[iMin] = 1.239 s.
iMax = 1 Results[iMax] = 1.243 s.
Amount = 2 Mean = 1.241 s. - 75.10%
OnTesterDeinit
------
Interval = 3.305 s., Count = 0, 0.0 unit/sec

Alles das gleiche 1,5 Mal! Aber die Trottel kümmern sich nicht, lassen Sie uns weiterhin Super-SB verwenden .

 
fxsaber:

Dasselbe 1,5 Mal! Aber den Trotteln ist das egal, sie wollen weiter den Super-SB benutzen .

Das ist die Art von SB-Tweaks, die

//+------------------------------------------------------------------+
//| Bestellung abschicken|
//+------------------------------------------------------------------+
bool CTrade::OrderSend(const MqlTradeRequest &request,MqlTradeResult &result)
  {
   static const bool IsTester = (::MQLInfoInteger(MQL_TESTER) || ::MQLInfoInteger(MQL_OPTIMIZATION));
   
   bool res;
   string action="";
   string fmt   ="";
//--- Aktion
   if(m_async_mode)
      res=::OrderSendAsync(request,result);
   else
      res=::OrderSend(request,result);
//--- prüfen
   if(res)
     {
      if(!IsTester &&  m_log_level>LOG_LEVEL_ERRORS)
         PrintFormat(__FUNCTION__+": %s [%s]",FormatRequest(action,request),FormatRequestResult(fmt,request,result));
     }
   else
     {
      if(!IsTester &&  m_log_level>LOG_LEVEL_NO)
         PrintFormat(__FUNCTION__+": %s [%s]",FormatRequest(action,request),FormatRequestResult(fmt,request,result));
     }
//--- Rückgabe des Ergebnisses
   return(res);
  }
//+------------------------------------------------------------------+
//| Wählen Sie eine Position auf dem Index|
//+------------------------------------------------------------------+
bool CPositionInfo::SelectByIndex(const int index)
  {
   return(PositionGetTicket(index));
   
   ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
//---
   if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
     {
      ulong ticket=PositionGetTicket(index);
      if(ticket==0)
         return(false);
     }
   else
     {
      string name=PositionGetSymbol(index);
      if(name=="")
         return(false);
     }
//---
   return(true);
  }

die die SB-Berater auf wundersame Weise beschleunigen. Ist es kompliziert?

Ehrlich gesagt, sollte die Handels-SB, ohne die API-Logik zu ändern, fast vollständig neu geschrieben werden. Jeder Teil davon ist schlecht.