Progetto del consigliere - pagina 7

 
George Merts:

Cosa intende per "l'ATR non conta come indicatore"?

E in che modo "non è adatto come segnale d'entrata"? Sono un pazzo che usa "volatility breakthrough" usando solo questo indicatore...?

Credo che lei abbia la sua comprensione degli indicatori. Per me, un indicatore è un oggetto che può produrre un valore variabile in funzione del tempo. Infatti, anche un normale grafico a candele del prezzo è un indicatore. Ma per te è un'altra cosa... Di conseguenza, la nostra comprensione è diversa.

Essenzialmente
indicatore = uno strumento che mostra i cambiamenti di qualcosa.
In questo senso, l'ATP è un indicatore.
Quando guardi il grafico, noterai che l'indicatore è il più preciso (cioè, l'indicatore non è un indicatore autonomo - è un indicatore di posizione) e devi tenerlo sul mercato.

il mio rispetto.

 

Я не вижу особой разницы - как я понимаю, WS (WareStore, вероятно ?) - это все тот же мой дата-провайдер.

Questa è un'abbreviazione di WorkSymbol. L'abbreviazione breve è scelta di proposito, a causa del frequente riferimento a questo oggetto.

Ho il sospetto che ci debbano essere dei passi preliminari nell'inizializzazione dell'oggetto WS.

WS è un'istanza dell'oggetto CSymbol il cui costruttore usa di default il simbolo Symbol() corrente. Pertanto, WS non richiede l'inizializzazione dall'esterno. Viene semplicemente creato insieme alla classe della strategia.

Ci possono essere molti contenitori diversi di diversi simboli e diversi timeframes in un EA. L'ideologia del fornitore di dati permette di non duplicarli. Poiché in realtà - tutte le serie temporali sono memorizzate in esso, e i contenitori - basta puntare a quelli necessari.

Il risultato è un kernel di megaclasse, a cui accedono le classi esperte. Come si differenzia dal MQL di base, quando c'è il kernel MetaTrader e centinaia di sue funzioni, che vi accedono?

Se consideriamo MT4-5 stesso come il fornitore di dati, e la nostra classe è usata solo per fornire l'accesso - allora mi sembra irragionevole che secondo il tuo riferimento al prezzo Open dovremmo chiamare la funzione CopyOpen() per un valore.

Esattamente. Solo un tale appello garantisce l'unità della rappresentazione dei dati e la completa sincronizzazione degli stati. Non c'è bisogno di fare aggiornamenti di quotazioni (che possono essere dimenticati), non c'è bisogno di usare un mucchio di interruttori aggiuntivi, che inevitabilmente sorgono quando si crea un intermediario di archiviazione dei dati. Non c'è bisogno di cercare nel database i dati che corrispondono a quelli richiesti. Se il mio EA lo fa:

Trade.SellLimit(WS.High[1]);

Allora è garantito sapere che WS.High[1] restituirà il suo estremo precedente, non importa come l'ambiente di trading viene aggiornato. Sì, è troppo costoso chiamare CopyHigh ad ogni chiamata e copiare un singolo valore di doppio, ma è affidabile al 100%. Poiché le classi di copertura non immagazzinano dati, ma passano solo la chiamata alle funzioni di sistema, allora non possiamo avere una situazione in cui i dati immagazzinati non corrispondono all'ambiente corrente.

Penso anche che sia molto irragionevole dare pieno accesso globale a tutte le variabili in qualsiasi punto del programma; al contrario, cerco di avere accesso solo a quelle strutture e dati che sono necessari per una data azione in ogni luogo del programma. Tutto il resto deve essere inaccessibile. L'ideologia del fornitore di dati permette solo di controllare questo accesso.

Georg, in effetti, hai già creato questo accesso globale. Avete un grande fornitore di superclassi a cui tutti accedono. Questo è un grande pool globale di oggetti (indicatori, serie temporali, ecc.), che è raccolto sotto l'involucro di OOP. In altre parole, nell'esempio con il fornitore di dati, OOP si è trasformato in una finzione. Esiste formalmente, ma non esiste nella realtà.

 
Vasiliy Sokolov:

