MT5とスピードの関係 - ページ 20

 
fxsaber:

もっと早い選択肢があるかもしれません。しかし、数えるべきものの条件を一歩左にずらせば、ロジックはかなり変わらざるを得ないかもしれません。一般的には簡単ではない。

CHashMap<ulong, ulong> DealsIn;  // По PositionID возвращает DealIn.


キャッシュではなく、インデキシングです。以下、キャッシュ(コードの一部)です。

class DealInfo {
public:
  datetime Closed;
  ulong Ticket;
  ulong Position;
  string Symbol;
  long Type;
  long Reason;
  double Volume;
  double Price;
  double Profit;
  double Swap;
  long Magic;
};

class DealsComparer : public IComparer<DealInfo*> {
  int Compare(DealInfo* x, DealInfo* y) {
    int res = (int)(x.Closed - y.Closed);
    if (res == 0) {
      res = (int)(x.Ticket - y.Ticket);
    }
    
    return res;
  }
};

CArrayList<DealInfo*> dealsHistory;

inline bool UpdateDeals(CArrayList<DealInfo*> &deals, datetime &lastUpdated) {
  DealInfo* dealsToAdd[];
  DealsComparer comparer;
  int toAdd = 0;
  DealInfo* deal;
  
  if (!HistorySelect(lastUpdated, TimeLocal() + 12*3600)) {
    return false;
  }

  for (int i = 0, total = HistoryDealsTotal(); i < total; i++) {
    DealInfo tmp;
    ulong ticket = HistoryDealGetTicket(i);
    if (ticket == 0) continue;
    
    datetime dt = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);
    if (lastUpdated < dt) {
      lastUpdated = dt;
    }

    if (HistoryDealGetInteger(ticket, DEAL_ENTRY) != DEAL_ENTRY_OUT) continue;

    ulong reason = HistoryDealGetInteger(ticket, DEAL_REASON);

    tmp.Ticket = ticket;
    tmp.Closed = dt;
    int idx = deals.BinarySearch(&tmp, &comparer);
    if (idx >= 0 && deals.TryGetValue(idx, deal) && deal != nullptr && deal.Ticket == ticket)
      continue;

    deal = new DealInfo;
    deal.Ticket = ticket;
    deal.Closed = dt;
    deal.Position = HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
    deal.Symbol = HistoryDealGetString(ticket, DEAL_SYMBOL);
    deal.Type = HistoryDealGetInteger(ticket, DEAL_TYPE);
    deal.Reason = HistoryDealGetInteger(ticket, DEAL_REASON);
    deal.Volume = HistoryDealGetDouble(ticket, DEAL_VOLUME);
    deal.Price = HistoryDealGetDouble(ticket, DEAL_PRICE);
    deal.Swap = HistoryDealGetDouble(ticket, DEAL_SWAP);
    deal.Profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
    deal.Magic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
    
    ArrayResize(dealsToAdd, toAdd + 1, total);
    dealsToAdd[toAdd++] = deal;
  }
  
  if (toAdd > 0) {
    deals.AddRange(dealsToAdd);
    deals.Sort(&comparer);
  }
  
  return (toAdd > 0);
}

このコードは急いで書いたもので、頻繁にArrayResizeを 行うことを考えると、改良すべき点がたくさんありますが、正確にキャッシュを更新し、Closedでソートしています。後で検索する場合は、独自のインデックスを使用します。でも、毎回更新するのはごく一部だけです。
なぜ「12*3600」があるのかは覚えていませんが、全ての案件が発行されたわけではないと思います。

 
Andrey Pogoreltsev:

キャッシュではなく、インデックスなんです。

よくお読みください。

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

MT5とスピードの関係

fxsaber, 2020.08.28 21:10

純粋なMQL5は、部分的(HistorySelectByPositionのみ)なキャッシュに 比べ100倍も遅い。

建築的に フルキャッシュを行うには、慎重に考える必要があります。いろいろな落とし穴があるんです。

以下、キャッシュ(コードの一部)です。

急遽書いたコードで、頻繁なArrayResizeを考えると改善すべき点はありますが、Closedでソートされたキャッシュを更新しています。後で検索する場合は、独自のインデックスを使用します。でも、毎回更新するのはごく一部だけです。

まさに、本当のギミックを排除した正面からの歴史保存の例と言えるでしょう。MT4Ordersでも部分的なキャッシュは5秒のマージンで行われますが...。

なぜ「12*3600」があるのか覚えていないのですが、全てのトレードが発行されたわけではないと思うのですが。

常にINT_MAXを設定する。

 
fxsaber:

アーキテクチャ上、完全なキャッシュを行うには、多くの思考が必要です。落とし穴がたくさんあるんです。

何も難しいことはないんです。例えば、履歴に遡って表示されるかもしれない全ての注文に対して、数時間の余裕を持ってサンプリングを行うことができます(ちなみに、これは非常に不思議なことです)。

これはまさに、リアルタイムのギミックを排除した真正面からの履歴保存の一例です。MT4Ordersでも部分的なキャッシュは5秒のマージンで行われますが...。

常にINT_MAXを設定する。

シフトの意味がわからない。現在のタイムスタンプがあるように、そこからの相対的な取得をしたいのに、存在しない時間を指定しなければならないのはおかしい。論理的な説明が欲しいところです。

