MT5 und Geschwindigkeit in Aktion - Seite 20

 
fxsaber:

Vielleicht gibt es eine schnellere Möglichkeit. Aber ein Schritt nach links in der Bedingung, was gezählt werden muss, und die Logik muss sich möglicherweise erheblich ändern. Im Allgemeinen nicht einfach.

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


Das ist keine Zwischenspeicherung, sondern eine Indizierung. Hier ist Caching (Teil des Codes):

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);
}

Der Code wurde hastig geschrieben und es gibt viel zu verfeinern, angesichts der häufigen ArrayResize, aber es aktualisiert genau den Cache, sortiert nach Closed. Wenn Sie später suchen wollen, verwenden Sie Ihren eigenen Index. Sie müssen aber jedes Mal nur einen kleinen Teil aktualisieren.
Ich weiß nicht mehr, warum dort"12*3600" steht, ich glaube nicht, dass alle Angebote an mich ausgegeben wurden.

 
Andrey Pogoreltsev:

Es handelt sich nicht um eine Zwischenspeicherung, sondern um einen Index.

Bitte sorgfältig lesen.

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

MT5 und Geschwindigkeit in Aktion

fxsaber, 2020.08.28 21:10

Reines MQL5 ist 100x langsamer als partielles (nur HistorySelectByPosition) Caching.

Architektonisch gesehen ist eine vollständige Zwischenspeicherung möglich - Sie müssen sorgfältig überlegen. Es gibt viele Fallstricke.

Hier ist Caching (Teil des Codes):

Der Code wurde hastig geschrieben und hat einige Dinge zu verbessern angesichts der häufigen ArrayResize, aber es aktualisiert Cache sortiert nach Closed. Wenn Sie später suchen wollen, verwenden Sie Ihren eigenen Index. Sie müssen aber jedes Mal nur einen kleinen Teil aktualisieren.

Dies ist nur ein Beispiel für eine frontale Geschichtsrettung ohne reale Gimmicks. Selbst in MT4Orders wird ein Teil des Caching mit einer Marge von fünf Sekunden durchgeführt...

Ich weiß nicht mehr, warum dort"12*3600" steht, ich glaube nicht, dass alle Gewerke an mich ausgegeben wurden.

Setzen Sie immer INT_MAX.

 
fxsaber:

Architektonisch gesehen erfordert die vollständige Zwischenspeicherung eine Menge Überlegungen. Es gibt eine Reihe von Fallstricken.

Es ist wirklich nichts Kompliziertes dabei. Sie können zum Beispiel stundenlang eine Stichprobe für alle Aufträge machen, die rückwirkend in der Geschichte auftauchen könnten (was übrigens sehr merkwürdig ist).

Dies ist nur ein Beispiel dafür, wie man die Geschichte frontal speichert, ohne irgendwelche Echtzeit-Gimmicks. Sogar in MT4Orders wird ein Teil des Caching mit einer Marge von fünf Sekunden durchgeführt...

Setzen Sie immer INT_MAX.

Ich verstehe nicht, was der Sinn dieser Verschiebung ist. Wenn es einen aktuellen Zeitstempel gibt, möchte ich mich relativ dazu bewegen, und es ist seltsam, dass man eine Zeit angeben muss, die nicht existiert. Ich möchte eine logische Erklärung haben.

Mein Cache funktioniert übrigens auf realen Konten mit 10k+ Trades.

Und die wichtigsten Bremsen im Code sind bisher die Netzwerkfunktionen.

 
Ich bin nur zufällig vorbeigekommen und dachte, ich fasse zusammen, was hier bereits angedeutet wurde. Wenn Sie um jeden Preis eine superschnelle Leistung benötigen, wird diese auf traditionelle Weise erreicht - auf Kosten anderer Ressourcen, z. B. des Arbeitsspeichers. Mit anderen Worten, es ist nicht notwendig, eine Schleife durch die gesamte Geschichte jedes Mal, wenn es erforderlich ist, um einige aggregierte Wert (kann nicht nur die Gesamtdauer) zu berechnen, und berechnen alle im Voraus in der "Array" (oder andere optimierte Datenstruktur) und dann nur zu erweitern. Und eine Abfrage eines Wertes über eine Positionskennung (oder einen anderen Parameter, über den die Aufschlüsselung erfolgt) wird zu einer Speicherzellenreferenz degenerieren. In der allgemeinsten Form - es ist so etwas wie OLAP (obwohl meine Umsetzung nicht fertig Online-Update), sondern für ein bestimmtes Problem getan werden kann und einfacher.
 

In der neuesten Beta-Version 2588 wird die HistorySelect-Funktion sehr gut zwischengespeichert und ist fast immer (außer beim ersten Mal) kostenlos.

Bis zur Veröffentlichung werden wir wahrscheinlich eine Reihe weiterer Verbesserungen vornehmen.



Wie ich bereits erklärt habe, gibt es im MT5 keine zusätzlichen Kosten für die automatische Erstellung von Markt-Snapshots für jeden EA vor jedem Ereignis, wie es im MT4 der Fall war. Dadurch werden Verzögerungen verringert und die Roboter können schneller arbeiten. Jeder Entwickler fragt genau das, was er braucht.

Daher sollten Sie sich darüber im Klaren sein, dass der Ansatz "Ich rufe HistorySelect für den gesamten Verlauf auf und mache dann sofort eine weitere Auswahl mit HistorySelectByPosition" die zuvor erstellten Zwischenspeicher des Verlaufs zerstört. Das ist ein Schuss ins eigene Knie.


Nach der Veröffentlichung werden wir intensiv daran arbeiten, neue, effizientere MQL5-Funktionen und offene native Order-/Handelsdatenstrukturen hinzuzufügen, um den Algotrading-Prozess zu vereinfachen und zu beschleunigen.

 
Renat Fatkhullin:

In der neuesten 2588-Beta-Version wird die HistorySelect-Funktion sehr gut zwischengespeichert und ist fast immer (außer beim ersten Mal) frei.

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


Ergebnis.

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.


Bei jeder Zecke gibt es ein Problem.


ZY hat Win10 installiert, LatencyMon zeigt, dass alles in Ordnung ist.

 
Im Moment sehe ich, dass in 99 % der Fälle nur HistorySelect(0, INT_MAX) verwendet werden sollte. Versuchen Sie, keine anderen Optionen zu verwenden.
 
Renat Fatkhullin:

Nach der Veröffentlichung werden wir intensiv daran arbeiten, neue, effizientere MQL5-Funktionen hinzuzufügen und native Order-/Handelsdatenstrukturen zu öffnen, damit der algorithmische Handel vereinfacht und beschleunigt werden kann.

MqlDeal, MqlOrder und MqlPosition wären toll. Es könnte sogar einfacher werden.

 
fxsaber:
Im Moment sehe ich, dass wir in 99 % der Fälle nur HistorySelect(0, INT_MAX) verwenden sollten. Versuchen Sie, die anderen Optionen nicht zu verwenden.

Wenn ich Hunderttausende von Aufträgen in meiner Historie habe, geht es dann auch schneller als mit der Last-Minute-Historie?

Muss ich diese ganze Geschichte also noch einmal durchgehen? Das macht keinen Sinn.

 
Dmi3:

Wenn ich Hunderttausende von Aufträgen in meiner Historie habe, ist es dann auch schneller, als wenn ich den Last-Minute-Verlauf nehme?

Nur noch 0-INT_MAX Variante bei Kampfrobotern. Ich habe die Verzögerungen nicht mehr bemerkt.

Grund der Beschwerde: