Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Nutzungsmöglichkeiten und Vorschläge - Seite 13

 
Renat Fatkhullin:

Sie können HistorySelect(legt den Zugriffsbereich in den Tester) und HistoryDealSelect(Ticket), das tatsächlich nach einem bestimmten Ticket sucht und es zwischenspeichert, nicht vergleichen.

Um dies zu verstehen, wurde die Clear-Variante sofort erstellt. Um gleichzeitig einen Vergleich zwischen Clear und Full anstellen zu können.

 
fxsaber:
Auf diese Weise wird die Historie (insbesondere im Tester) nur ergänzt, die alten Datensätze werden nicht verändert. Ich meine die Clear-Variante.


In der Praxis scheint es so zu sein, dass selbst wenn ein Auftrag teilweise ausgeführt wird und mehrere Abschlüsse generiert, er nicht in die Historie aufgenommen wird, bis er vollständig ausgeführt oder storniert wurde. D.h. die Regel der eingefrorenen Geschichte bleibt erhalten.

Wenn wir Software ohne Kontrollen schreiben würden, wäre schon längst alles zusammengebrochen.

Finanzsoftware erlaubt es Ihnen nicht, im "Spar"-Modus zu schreiben. Man kürzt an einer Stelle, dann an einer anderen, und dann glauben die Entwickler, dass sie das Recht haben, harte Prüfungen zu überspringen, und das Scheitern ist unvermeidlich.

Im Tester können Sie die Prüfungen noch entspannen, aber im echten EA gibt es eine Menge asynchroner Prozesse, die parallel zur Arbeit Ihres EAs an ständigen Veränderungen des gesamten Marktumfelds arbeiten. Es ist beängstigend zu denken, dass zwischen den MQL5-Aufrufen etwas gespeichert wird.

 
Renat Fatkhullin:

Wenn wir Software ohne Kontrollen schreiben würden, wäre schon längst alles zusammengebrochen.

Finanzsoftware erlaubt es Ihnen nicht, im "Spar"-Modus zu schreiben. Man kürzt an einer Stelle, dann an einer anderen, und dann glauben die Entwickler, dass sie das Recht haben, harte Prüfungen zu überspringen, und das Scheitern ist unvermeidlich.

Sie können die Kontrollen im Tester noch lockern, aber in der realen Welt gibt es eine Menge asynchroner Prozesse, die parallel zu Ihrem Expert Advisor an der ständigen Veränderung des gesamten Marktumfelds arbeiten. Es ist beängstigend zu denken, dass zwischen MQL5-Aufrufen etwas gespeichert wird.

Danke für die Klarstellung! Der Tester wird es hoffentlich ein wenig verschärfen.

 
fxsaber:

Aufgrund dieser Erkenntnis wurde sofort die Clear-Variante geschaffen. So können Sie gleichzeitig Clear und Full vergleichen.

Sie verstehen nicht, was Sie testen. Dies ist in keiner Weise eine eindeutige Variante und steht in keinem Zusammenhang mit dem ursprünglich angegebenen Verweis auf HistorySelect.

Ihre Full-Variante bedeutet im Wesentlichen einen doppelten Aufruf (Ticket-Lookup), wobei der erste Aufruf den Handel im Cache auswählt und der zweite auf das Ergebnis im Cache zugreift. Bei einer bestimmten Aufgabe, bei der bekannt ist, dass es einen Handel gibt, ist der erste Select-Aufruf überflüssig. Get-Methoden zwischenspeichern den betroffenen Datensatz implizit.



Zu Informationszwecken müssen wir intern detaillierte Last Error Codes offenlegen (unter GetLastError()-Aufruf), damit die Entwickler die Gründe für den Fehler erfahren können. Normalerweise gibt es mehrere solcher Prüfungen pro Aufruf tief in der Plattform.
 
Renat Fatkhullin:

Sie verstehen nicht, was Sie testen. Es handelt sich keineswegs um eine Clear-Option, und es besteht kein Zusammenhang mit dem ursprünglich angegebenen Verweis auf HistorySelect.