ちなみに私のキャッシュは、1万円以上の取引をしている実際の口座で動作しています。

そして、これまでのコードで大きなブレーキとなっているのが、ネットワーク機能です。

 
ちょうど通りかかったので、ここですでにヒントになっていることをまとめておこうと思ったのです。何が何でも超高速なパフォーマンスが必要な場合は、メモリなど他のリソースの消費を犠牲にして、伝統的に実現されています。つまり、何らかの集計値(総時間だけでなくてもよい)を算出する必要がある場合に、毎回履歴全体をループさせる必要はなく、あらかじめ「配列」(あるいは他の最適化されたデータ構造)ですべてを算出し、あとは補強するだけでよいのです。また、位置識別子(またはブレークダウンが行われる任意のパラメータ)による値の要求は、メモリセルの参照に縮退されます。最も一般的な形で - それはOLAPのようなものだ(私の実装では、オンラインアップデートを終了していないが)、特定の問題のために行われ、よりシンプルにすることができます。
 

最新のベータ2588では、HistorySelect 機能は非常によくキャッシュされ、ほとんど(初回を除いて)無料で利用できる。

その他にも、発売までに様々な改良を加えていく予定です。



先ほど説明したように、MT5では、MT4で行われていた各イベントの前に各EAのマーケットスナップショットを自動的に作成することに、余分なコストはかかりません。これにより、遅延を減らし、ロボットをより速く走らせることができるのです。各開発者は、必要なものを的確に要求する。

したがって、「履歴全体に対してHistorySelectを呼び出した後、すぐに別のHistorySelectByPositionの選択を行う」というやり方は、以前に作成した履歴のキャッシュを殺してしまうことを明確に理解する必要があるのです。これは足元をすくわれますね。


リリース後は、より効率的なMQL5関数やオープンなネイティブ・オーダー/トレード・データ構造の追加に取り組み、アルゴリズム・トレーディングの簡素化とスピードアップを実現する予定です。

 
Renat Fatkhullin:

最新の2588ベータ版では、HistorySelect 機能は非常によくキャッシュされ、ほとんど(初回を除いて)無料で利用できる。

#include <fxsaber\Benchmark.mqh> // https://c.mql5.com/3/321/Benchmark.mqh

input int inAlertTime = 1; // Нижний порог в миллисекундах

#define _B2(A) _B(A, inAlertTime)
#define  ALERT(A) Alert(#A + " = " + (string)(A))

void OnInit()
{
  if (HistorySelect(0, INT_MAX))
  {
    ALERT(HistoryDealsTotal());
    ALERT(HistoryOrdersTotal());
  }
}

void OnTick()
{
  static int i = 0;
  
  ALERT(i++);
  
  _B2(HistorySelect(TimeCurrent(), INT_MAX));
  _B2(HistorySelect(0, INT_MAX));
}


結果

2020.09.01 22:56:46.089 Test6 (EURAUD,M1)       Alert: HistoryDealsTotal() = 9435
2020.09.01 22:56:46.089 Test6 (EURAUD,M1)       Alert: HistoryOrdersTotal() = 12529
2020.09.01 22:56:46.575 Test6 (EURAUD,M1)       Alert: i++ = 0
2020.09.01 22:56:46.579 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.424 Test6 (EURAUD,M1)       Alert: i++ = 1
2020.09.01 22:56:47.428 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.765 Test6 (EURAUD,M1)       Alert: i++ = 2
2020.09.01 22:56:47.768 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:47.902 Test6 (EURAUD,M1)       Alert: i++ = 3
2020.09.01 22:56:47.906 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:48.453 Test6 (EURAUD,M1)       Alert: i++ = 4
2020.09.01 22:56:48.456 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 3 ms.
2020.09.01 22:56:48.516 Test6 (EURAUD,M1)       Alert: i++ = 5
2020.09.01 22:56:48.521 Test6 (EURAUD,M1)       Alert: Time[Test6.mq5 25: HistorySelect(0,INT_MAX)] = 4 ms.


すべてのティックに問題がある。


ZYはWin10をインストールし、LatencyMonはすべてがうまくいっていることを示しています。

 
現時点では、99%のケースでHistorySelect(0,INT_MAX)だけが使用されるべきだと考えています。他の選択肢を使わないようにする。
 
Renat Fatkhullin:

リリース後は、より効率的なMQL5関数の追加や、アルゴリズム取引の簡素化・高速化を実現するためのネイティブな注文・取引データ構造のオープン化など、多くの作業を開始する予定です。

MqlDeal、MqlOrder、MqlPositionがあれば最高です。もっとシンプルになるかもしれません。

 
fxsaber:
現時点では、99%のケースでHistorySelect(0,INT_MAX)を使用すればよいことがわかります。他の選択肢を使わないようにする。

履歴に何十万件も注文がある場合も、直前の履歴を取るより早くなるのでしょうか?

では、このような経緯を経なければならないのでしょうか?意味がないのです。

 
Dmi3:

履歴に何十万件も注文がある場合も、直前の履歴を取るより早いのでしょうか?

戦闘ロボットに0-INT_MAXのバリアントのみを残した。ラグに気づかなくなった。