Georg, in effetti hai già creato questo accesso globale. Avete un unico grande fornitore di superclasse, a cui tutti possono accedere. Questo è un grande pool globale di oggetti (indicatori, serie temporali, ecc.) che è assemblato sotto l'involucro di OOP. In altre parole, nell'esempio con il fornitore di dati, OOP si è trasformato in una finzione. Formalmente c'è, ma non c'è nella realtà.

No, stavo confrontando le velocità di esecuzione quando metto un buffer nel provider di dati o ottengo i dati ogni volta tramite CopyXXX - ho ottenuto un accesso al mio buffer più veloce. Questo è il motivo per cui ho scelto i miei buffer, e Data Provider è solo uno stoccaggio centralizzato per questi buffer.

In effetti, la presenza del "livello" - questo stesso fornitore di dati porta un rischio di non sincronizzazione dei dati. Ma finora non ho mai incontrato un tale problema, ma il fornitore di dati salva la velocità in modo abbastanza chiaro. In realtà, penso che questo test sia stato già condotto da molte persone - tutto è risultato che quando si elabora un tick è più redditizio copiare i dati una volta e usarli, piuttosto che ogni volta al terminale per i dati.

Ora è diverso? E la velocità di un certo numero di chiamate tramite CopyXXX per ogni valore doppio è la stessa della velocità di una chiamata in una volta sola per tutto l'intervallo, e poi - chiamata al buffer per i valori?

 
George Merts:

No, stavo confrontando le velocità quando metto il buffer in Data Provider, o ottengo i dati ogni volta con CopyXXX - ho ottenuto un accesso più veloce al mio buffer. Questo è il motivo per cui ho scelto i miei buffer, e Data Provider è solo uno stoccaggio centralizzato per questi buffer.

In effetti, la presenza del "livello" - questo stesso fornitore di dati porta un rischio di non sincronizzazione dei dati. Ma finora non ho mai incontrato un tale problema, ma il fornitore di dati salva la velocità in modo abbastanza chiaro. In realtà, penso che molti abbiano già condotto questo test - tutti hanno ricevuto che quando si elaborano le zecche è più redditizio copiare i dati una volta e usarli, invece di andare al terminale ogni volta per i dati.

Ora è diverso? E la velocità del numero di chiamate via CopyXXX per ogni valore doppio è la stessa della velocità di una chiamata in una volta per l'intero intervallo, e poi - chiamata al buffer per i valori?

Senza dubbio, è molto più veloce copiare tutte le citazioni in una volta nella memoria interna dell'EA (fornitore di date) e poi chiamare i valori da esso, che chiamare costantemente il CopyBuffer. Ma questo è il prezzo di un sistema basato sullo stato. Fondamentalmente, tutto il nostro dominio - scrivere EAs, scripts, etc. - è la programmazione di sistemi basati su stati: abbiamo un ordine - elaborare le regole della sua gestione. Se non c'è un ordine - controlliamo le condizioni della sua apertura.

Come per CopyBuffer, copiare grandi porzioni di citazioni e misurare il guadagno di prestazioni è possibile solo in test sintetici. In pratica, nel 90% dei casi, l'Expert Advisor lavora con l'ultima barra di ogni tick o al momento dell'apertura di una nuova barra. Pertanto, i dati dell'ultima barra sono sempre richiesti, e c'è una chiamata costante della funzione CopyBuffer che copia l'ultima barra nella cache.

L'unico vero aumento di produttività è quando l'Expert Advisor richiede le ultime N barre, dove il numero N è molto maggiore di 1. Ma qual è la richiesta delle ultime N battute? È il lavoro nella finestra scorrevole (99% di tutto il lavoro dell'Expert Advisor). E una finestra scorrevole è un buffer circolare nella sua essenza. Pertanto, quando si richiedono le ultime N barre, in realtà, è necessario aggiornare o aggiungere solo una, l'ultima barra. Cioè tutta questa roba con la copia di blocchi di dati è una storia molto bella, ma non funziona nell'area tematica per cui è stata creata, mentre sono i ring buffer che funzionano, e con successo.

Ora il mio CSymbol funziona semplicemente passando l'indice giusto. Ma posso aggiornarlo in modo che memorizzi N ultime barre e N sarà scelto da CSymbol stesso, a seconda dell'indice massimo richiesto. E poi, senza alcuna modifica esterna, CSymbol su alcuni compiti, lavorerà molte volte più velocemente della chiamata permanente di CopyBuffer. Questo è il potere dell'OOP. Dopo un certo overhead associato all'uso di wrapper aggiuntivi, arriva un salto qualitativo, quando si può ridurre drasticamente l'uso della memoria o il tempo della CPU grazie agli algoritmi adattivi.

 
Gregory Kovalenko:
Salve.
Quando la quantità di codice cresce, a volte ci sono difficoltà e confusione.
Ho visto codice EA con un enorme numero di linee di codice, mi chiedo come vengono progettati gli EA complessi, forse ci sono alcuni strumenti o tecniche per lavorare con algoritmi così complessi?

Scrivo enormi blocchi di codice che occupano centinaia di righe. Quasi nessun commento. Senza OOP. Il codice è in russo. Tutto funziona in modo molto efficiente. Non ho problemi di orientamento nel programma, anche se ci sono circa 100 file collegati. Probabilmente perché mi sono abituato e mi sono ricordato tutto molto tempo fa. La cosa principale è conoscere e capire il vostro programma, tutto il resto è secondario. Imho.

 
Реter Konow:

Scrivere enormi blocchi di codice che occupano centinaia di righe. Quasi nessun commento. Nessun OOP. Codice in russo. Tutto funziona in modo molto efficiente. Non ho problemi di orientamento nel programma, anche se ci sono circa 100 file collegati. Probabilmente perché mi sono abituato e mi sono ricordato tutto molto tempo fa. La cosa principale è conoscere e capire il tuo programma, tutto il resto è secondario. La mia sensazione è che la cosa più importante è conoscere il proprio programma, e il resto è secondario.

Sei passato da 1C a MQL?
 
Vasiliy Sokolov:
Sei passato da 1C a MQL?

Sono un autodidatta. Il primo linguaggio di programmazione che ho imparato è stato MQL4. Dopo di che, ho fatto un po' di pratica in C# e C++.


Mai sentito parlare di 1C. Che cos'è?

 
Vasiliy Sokolov:

Come per CopyBuffer, copiare grandi porzioni di citazioni e misurare il guadagno di prestazioni è possibile solo in test sintetici. In pratica, nel 90% dei casi, l'Expert Advisor lavora con l'ultima barra di ogni tick, o al momento dell'apertura di una nuova barra. Pertanto, i dati dell'ultima barra sono sempre richiesti e c'è una chiamata costante del CopyBuffer, che copia l'ultima barra nella cache.

Quindi, abbiamo bisogno della velocità nel "test sintetico" - la velocità diventa critica quando si cercano le varianti nel tester di strategia. È il tester di strategia per me è un "collo di bottiglia" dove abbiamo bisogno di velocità.

Proprio nel lavoro reale - la velocità di accesso diretto ai dati tramite CopyXXX ogni volta è sufficiente. Ma, per il prog nel tester - la differenza di velocità è molto importante.

 
I commenti non pertinenti a questo argomento sono stati spostati in"OOP vs programmazione procedurale".
 
George Merts:

Ma è nel "test sintetico" che abbiamo bisogno di velocità - la velocità diventa critica quando si provano le opzioni nello strategy tester. È il tester di strategia per me è un "collo di bottiglia" dove è richiesta la velocità.

Proprio nel lavoro reale - la velocità di accesso diretto ai dati tramite CopyXXX ogni volta è sufficiente. Ma, per il prog. in tester - la differenza di velocità è molto importante.

Per spiegare in parole più semplici: alla base del vostro dataprovider c'è la funzione CopyXXX, che copia l'ultimo carattere. Alla base del mio CSymbol c'è anche CopyXXX, che copia lo stesso ultimo carattere. Entrambe le funzioni sono lente. Quindi sia il tuo codice che il mio sono lenti, poiché la chiamata CopyXXX non può essere aggirata. Ma il mio codice è più semplice e più piccolo. Allora perché tutta questa costruzione a più piani sopra il CopyXXXXX, se non risolve il problema del CopyXXX stesso?

Motivazione: