Libreria di classi generiche - bug, descrizione, domande, caratteristiche d'uso e suggerimenti - pagina 13

 
Renat Fatkhullin:

Non puoi paragonare HistorySelect(mette l'intervallo di accesso in tester) e HistoryDealSelect(ticket), che cerca effettivamente un ticket specifico e lo mette in cache.

Per capire questo, la variante Clear è stata creata immediatamente. Per essere in grado di confrontare Clear vs Full allo stesso tempo.

 
fxsaber:
In questo modo la storia (soprattutto nel tester) viene solo integrata, i vecchi record non vengono cambiati. Intendo la variante Clear.


Nella realtà, sembra che anche quando un ordine è parzialmente eseguito e genera diversi trade, non entrerà nella storia fino a quando non sarà completamente riempito o cancellato. Cioè la regola della storia congelata è conservata.

Se scrivessimo software senza controlli, tutto sarebbe crollato da tempo.

Il software finanziario non ti permette di scrivere in modalità "cut corners". Si taglia in un posto, poi in un altro, e poi gli sviluppatori crederanno nel diritto di saltare i controlli difficili e il fallimento è inevitabile.

Nel tester, puoi ancora diminuire il controllo, ma nell'EA reale ci sono molti processi asincroni che lavorano sui continui cambiamenti dell'intero ambiente di mercato simultaneamente al lavoro del tuo EA. Non si può nemmeno pensare che qualcosa venga salvato tra le chiamate MQL5.

 
Renat Fatkhullin:

Se scrivessimo software senza controlli, tutto sarebbe crollato da tempo.

Il software finanziario non ti permette di scrivere in modalità "cut corners". Si taglia in un posto, poi in un altro, e poi gli sviluppatori crederanno nel diritto di saltare i controlli difficili e il fallimento è inevitabile.

Puoi ancora allentare i controlli nel tester, ma nel mondo reale ci sono un sacco di processi asincroni che lavorano per cambiare costantemente l'intero ambiente di mercato in parallelo con il tuo Expert Advisor. Fa paura pensare che qualcosa verrà salvato tra le chiamate MQL5.

Grazie per il chiarimento! Si spera che il tester stringa un po'.

 
fxsaber:

A causa di questa comprensione, la variante Clear è stata creata immediatamente. Così si potrebbe confrontare Clear vs Full allo stesso tempo.

Hai frainteso ciò che stavi testando. Questa non è in alcun modo Clear variant e non c'è alcuna relazione con il riferimento originariamente dichiarato a HistorySelect.

La tua variante Full significa essenzialmente una doppia chiamata (ticket lookup), la prima delle quali seleziona lo scambio nella cache e la seconda accede al risultato della cache. In un compito particolare, in cui si sa che esiste uno scambio, la prima chiamata select è ridondante. I metodi Get mettono implicitamente in cache il record interessato.



Per informazione, internamente dobbiamo esporre i codici dettagliati di Last Error (sotto la chiamata GetLastError()), in modo che gli sviluppatori possano ottenere le ragioni sottostanti al fallimento. Di solito ci sono diversi controlli di questo tipo per ogni chiamata in profondità nella piattaforma.
 
Renat Fatkhullin:

Lei fraintende ciò che sta testando. Non è in alcun modo un'opzione Clear e non c'è alcuna connessione con il riferimento originariamente dichiarato a HistorySelect.

Sembra che non l'abbiate notato.

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Libreria di classi generiche - bug, descrizione, problemi, casi d'uso e suggerimenti

fxsaber, 2017.12.08 22:46

  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
O forse stiamo parlando di cose diverse.
 
fxsaber:

Non sembra che tu l'abbia notato.

O forse stiamo parlando di cose diverse.

L'ho notato.

Quale storia precaricata? Ho fatto notare che HistorySelect nel tester è falso e non fa un vero trasferimento alla cache tutta la storia specificata nella query, ma segna solo le posizioni da & a nel database esistente di offerte. Pertanto, il costo è zero.

In GetDealProfitClear, fate esattamente una richiesta allo stesso posto usando HistoryDealGetDouble(Deal, DEAL_PROFIT), come nel vostro incompreso metodo GetDealProfitFull, che usa due metodi che sono esattamente gli stessi nella loro essenza fisica

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

Cioè, l'accesso alla cronologia nel tester è molto ottimizzato e si concentra davvero sul fatto che nessuno può cambiare la cronologia di trading tranne il tuo Expert Advisor (e i controlli sono ancora lì).

Nel terminale reale tutto è diverso e HistorySelect è costoso.

 
Renat Fatkhullin:

Capisco cosa intendi. Grazie per i dettagli! Mi chiedo quale sarà il risultato.

Forum sul trading, sistemi di trading automatico e test di strategia

Libreria di classi generiche - errori, descrizione, domande, peculiarità d'uso e suggerimenti

Renat Fatkhullin, 2017.12.08 23:19

Ho guardato il nostro codice - è possibile ottimizzare le chiamate alla base commerciale. Cercheremo di implementare per il rilascio della prossima settimana.

E l'argomento generico è molto utile, comunque! Lo seguirò con interesse.
 

Ho controllato l'implementazione diCHashMap
Mi è piaciuta, onestamente.

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


Ci sono alcuni suggerimenti per un possibile miglioramento:

1) A mio modesto parere, l'implementazione contiene una scelta non del tutto corretta della capacità - sia la dimensione iniziale 3 che quelle successive quando si ricostruisce la tabella hash.
Sì, è corretto che un numero primo dovrebbe essere scelto per l'uniformità della distribuzione.
Tuttavia, l'implementazione di CPrimeGenerator non soddisfa le aspettative e contiene omissioni di numeri primi.
Lo scopo di un tale "generatore" è chiaro - fornire un fattore di incremento dell'ordine di 1,2 con la generazione automatica di numeri primi.
Tuttavia, non è un coefficiente troppo piccolo? In C++ per i vettori, il coefficiente è di solito 1,5-2,0, a seconda della libreria (poiché influenza fortemente la complessità media dell'operazione).
La via d'uscita potrebbe essere un coefficiente costante seguito dall'arrotondamento del numero al primo tramite una ricerca binaria di una lista di numeri primi.
E una dimensione iniziale di 3 è troppo piccola, non viviamo nel secolo scorso.

2) Attualmente la tabella hash viene ricostruita (Resize) solo quando la capacità è piena al 100% (tutte le m_entries[] sono riempite).
A causa di questo, ci possono essere molte collisioni per chiavi che non sono distribuite in modo molto uniforme.
Come opzione, considerate l'introduzione di un fattore di riempimento che riduce il 100% del limite richiesto per eseguire una ricostruzione della tabella hash.

 
fxsaber:

E la versione classica di quanto rende nel suo caso?

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 микросекунд

È il tempo di esecuzione di printf.

In qualche modo avete capito stranamente il mio esempio. Non ho l'obiettivo di confrontare qualcosa con la funzionalità standard di MetaTrader. Si tratta solo di come organizzare algoritmi efficienti di associazioni e campionamenti di qualsiasi cosa con qualsiasi cosa a livello di utente. L'esempio di associazione di un numero di affare con un numero di ordine deve essere considerato solo come un esempio con un basso valore pratico, perché esiste un sistemaHistoryDealGetInteger(Deal, DEAL_ORDER).

 
fxsaber:

Bene, ecco un confronto tra le due metriche evidenziate. Si scopre che l'accesso alla HashMap è 4 volte più veloce di quello degli sviluppatori. Ma gli sviluppatori l'hanno già inclusa la storia...

Per la stessa ragione il confronto non è corretto. Come si può paragonare la CHashMap personalizzata e il lavoro con le funzioni di sistema per ottenere un ambiente di trading?