Es scheint, dass Sie das nicht bemerkt haben.

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Generische Klassenbibliothek - Bugs, Beschreibung, Probleme, Anwendungsfälle und Vorschläge

fxsaber, 2017.12.08 22:46

  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
Vielleicht reden wir aber auch über unterschiedliche Dinge.
 
fxsaber:

Sie scheinen es nicht bemerkt zu haben.

Vielleicht sprechen wir aber auch über unterschiedliche Dinge.

Ich habe es bemerkt.

Welche vorinstallierte Geschichte? Ich wies darauf hin, dass HistorySelect in der Tester ist gefälscht und nicht eine echte Übertragung auf den Cache alle der Geschichte in der Abfrage angegeben, sondern markiert nur Positionen von & bis in der bestehenden Datenbank der Geschäfte. Daher sind die Kosten gleich Null.

In GetDealProfitClear stellen Sie mit HistoryDealGetDouble(Deal, DEAL_PROFIT) genau dieselbe Anfrage wie in Ihrer falsch verstandenen Methode GetDealProfitFull, wobei es zwei Methoden gibt, die in ihrem Wesen genau gleich sind

return(HistoryDealSelect(Deal) ? HistoryDealGetDouble(Deal, DEAL_PROFIT) : 0)

Das heißt, der Zugriff auf die Historie im Tester ist sehr optimiert und konzentriert sich wirklich auf die Tatsache, dass niemand die Handelshistorie ändern kann, außer Ihrem Expert Advisor (und die Kontrollen sind immer noch da).

Im echten Terminal ist alles anders und HistorySelect ist teuer.

 
Renat Fatkhullin:

Ich verstehe, was Sie meinen. Vielen Dank für die Informationen! Ich frage mich, was das Ergebnis sein wird.

Forum zum Thema Handel, automatisierte Handelssysteme und Strategietests

Generische Klassenbibliothek - Fehler, Beschreibung, Fragen, Besonderheiten der Verwendung und Vorschläge

Renat Fatkhullin, 2017.12.08 23:19

Ich habe mir unseren Code angesehen - es ist möglich, die Aufrufe an die Handelsbasis zu optimieren. Wir werden versuchen, diese bis zur nächsten Woche zu implementieren.

Das generische Thema ist jedoch sehr nützlich! Ich werde es mit Interesse verfolgen.
 

Ich habe mir dieCHashMap-Implementierung angeschaut
und sie gefiel mir, ehrlich gesagt.

//+------------------------------------------------------------------+
//| Class CHashMap<TKey, TValue>.                                    |
//| Usage: Represents a collection of keys and values.               |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
class CHashMap: public IMap<TKey,TValue>
  {
protected:
   int               m_buckets[];                        
   Entry<TKey,TValue>m_entries[];
   int               m_count;
   int               m_free_list;
   int               m_free_count;
   IEqualityComparer<TKey>*m_comparer;
   bool              m_delete_comparer;

public:
                     CHashMap(void);
                     CHashMap(const int capacity);
                     CHashMap(IEqualityComparer<TKey>*comparer);
                     CHashMap(const int capacity,IEqualityComparer<TKey>*comparer);
                     CHashMap(IMap<TKey,TValue>*map);
                     CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer);
                    ~CHashMap(void);
   //--- methods of filling data 
   bool              Add(CKeyValuePair<TKey,TValue>*pair);
   bool              Add(TKey key,TValue value);
   //--- methods of access to protected data
   int               Count(void)                                       { return(m_count-m_free_count); }
   IEqualityComparer<TKey>*Comparer(void)                        const { return(m_comparer);           }
   bool              Contains(CKeyValuePair<TKey,TValue>*item);
   bool              Contains(TKey key,TValue value);
   bool              ContainsKey(TKey key);
   bool              ContainsValue(TValue value);
   //--- methods of copy data from collection   
   int               CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
   int               CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
   //--- methods of cleaning and deleting
   void              Clear(void);
   bool              Remove(CKeyValuePair<TKey,TValue>*item);
   bool              Remove(TKey key);
   //--- method of access to the data
   bool              TryGetValue(TKey key,TValue &value);
   bool              TrySetValue(TKey key,TValue value);

