ライブラリ: TesterBenchmark - ページ 4

 

MT5の主な速度低下の理由は、完全な取引環境の模倣です。大半のExpert Advisorでは、そのような正確なシミュレーションは必要ありません。そのようなExpert Advisorのための優れた解決策は、取引環境の単純なモデリングで、簡略化されたテストモードに切り替えることでしょう。しかし、そのような可能性はありません。しかし、自分で簡略化したストラテジー・テスターを作成し、それを数学的計算 モードで実行すれば、最適化のスピードは飛躍的に向上します! Expert Advisorsの最適化速度を劇的に 向上させたいとお考えの皆様には、このような方法をお勧めします。

 
Vasiliy Sokolov:

CStrategyでは、取引操作は CTradeを通じて直接行われる。つまり、CStrategyにはそれ自体の取引ロジックは全くありません。テスト用Expert Advisorでは、N秒後にポジションをオープン/クローズする以外の取引ロジックは見当たりませんでした。また、CStrategyはヒストリカル・ポジションを保存しないため、この例は残念ながらCStrategyでは実現できません。

CTradeも履歴を保存しませんが、だからといって、それを使ってバリアントを実装することを妨げるものではありませんでした。

OOPコードが手続き型コードより遅いという事実は、私に何も教えてはくれない。本題に入りましょう。どのCTradeメソッドがボトルネックになっているのでしょうか?なぜか?これらのメソッドのプロファイリングは何を教えてくれるのか?テスターで遅いコードセクションをどうやって特定するのですか?

SBブレーキの理由を分析したことはありませんが、OOPではないと思います。なぜならMT4OrdersもOOPで書かれているからです。BODへのリクエストの後、開発者はSBを加速させた。SB自体をいじったのか、コンパイラをいじったのかはわからない。

私自身は、まず絶対ブレーキを分析し、次に相対ブレーキを分析する。

MetaTrader 5には、過去のデータからExpert Advisorをプロファイリングする優れた機能があります。しかし、動作が遅い(ビジュアルモード)ことに加え、最終的な結果は相対的な単位で提供されます。

 
Vasiliy Sokolov:

MT5の主な速度低下の理由は、完全な取引環境の模倣です。大半のExpert Advisorでは、そのような正確なシミュレーションは必要ありません。そのようなExpert Advisorのための優れた解決策は、取引環境の単純なモデリングで、簡略化されたテストモードに切り替えることでしょう。しかし、そのような可能性はありません。しかし、自分で簡略化したストラテジー・テスターを作成し、それを数学的計算 モードで実行すれば、最適化のスピードは飛躍的に向上します! EAの最適化速度を劇的に 上げたいすべての方に考えていただきたいことです。

カスタム・シンボルを使えば、フル・シミュレーションで何桁ものスピードアップが実現できます。実際、カスタム・シンボルのベータ・モードでも、これを実現することは可能です。後でやってみます。

 
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は、同じMQL5で書かれたライブラリよりも遅いことが判明した!私は調査を開始し、次の置換を行うことでその原因を見つけました。

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

エキスパートアドバイザーのMQL5バージョンはこのようなパフォーマンスを示すようになった。

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


PositionSelectを PositionGetTicketに置き換えただけで、バックテスト速度が7%向上した!

MT4Ordersは最大に最適化された純粋なMQL5より1%未満遅れている。

 
fxsaber:

各賞の順位は以下の通りである。

  1. Pure MQL5 - 100%のパフォーマンス。

  2. SB TradeTrade.mqh - パフォーマンス84%。
SBはラグが少なくなった。

機能性や汎用性は変えずに、SB自体を少しいじった(Expert Advisorが使用するSBの一部)。84%ではなく97%になった。

SBを使っている人は、加速の可能性に注意してください。

 

同じMT4多通貨Expert Advisorを異なる方法で変換した場合のパフォーマンスを比較するのが面白くなりました。

フルコンバージョン

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


職人的(高速)変換

パフォーマンス測定の結果。


本格版

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


職人的なもの

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


artisanalは大きく負けています。理由は簡単で、高速な時系列を求めるなら、MT4の時系列を真正面から変換できないからです

取引、自動取引システム、取引戦略のテストに関するフォーラム。

ライブラリ: CPrice

fxsaber, 2016.08.28 10:36 AM

そのようなオプションを見て ください

#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)

MT4のように、Open[bar]、High[bar]、Time[bar]、Volume[bar]などを呼び出すことができます。また、iHigh(...)、iClose(...)など。

ブッシュだけでなく、本格的なバリアントでも)この ようなソリューションを使用する必要があります。

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

職人的なものは大きく損をする。理由は簡単で、高速な時系列を求めるなら、MT4の時系列を真正面から変換できないからだ。

間違った結論だ。ブレーキの理由はまったく異なる。MT5の各バリアントに1行だけ挿入してみよう。

#define Comment(A)

そしてもう一度計測してみよう

  • 本格的

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

  • 職人的なもの

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


フル装備の方が67%速く、アルチザナルの方が108%速い!まとめると、その差は小さくなり、フル装備の方がアーティザナルより~11%速い。その理由はOOPオーバーヘッドにあるようだ。


しかし、メインはそこではない。1行でEAを高速化することに成功したのだ!しかも、これはオプティマイザーでのことで、コメントは 何の役割も果たしていない。

 

これはSDアプリケーションと一緒に夏に書かれたものです。すべてが互角とは驚きです!それとも論理的?ほとんどすべての(SBを使用した)EAが速度で失敗し、クラウドで資金を食いつぶすなどしているのに、どうしてテスターの超高速について語ることができるのでしょうか!どうやらこれが普通らしい。


私はヒストリーとMT4Ordersの作業を捨ててソースコードを単純化した。純粋なMQL5とSBだけを残した。

#include <TesterBenchmark.mqh>

#include <Trade\Trade.mqh> // 純粋なMQL5でバリアントを有効にするためのコメントアウト

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の結果

------
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


純粋な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

すべて同じ1.5倍!でも、カモは 気にしない、スーパーSBを 使い続けよう。

 
fxsaber:

同じ1.5倍!でも、カモは 気にしない、スーパーSBを 使い続けよう。

これがSBの微調整だ。

//+------------------------------------------------------------------+
//| 注文の送信|
//+------------------------------------------------------------------+
bool CTrade::OrderSend(const MqlTradeRequest &request,MqlTradeResult &result)
  {
   static const bool IsTester = (::MQLInfoInteger(MQL_TESTER) || ::MQLInfoInteger(MQL_OPTIMIZATION));
   
   bool res;
   string action="";
   string fmt   ="";
//--- アクション
   if(m_async_mode)
      res=::OrderSendAsync(request,result);
   else
      res=::OrderSend(request,result);
//--- チェック
   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));
     }
//--- 結果を返す
   return(res);
  }
//+------------------------------------------------------------------+
//| インデックス上の位置を選択|
//+------------------------------------------------------------------+
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);
  }

SBアドバイザーを奇跡的にスピードアップさせる。複雑ですか?

率直に言って、APIロジックを変えずに取引SBを、ほぼ完全に書き換えるべきだ。どの部分もダメだ。