ライブラリ: MT4Orders - ページ 82

 

MT5の言語関数を使用せずに、テスト速度でこの問題を解決することが可能かどうか理解できません。 この問題はかなり前に現れていましたが、私の手は今になってようやくそれにたどり着きました。

ビルド3802、___MT4ORDERS__ "2022.07.20"

Expert Advisorでティックごとに呼び出される条件関数。mt5ストラテジーテスターでテスト。

	 datetime get_last_order_close_time () {
                datetime last_close_time=0;

                for ( int i = OrdersHistoryTotal() - 1; i >= 0; i-- ) {
                        if ( !OrderSelect ( i, SELECT_BY_POS, MODE_HISTORY )) {
                                continue;
                        }
         		 last_close_time=OrderCloseTime();
		        return last_close_time;
                }

                return last_close_time;
        }

取引数は 約26,000件。テスト時間は約1時間10分。

コードから関数を削除すると、テスト時間は約17分になった。

同じ関数をMT5の機能を使って書き直しました:

	 datetime get_last_order_close_timeMT5 () {
                datetime last_close_time=0;
                HistorySelect(0,TimeCurrent()); 

                for ( int i = HistoryDealsTotal() - 1; i >= 0; i-- ) {
                        
                        ulong ticket=HistoryDealGetTicket(i);
                        
                        if((ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT)
                        {
                           last_close_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
                           return last_close_time;
                        }                       
                }

                return last_close_time;
        }

テスト時間は約18分。

ライブラリを__MT4ORDERS__のバージョン「2020.01.12」にロールバックし、ビルド2980でExpert Advisorをコンパイルしました。

get_last_order_close_time 関数を使用したExpert Advisorの時間は約20分です。

 
elavr #:

このテスト速度の問題は、MT5の言語機能を使用せずに解決できるかどうかわかりません。

3つのケースとも最終結果は同じですか?
 
fxsaber #:
3つのケースとも、最終的な結果は同じなのだろうか?

はい、もちろんです。

別のターミナルをアップデートした後に起こり始めました。あなたのライブラリは変更せず、古いターミナルでボットをコンパイルして、以前と同じように動くようにしました。

 
elavr #:

この現象は、ターミナルの別のアップデートの後に起こり始めました。私はあなたのライブラリを変更せず、古いターミナルでボットをコンパイルして、以前と同じように動作するようにしました。

少し調べてみました。


エキスパートアドバイザー

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

#define  VIRTUAL_SNAPSHOT_REFRESHTIME 1000
#include <fxsaber\Virtual\Virtual.mqh> //https://www.mql5.com/ja/code/22577

input int inMod = 5;
input int inRange = 0;
input bool inVirtual = false;

const bool Init = inVirtual ? VIRTUAL::SelectByHandle(VIRTUAL::Create()) : false;;

#define  Bid SymbolInfoDouble(_Symbol, SYMBOL_BID)
#define  Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

ulong lOnTester = 0;

void OnTick()
{  
  static int i = 0;
  
  VIRTUAL::NewTick();
  
  if (!(i++ % inMod))
    OrderClose(OrderSend(_Symbol, OP_BUY, 0.1, Ask, 0, 0, 0), 0.1, Bid, 0);
    
// VIRTUAL::Snapshot(); 
  lOnTester += LastCloseTimeMQL4() % 100;
  
// lOnTester += LastCloseTimeMQL5() % 100;
}

double OnTester()
{
  if (HistorySelect(0, INT_MAX))
    Print(HistoryDealsTotal());
  
  return((double)lOnTester);
}

各inModティックでポジションがオープンされ、クローズされます。そして各ティックでOrderCloseTimeが計算されます。

OnTesterは、異なる設定での結果の同一性をチェックする基準として機能する。


履歴に対応する機能。

datetime LastCloseTimeMQL4()
{  
  datetime Res = 0;
  
  for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
    {
      Res = OrderCloseTime();
      
      break;
    }

  return(Res);
}

datetime LastCloseTimeMQL5()
{
  datetime Res = 0;
  
  if (HistorySelect(0, INT_MAX))
    for (int i = HistoryDealsTotal() - 1; i >= 0; i--)
    {
      const ulong Ticket = HistoryDealGetTicket(i);
      
      if (HistoryDealGetInteger(Ticket, DEAL_ENTRY) != DEAL_ENTRY_IN)
      {
        Res = (datetime)HistoryDealGetInteger(Ticket, DEAL_TIME);
        
        break;
      }
    }
    
  return(Res);
}

#define  MACROS(A, B)          \
  datetime A##_2()            \
  {                           \
    static datetime Res = 0;  \
    static int PrevTotal = 0; \
                              \
    const int Total = B;      \
                              \
    if (PrevTotal != Total)   \
    {                         \
      Res = A();              \
                              \
      PrevTotal = Total;      \
    }                         \
                              \
    return(Res);              \
  }

// LastCloseTimeMQL4_2
MACROS(LastCloseTimeMQL4, OrdersHistoryTotal())

// LastCloseTimeMQL5_2
MACROS(LastCloseTimeMQL5, HistorySelect(0, INT_MAX) ? HistoryDealsTotal() : 0)



ソースと同じ設定(inMod = 5)で 1 回実行。

2023.07.06 23:59:59   28179
final balance 99996992.20 pips
OnTester result 2761115
EURUSD,M1: 274413 ticks, 70443 bars generated. Environment synchronized in 0:00:00.021. Test passed in 0:00:03.712 (including ticks preprocessing 0:00:00.031).

28Kトランザクション、ほぼ4秒。パフォーマンスを最適化モードで測定する必要があるため、以下のパフォーマンス測定はすべてこの方法で行った。

shortest pass 0:00:02.875, longest pass 0:00:03.094, average pass 0:00:02.919

実行前に再コンパイルが必須であり、パスのシーケンシャル実行には1つのエージェントのみが有効である。


パフォーマンス

b3815とb2958のパフォーマンス表(実行時間単位:ミリ秒)。

MT5ビルド LastCloseTimeMQL4 最終クローズ時間MQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::スナップショット LastCloseTimeMQL4+VirtualTester
b3815 2875 113 708 732 45
b2958 2718 107 675 715 50

20.07.2022からの MT4Ordersはどこでも使用された。


結論

  • OrderSelect は遅い。これは、OrderSelect が履歴から選択された注文の絶対的にすべてのデータを計算するためである(OrderPrint は無料)。これは、HistoryOrderGet*関数とHistoryDealGet*関数の素晴らしい組み合わせであり、どんな複雑な相場状況や多数の落とし穴にも対応します。MT4ORDERS::GetHistoryPositionData()をチェックしてください。これはターミナル用とテスター用の単一の関数ですが、ターミナルの多くの落とし穴がテスターには存在しないため、テスター用に特別に高速化されています。設定の例:123
  • したがって、過去の注文の OrderSelect 呼び出しを減らす必要があります。これは、表の右3列で示した方法で達成できる。
  • 純粋なMQL5よりも)最も速い作業は、仮想環境での取引です。仮想環境で最適化し、仮想環境外ではシングルパスで最適化することをお勧めします。
  • テスターb2958とb3815のパフォーマンスはほぼ同じです。
  • TesterのTSのロジックを、取引履歴を参照して紐付けることはお勧めしません。例えば、履歴を参照しなくてもTSのOrderCloseTimeを知ることができます。
 
elavr #:

テスト時間は約1時間10分

ライブラリを__MT4ORDERS__バージョン「2020.01.12」にロールバックし、ビルド2980でExpert Advisorをコンパイルします。

get_last_order_close_time 関数によるExpert Advisorの動作時間は約20分 です。

上記のコードをライブラリの古いバージョン(私は持っていません)で試してみてください。

もしパフォーマンスに違いがあれば、PMに送ってください。

 
本当にありがとう!来週チェックしてみるよ
 

メモリリークや必要以上のメモリ使用はありませんか?this.tickets内かthis.amount (::ArrayResize)内か、あるいは他のどこかでしょうか?

配列のサイズは時間の経過とともに大きくなるだけです。これは必須ですか?配列を空にすることは可能でしょうか、あるいは以前の取引をすべて読み込まないようにすることは可能でしょうか。

 
pcdeni #:

メモリリークや必要以上のメモリ使用はありませんか?もしかしたらthis.ticketかthis.amount (::ArrayResize)の中か、あるいは他のどこかでしょうか?

配列のサイズは時間の経過とともに大きくなるだけです。これは必須ですか?配列を空にすることは可能でしょうか、あるいは以前の取引をすべて読み込まないようにすることは可能でしょうか。

ライブラリは履歴データを完全にキャッシュしません。メモリ不足になることは理論的には可能ですが、実際には不可能です。

ライブラリを使って全取引履歴をソートするスクリプトを作成し、メモリ消費量を確認してください。

 
fxsaber #:

ライブラリーは履歴データを完全にはキャッシュしない。メモリ不足に陥ることは理論的には可能だが、実際にはありえない。

ライブラリを使って全取引履歴をソートするスクリプトを書き、メモリがどれだけ消費されるかを見てみよう。

ストラテジー・テストでは、EAはコアあたり25GBを使用している。

編集:1年間のタイムフレームテストなので、それほど多くはない。
 
pcdeni #:

ストラテジー・テストでは、EAはコアあたり25GBを使用している。

編集:1年間のタイムフレームテストなので、それほど多くはありません。

ライブラリ(MT4Orders.mqh)はそれほどメモリを消費しません。たとえば、このEAを 実行してご自分の目で確かめてみてください。

おそらく、インジケータの操作が間違っているのでしょう。新しいインジケータハンドルを作成し、古いハンドルを削除していません。