private:
   void              Initialize(const int capacity);
   void              Resize(int new_size,bool new_hash_codes);
   int               FindEntry(TKey key);
   bool              Insert(TKey key,TValue value,const bool add);
  };


Es gibt einige Vorschläge für mögliche Verbesserungen:

1) Meiner bescheidenen Meinung nach enthält die Implementierung eine nicht ganz korrekte Wahl der Kapazität - sowohl der anfänglichen Größe 3 als auch der nachfolgenden beim Wiederaufbau der Hashtabelle.
Ja, es ist richtig, dass für eine gleichmäßige Verteilung eine Primzahl gewählt werden sollte.
Die Implementierung von CPrimeGenerator entspricht jedoch nicht den Erwartungen und enthält Auslassungen von Primzahlen.
Der Zweck eines solchen "Generators" ist klar: Er soll einen Steigerungsfaktor in der Größenordnung von 1,2 mit automatischer Generierung von Primzahlen liefern.
Aber ist dieser Koeffizient nicht zu klein? In C++ für Vektoren beträgt der Koeffizient normalerweise 1,5-2,0, je nach Bibliothek (da er die durchschnittliche Komplexität der Operation stark beeinflusst).
Der Ausweg könnte ein konstanter Koeffizient sein, gefolgt von einer Rundung der Zahl auf eine Primzahl über eine binäre Suche in einer Liste von Primzahlen.
Und eine Anfangsgröße von 3 ist zu klein, wir leben nicht im letzten Jahrhundert.

2) Derzeit wird der Neuaufbau der Hash-Tabelle (Resize) nur ausgeführt, wenn die Kapazität zu 100% gefüllt ist (alle m_entries[] sind gefüllt).
Aus diesem Grund kann es bei nicht sehr gleichmäßig verteilten Schlüsseln zu vielen Kollisionen kommen.
Als Option könnte man die Einführung eines Füllfaktors in Erwägung ziehen, der 100 % um den erforderlichen Grenzwert für den Neuaufbau einer Hash-Tabelle reduziert.

 
fxsaber:

Und die klassische Frage: Wie viel bringt es in Ihrem Fall ein?

ulong GetDealOrder( const ulong Deal )
{
  return(HistoryDealSelect(Deal) ? HistoryDealGetInteger(Deal, DEAL_ORDER) : 0);
}
2017.12.08 17:56:05.184 OrdersID (SBRF Splice,M1)       Время выполнения запроса: 9 микросекунд

Das ist die Ausführungszeit von printf.

Sie haben mein Beispiel irgendwie seltsam verstanden. Ich habe nicht das Ziel, irgendetwas mit der Standardfunktionalität des MetaTrader zu vergleichen. Es geht nur darum, wie man effiziente Algorithmen für Assoziationen und Sampling von irgendetwas mit irgendetwas auf Ihrer Benutzerebene arrangiert. Das Beispiel der Verknüpfung einer Geschäftsnummer mit einer Auftragsnummer sollte nur als Beispiel mit geringem praktischen Wert betrachtet werden, da es ein SystemHistoryDealGetInteger(Deal, DEAL_ORDER) gibt.

 
fxsaber:

Nun, hier ein Vergleich der beiden hervorgehobenen Kennzahlen. Es stellt sich heraus, dass der HashMap-Zugriff 4 Mal schneller ist als der der Entwickler. Aber die Entwickler haben es bereits inklusive Geschichte...

Aus demselben Grund ist der Vergleich falsch. Wie können Sie die benutzerdefinierte CHashMap und die Arbeit mit Systemfunktionen vergleichen, um eine Handelsumgebung zu erhalten?

Grund der Beschwerde: