English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Il lettore di trading basato sulla cronologia delle operazioni

Il lettore di trading basato sulla cronologia delle operazioni

MetaTrader 5Trading | 17 dicembre 2021, 15:10
134 0
Mykola Demko
Mykola Demko


Vedere una volta è meglio che sentire due volte

L'analisi visiva della cronologia di trading è una parte significativa del lavoro analitico di un trader. Se così non fosse, non ci sarebbe l’analisi tecnica a trasformare il mondo delle cifre nel mondo delle immagini. Beh, è chiaro dal momento che l'80% della percezione umana avviene attraverso gli occhi. La statistica, che generalizza le informazioni, non ci dà molti dettagli. E solo la visualizzazione con la sua percezione intuitiva del mondo delle cifre può attraversare le t. Dicono che vedere una volta è meglio che sentire due volte.

In questo articolo non tratteremo di come scrivere un Expert Advisor destinato all'automazione della visualizzazione visiva della cronologia di trading. Discuteremo le questioni del passaggio di informazioni tra gli oggetti, della pianificazione di enormi applicazioni, della gestione di grafici, della sincronizzazione di informazioni di simboli diversi, ecc.

Come da tradizione, all'inizio voglio parlarvi dei vantaggi dell'applicazione del lettore e dello script associato, quindi passeremo all'analisi del codice.


Esecuzione delle operazioni sullo Strategy Tester di MetaTrader 5

Il funzionamento del lettore si basa sul report HTML di MetaTrader 5. Così la cronologia dell’Automated Trading Championship 2010 si può ottenere accedendo a un account necessario di ATC-2010 e salvando la cronologia di trading come report HTML.

Poiché il server dell’Automated Trading Championship 2008 è fermo, non siamo in grado di procedere allo stesso modo. Il sito contiene il resoconto generale di tutti i concorrenti come fosse un unico archivio zip. Automated_Trading_Championship_2008_All_Trades.zip

L'archivio "Automated Trading Championship 2008 All Trades.zip" deve essere decompresso nella cartella \Files della directory di installazione di MetaTrader 5.

Per analizzare la cronologia dell’ Automated Trading Championship 2008, è necessario eseguire lo script Report Parser MT4 che analizzerà la cronologia, effettuare una selezione per il login specificato e salvarlo in un file binario. Questo file binario viene letto dall’Expert Advisor Player Report.

L’EA Player Report deve essere eseguito nello strategy tester con l'accesso necessario specificato. Al termine del test, salva un report in formato HTML. L'account di accesso specificato non influisce sul risultato del test, ma verrà visualizzato nel report come parametro di input "login". Questo permette un ulteriore discernimento delle relazioni. Poiché i report sono creati dallo stesso Expert Advisor, si consiglia di fornire un nome diverso da quello predefinito.

Lo script Report Parser MT4 possiede anche il parametro di input "login" in cui è necessario specificare il login di un concorrente di cui si desidera visualizzare la cronologia. Se non conosci il login del concorrente, ma conosci il suo nickname, avvia lo script con il valore zero (predefinito) del login. In questo caso, lo script non emetterà una selezione tramite un login; creerà solo un file csv in cui tutti gli accessi sono elencati in ordine alfabetico. Il nome del file è "Automated Trading Championship2008 All Trades_plus". Non appena trovi il partecipante che ti occorre in questo file, esegui nuovamente lo script con il login specificato.

Così il tandem dello script Report Parser MT4 e dell’EA Player Report crea il report html standard dello Strategy Tester di MetaTrader 5 sulla base della cronologia di trading nel formato MetaTrader 4.

L’Expert Advisor Player Report non esegue le operazioni esattamente come sono state eseguite nella realtà, ma le rende in maniera approssimativa. Le motivazioni comprendono quotazioni diverse, arrotondamento del tempo in minuti nel report e slippage durante l'esecuzione. Nella maggior parte dei casi, la differenza è di diversi punti e succede nel 10% delle operazioni di trading. Ma è sufficiente ridurre il profitto nello strategy tester da ~ 170 mila a ~ 160 mila, per esempio. Tutto dipende dal volume di operazioni con slippage.


Funzionamento del segnale.

Come accennato in precedenza, il lettore può essere utilizzato per guardare la cronologia di trading dell’ Automated Trading Championship 2008 utilizzando delle applicazioni aggiuntive, mentre l’Automated Trading Championship 2010 può essere visionato direttamente.

Inoltre, il lettore supporta tutti i rapporti MetaTrader 5, quindi è possibile guardare la cronologia di trading di qualsiasi Expert Advisor eseguito nello strategy tester o la cronologia del trading manuale che non è formattata dal tester, ma salvata come report dalla scheda "Cronologia" della finestra "Toolbox".

Parametri dell’Expert Advisor Player History Trades exp v5 :

Un report dello Strategy tester di MetaTrader 5 viene utilizzato come file di input per il lettore della cronologia delle operazioni. "name of html file of the strategy tester report" è il nome di un file di report che deve essere specificato come parametro di input dell’EA Player History Trades exp v5. Quando si avvia il lettore, un utente è in grado di specificare un periodo di lettura nelle variabili di input "inizio della cronologia" e "fine della cronologia".

Se queste variabili non sono impostate, il lettore le prenderà dalla cronologia di trading a partire dalla prima operazione e terminando con l'ultima. Il numero di simboli utilizzati per il trading non fa alcuna differenza. Viene considerato solo il tempo del primo e dell'ultimo affare sul conto.

Inoltre, un utente è in grado di impostare i nomi dei simboli i cui grafici devono essere analizzati. I nomi devono essere specificati come enumerazione nella variabile "elenco dei grafici obbligatori". L'analisi di questa variabile non è sensibile al maiuscolo e al tipo di separatore. Se la variabile non è impostata, vengono aperti tutti i simboli usati sul conto. E a volte ce ne sono molti.

Ad esempio, Manov ha utilizzato 12 coppie di valute nel suo trading. Raccomando di impostare non più di quattro simboli alla volta. In primo luogo, è conveniente organizzarli; in secondo luogo, troppi grafici rallentano la velocità di riproduzione. Poiché ogni simbolo viene elaborato nel ciclo generale, l'aumento del numero di simboli porta a rallentare la generazione di tick.

Il lettore funzionerà anche se si specifica un simbolo che non è stato utilizzato nel trading. In questo caso, il grafico non mostrerà alcuna operazione, ma sarà proprio come gli altri grafici. Inoltre, avrà l'indicatore di saldo allegato; tuttavia, visualizzerà solo la cronologia del saldo generale in una qualsiasi delle sue varianti.

Ho intenzionalmente saltato la descrizione del parametro "Elimina grafico quando si elimina l'EA". Questo parametro riguarda il comportamento dell'Expert Advisor, non la sua gestione. Il punto è che l'Expert Advisor analizza molte informazioni per il suo funzionamento. Ho deciso che alcune informazioni che l'EA possiede saranno utili per l'analisi sotto forma di file. L'Expert Advisor crea dei file csv che contengono le operazioni di trading per ogni simbolo e il file con i saldi sincronizzati di tutti i simboli, il che può essere utile per rilevare un simbolo in un carrello multivaluta.

La stessa variabile viene utilizzata anche per la cancellazione dei grafici aperti automaticamente dall'Expert Advisor. Come da tradizione, l'EA deve pulire il suo ambiente di lavoro alla fine dell'operazione. Ma se un utente desidera analizzare da vicino un grafico senza il controllo dell’EA, dovrà avviare l'EA con il parametro "elimina grafici quando si elimina l'EA" impostato su "false".

I seguenti parametri non sono molto importanti.

Il periodo del generatore imposta il parametro iniziale del generatore di tick. Il termine "tick" qui non è usato nel suo significato classico, ma indica la variazione di livello. Nell'Expert Advisor, i tick vengono generati in base a quattro punti di barre. Il parametro "Periodo del generatore" imposta lo stato iniziale del generatore. Inoltre, sarai in grado di modificare questo parametro nel lettore durante il suo funzionamento.

Perché non generiamo tutti i periodi a partire da M1? Perché dobbiamo cambiare il periodo del generatore? La questione è che le barre di intervalli di tempo maggiori contengono molte barre M1, quindi potremmo aver bisogno di accelerare il processo di generazione. Ecco perché viene implementata la possibilità di modificare il periodo. Solo alcuni tempi vengono implementati nel generatore. Il modo per modificarlo nel codice verrà descritto in seguito.

Il parametro "font dei commenti alle operazioni" può essere utile, ad esempio, quando i commenti alle operazioni impediscono la visualizzazione delle operazioni stesse. Se imposti la dimensione su 1, l'iscrizione apparirà come una linea sottile e non impedirà la visualizzazione. A questo punto sarai in grado di vedere il volume dell'operazione e la posizione nella scheda "Elenco di oggetti" mentre scopri il nome dell'oggetto dalla descrizione comando.

La cronologia di trading viene tracciata con accordi separati, ma la linea tracciata dipende dal tipo di posizione.

Utilizzando il "colore delle operazioni di acquisto" e il "colore delle operazioni di vendita" è possibile impostare i colori desiderati.

Visualizzazione della cronologia di trading

Nello screenshot sopra, puoi vedere che il livello di posizione spesso differisce dal livello dell’operazione.

Ma il profitto è calcolato sulla base del livello di posizione. Così ho deciso di visualizzare la posizione con una linea di tendenza e collegare i livelli di posizione e eseguire le transazioni utilizzando una linea verticale. Il commento vicino al livello di posizione visualizza le seguenti informazioni:

[deal volume|position volume]

Se il tipo di operazione non corrisponde al tipo di posizione (ad esempio, se c'è una chiusura parziale), i volumi verranno visualizzati con segni aggiuntivi:

[<deal volume>|position volume]

Al primo posto puoi vedere il volume dell'operazione così come viene visualizzato nel report di trading; il volume della posizione è calcolato sulla base dello stato precedente della posizione e delle modifiche apportate dall'operazione.

Il parametro "numero di velocità" regola il numero di passaggi per diminuire la velocità di riproduzione. Il lettore viene avviato alla massima velocità. Inoltre, sarai in grado di diminuirlo e aumentarlo entro il valore del parametro "numero di velocità". Così il pulsante di velocità e il periodo del generatore compongono una gamma completa di strumenti per gestire la velocità di riproduzione della cronologia di trading.

L'ultimo parametro è la "dimensione invertita del pulsante di avanzamento". L'ho creato per gli utenti che preferiscono i grandi pulsanti della barra di avanzamento. In generale, il mio obiettivo era quello di evitare di nascondere il grafico dietro i controlli. Ecco perché il parametro "dimensione invertita del pulsante di avanzamento" è impostato su 8.

Passiamo ora ai controlli del lettore.

Controlli del lettore

La velocità è controllata utilizzando le frecce sinistra e destra. La modalità di controllo dipende dallo stato del pulsante centrale (quadrato). Nello stato non premuto cambia la velocità, nello stato premuto cambia il periodo del generatore.

L'oggetto di controllo dell’indicatore di bilanciamento viene visualizzato come un ovale completo, ma in realtà è costituito da due grandi pulsanti che superano di gran lunga i bordi delle sue dimensioni visive. Il pulsante sinistro è destinato all'aggiunta e all'eliminazione dell'indicatore di bilanciamento dal grafico e il pulsante destro controlla il contenuto dei dati.

Nello stato "Tutti", vengono visualizzate le informazioni sul saldo totale dell'account; lo stato "Somma" è destinato alla visualizzazione di un campionamento del saldo per il simbolo del grafico su cui viene eseguito l'indicatore. Il controllo dell'indicatore è asincrono, il che significa che l'indicatore può essere eseguito su un grafico e non eseguito su un altro. 

L'indicatore di bilanciamento

L'obiettivo di controllare l'indicatore di bilanciamento è l'unica eccezione nella sincronizzazione dei grafici; tutti gli altri oggetti dei controlli vengono sincronizzati. In altre parole, le modifiche apportate per un simbolo vengono automaticamente apportate agli altri simboli.

Il plays/stop visualizza quale operazione verrà eseguita non appena lo si preme. Durante la riproduzione, vengono visualizzate due piccole righe che mostrano che l'operazione verrà sospesa se vengono premute. Viceversa, il triangolo viene visualizzato nello stato in pausa. Pertanto, se lo si preme, il lettore riprenderà le sue funzioni.

La linea di avanzamento è composta da 100 pulsanti di controllo realizzati come dei trigger: se viene premuto un pulsante, tutti gli altri pulsanti diventano non premuti. Poiché ci sono 100 pulsanti, il periodo di riproduzione è diviso in 100 parti. Se il numero di barre non è divisibile per 100, il resto viene aggiunto all'ultima parte. Ecco perché le impostazioni includono i parametri "inizio della cronologia" e "fine della cronologia". Modificando questi parametri, è possibile passare al periodo cronologico necessario.

Premendo un pulsante, un utente cambia la data del generatore interno di tick e naviga nella barra dello zero. Se non viene premuto, ma il tempo interno del generatore si è già spostato all'esterno del pulsante attivo, il giocatore eseguirà da solo l'accensione corrispondente.

Quindi l'oggetto "linea di avanzamento" è sia l'indicatore del progresso che il controllo attivo della navigazione. Gli oggetti di controllo del lettore vengono automaticamente nascosti ed espansi al centro del grafico; quindi, se è necessario premere un determinato pulsante della linea di avanzamento, occorre espandere il grafico a schermo intero.

Ora parliamo del comportamento dei grafici gestiti dal lettore. Il lettore esegue la sincronizzazione di tutti i grafici, ma ciò non significa che qualsiasi cambiamento di scala, tipo di grafico, combinazione di colori, spostamento della barra dello zero, ecc. eseguito sul grafico principale venga ripetuto negli altri grafici.

Le modifiche includono la modifica dell'intervallo di tempo. Qui dovremmo notare che il grafico che il lettore considera il principale è quello in cui vengono visualizzati i controlli, non quello con la linea di attività in blu. Di solito è lo stesso grafico, ma non è sempre così. Per attivare un grafico, clicca su di esso nel campo del grafico.

C'è una caratteristica che riguarda l’uso del lettore. Se due oggetti si trovano nello stesso campo, i pulsanti smettono di funzionare. Ecco perché a volte, quando la linea di offerta attraversa il campo del lettore, per premere un pulsante dovrai passare a un altro grafico o modificare la scala verticale del grafico.



Il video mostra la riproduzione del trading di Manov,, uno dei partecipanti all’ ATC 2010. Per farlo, mi sono collegato al suo account nel client terminal utilizzando i parametri login =630165 e password =MetaTrader. Il report di trading è stato salvato con il nome ReportHistory-630165.html nella cartella terminal_data_folder\MQL5\Files. È possibile scaricare questo file come archivio e decomprimerlo nella cartella specificata.


Preparazione all'avvio

  1. Per far funzionare tutto, scarica player_history_trades.zip ed estrailo nella cartella terminal_data_folder/MQL5/Indicatori.
  2. Apri la cartella copiata Player History Trades e compila quattro file nella sua directory principale su MetaEditor. La sequenza di compilazione dei file non ha importanza.
  3. Assicurati che il periodo cronologico richiesto per tutti i simboli nel report di trading sia disponibile sull’ intervallo di tempo М1. Per farlo, apri manualmente il grafico necessario con l'intervallo di tempo M1, posiziona una linea verticale e apri l’ Elenco di oggetti utilizzando la combinazione di tasti Ctrl + B del menu di scelta rapida. Quindi modifica la data della linea verticale alla data di inizio del trading.
  4. Poi premi il pulsante "Mostra". Se non ci sono quotazioni, ci possono essere due ragioni. O non vengono scaricati o il parametro "Barre massime nel grafico" è troppo piccolo. Per vedere, vai su Strumenti->Opzioni->Grafici.

Ora tutto dovrebbe funzionare.


Inizio dello sviluppo

Per sviluppare un'applicazione, è necessario disporre di un piano, il quale si trasforma ulteriormente in un diagramma a blocchi mentre lo si studia e, infine, si trasforma nel codice. Ma il progetto stesso inizia ancora prima. Il punto iniziale di qualsiasi progetto sono le proprietà dell'applicazione richieste dall'utente. Quindi quali proprietà dovrebbe avere il lettore della cronologia di trading? 

  1. Essere multivaluta.
  2. Apertura automatica dei grafici richiesti.
  3. Comoda interfaccia di navigazione e possibilità di scorrere la cronologia in entrambe le direzioni.
  4. Visualizzazione sincrona su tutti i grafici.
  5. Avvio/pausa della riproduzione.
  6. La possibilità di scegliere (oltre alla modalità predefinita) il numero e i simboli dei grafici visualizzati.
  7. La possibilità di scegliere (oltre alla modalità predefinita) il periodo in cui il lettore lavorerà.
  8. Visualizzazione della cronologia delle operazioni su un grafico.
  9. Visualizzazione della cronologia di bilanciamento e del patrimonio netto.
  10. Visualizzazione separata del saldo (patrimonio netto) di un simbolo e del saldo totale (patrimonio netto) di un conto.

I primi quattro elementi determinano il concetto generale. Le altre proprietà determinano la direzione di implementazione dei metodi.

Il piano generale di funzionamento del lettore:

  1. Caricare un report HTML;
  2. Analizzare le operazioni e ripristinare la cronologia delle posizioni;
  3. Disporre le operazioni come in una coda di ordini per l'apertura/chiusura;
  4. A un comando dell'utente, visualizzare le dinamiche della cronologia delle operazioni con il calcolo dei tassi necessari sotto forma di indicatori (grafici di patrimonio netto, drawdown, ecc.);
  5. Organizzare la visualizzazione di un pannello informativo sul grafico con le altre tariffe.

Inoltre, è necessario uno speciale Expert Advisor per il trading nello strategy tester secondo un report di MetaTrader 4:

  1. Le operazioni analizzate devono essere scritte come file di dati binari per l'Expert Advisor;
  2. Creare il report dello Strategy Tester di MetaTrader 5.

Questo è lo schema generale con la specifica dei requisiti per iniziare lo sviluppo. Se ce l'hai, puoi pianificare la scrittura del codice dall'alto verso il basso, dal concetto all'implementazione della funzionalità.

Per rendere l'articolo troppo vasto, più avanti descriverò solo le parti più significative del codice. Non dovresti incontrare problemi durante la lettura del codice poiché è ben commentato.


Ordini e operazioni

Attualmente, ci sono due concetti di trading. Il vecchio concetto che viene utilizzato su MetaTrader 4 e quello utilizzato per le offerte reali su MetaTrader 5, il cosiddetto concetto di "netting". La descrizione dettagliata della differenza tra di loro è fornita nell'articolo Orders, Positions, and Deals in MetaTrader 5.

Descriverò solo le differenze più significative. Su MetaTrader 4, un ordine può essere rappresentato come un contenitore che memorizza le informazioni sull'ora di apertura, il prezzo di apertura e il volume delle transazioni. E mentre la porta del contenitore è aperta, lo stato di trading è attivo. Non appena chiudi il contenitore, tutte le informazioni vengono spostate nella cronologia.

Su MetaTrader 5, le posizioni sono utilizzate come contenitori. Ma la differenza significativa è l'assenza di cronologia delle posizioni. C'è solo la cronologia comune di ordini e operazioni. E sebbene la cronologia contenga tutte le informazioni necessarie per ripristinare la cronologia delle posizioni, è necessario dedicare un po' di tempo alla riorganizzazione mentale.

Puoi scoprire a quale posizione appartiene un ordine o un'operazione selezionata utilizzando rispettivamente gli identificatori ORDER_POSITION_ID e DEAL_POSITION_ID. Quindi, per convertire la cronologia in un formato adatto a MetaTrader 5, dividerò gli ordini della cronologia di MetaTrader 4 in due operazioni separate: apertura e chiusura delle transazioni.


Il parser HTML

Per coloro che non hanno familiarità con lo slang informatico, spiegherò cosa significa la parola parse. Per parsing si intende l'analisi sintattica (grammaticale o lessicale) di un testo o di qualsiasi sequenza di lessemi (simboli, parole, byte, ecc.) che controlla la corrispondenza del testo di input a una grammatica specificata e compone un albero di analisi, in base al quale è possibile eseguire ulteriori calcoli o trasformazioni.

Nel parser vengono utilizzate due grandi classi, CTable e CHTML. L'uso della classe CTable è descritto in dettaglio nell'articolo Electronic Tables in MQL5, ecco perché non ne parlerò di nuovo.

Per il parsing html, ho sviluppato la classe CHTML. Secondo la mia idea originaria, avrei dovuto inserire la sua descrizione in un articolo a parte. Ma la classe è troppo semplice per scriverci su un articolo, quindi ne darò una descrizione concisa.

Il concetto generale della classe può essere descritto con il termine 'tag'. Un tag può essere rappresentato come una funzione con degli involucri. Ad esempio, il Tag(header,casket), dove 'header' è il titolo del tag (le variabili di tag che controllano l'aspetto della pagina sono solitamente specificate lì) e 'casket' è il contenuto del contenitore di tag. Tali tag sono costituiti dall'intero linguaggio HTML.

La struttura generale della classe può essere rappresentata come una chiamata di oggetti in tre fasi. L'istanza della classe CHTML crea gli oggetti di tutti i possibili tag nel suo nucleo. Le funzioni dei tag sono create da un modello e differiscono l'una dall'altra solo per i loro nomi e le impostazioni di due flag.

Un flag determina la presenza di intestazione e l'altro determina la presenza di un casket. Questi flag consentono di presentare tutti i tag con una struttura comune. Ogni istanza di tag crea un'istanza della classe CTegs nel proprio nucleo. Questa classe contiene metodi comuni per tutti i tag ed esegue le operazioni principali di ricerca di un tag necessario nel nucleo di un documento.

Quindi, ecco come appare la chiamata in tre fasi:

h.td.base.casket

Questa iscrizione significa che l'oggetto 'h' chiama il valore della variabile 'casket' attraverso l'oggetto 'td' (che è un'istanza dell'intestazione <td >casket</td> tag) attraverso l'oggetto nidificato 'base' (che è un oggetto della classe CTegs).

La classe include anche metodi di ricerca dei tag che sono combinati nel metodo pubblico,

h.td.Search(text,start);

il quale restituisce il punto di ricerca della fine del tag e riempie le variabili 'header' e 'casket'.

Le altre funzioni preparate nella classe non vengono utilizzate, quindi non le descriverò: ci sono ancora molte cose interessanti da dire.

Alla fine della descrizione del lavoro con documenti HTML, voglio menzionare che nell'articolo vengono utilizzati due tipi di parser; differiscono solo per il tipo di salvataggio delle informazioni ottenute dal file. Il primo tipo utilizza il salvataggio dell'intero documento in una singola variabile del tipo 'stringa' e viene utilizzato nel lettore. Il secondo tipo utilizza l'analisi riga per riga del report. Viene utilizzato nello script per preparare la cronologia della Championship 2008.

Perché si utilizzano due approcci? Perché, per il corretto funzionamento delle funzioni della classe CTegs, l'intero tag deve essere inserito nella stringa analizzata. E non è sempre possibile. Ad esempio, nel caso di tag come table, html, body (che sono multiriga). Una variabile del tipo stringa consente di memorizzare (secondo i miei calcoli) 32750 simboli senza i simboli di tabulazione. E con '\r' (dopo ogni 32748 simboli) sono riuscito a memorizzare fino a 2000000 di simboli; dopo aver raggiunto questo valore, ho interrotto i miei tentativi. Molto probabilmente è possibile memorizzare più simboli.

Allora perché usiamo due approcci? Il punto è che per un parser universale del lettore è necessario trovare una tabella adeguata. Le tabelle richieste per il report del tester e per il report della cronologia delle operazioni si trovano in luoghi diversi. Per mantenere la versatilità (affinché il parser comprenda entrambi i rapporti), uso lo schema di ricerca della tabella con il tag 'td' contenente le "operazioni".

La struttura del report della Championship 2008 è nota e non è necessario cercare la tabella necessaria. Tuttavia, il documento del report è enorme (35 MB) e posizionarlo per intero su una singola variabile richiederebbe molto tempo. Questa situazione stabilisce il secondo approccio all'analisi.


Il lettore

I 10 requisiti per il lettore sono descritti nella sezione "Inizio dello sviluppo". Poiché il multivaluta è al primo posto, l'Expert Advisor deve gestire i grafici. Sarà logico se ogni grafico viene elaborato da un oggetto separato che ha tutte le funzionalità necessarie per il funzionamento del lettore.

Dal momento che lavoriamo con la cronologia, abbiamo bisogno di un esempio separato di cronologia per un funzionamento ininterrotto invece di sperare di poterlo ottenere ogni volta che vogliamo. Inoltre, ottenere ripetutamente la stessa cronologia sarebbe uno spreco rispetto a mantenerla nel lettore. Alla fine, otteniamo il seguente schema:

Lo schema generale del lettore della cronologia di trading

La programmazione orientata agli oggetti (OOP) consente di scrivere applicazioni piuttosto enormi utilizzando i sistemi a blocchi. La parte di codice sviluppata dell’Expert Advisor può essere prima scritta in uno script, sottoposta a debug e quindi collegata a un Expert Advisor con un adattamento minimo.

Tale schema di sviluppo è conveniente perché sei sicuro che il codice connesso non contiene errori (perché funziona nello script senza errori) e qualsiasi bug trovato è un errore di adattamento. Non c'è un tale vantaggio quando un codice è scritto dal basso verso l'alto, quando si descrive tutto in un unico posto come una procedura. E un nuovo bug può apparire in qualsiasi punto dell'applicazione.

Quindi la programmazione dall'alto verso il basso ha dei vantaggi in termini di semplicità e velocità di scrittura di un'applicazione. Potresti chiederti "cosa c’è di semplice qui?" e io ti risponderei con un'allegoria: è difficile imparare ad andare in bicicletta ma ,una volta imparato, non te ne accorgerai nemmeno. Ti godrai solo una pedalata veloce. Una volta appresa la sintassi OOP, otterrai un grande vantaggio.


Per continuare la narrazione, ho bisogno di descrivere tre termini di OOP: Associazione, Aggregazione e Composizione.

  • Associazione, indica una connessione tra oggetti. Aggregazione e Composizione sono casi particolari di associazione.
  • L'aggregazione implica che gli oggetti siano connessi con la relazione "parte di". L'aggregazione può essere multipla, cioè un oggetto può essere aggregato in più classi o oggetti.
  • La composizione è una variante più rigorosa dell'aggregazione. Oltre al requisito "parte di", questa "parte" non può appartenere a più "proprietari" contemporaneamente e viene eliminata quando anche il proprietario viene eliminato.

Poiché l'associazione include l'aggregazione e la composizione, durante un'analisi dettagliata tutti i casi che non possono essere descritti come aggregazione o composizione vengono chiamati associazione. Generalmente, tutti e tre gli idiomi vengono chiamati associazione.

class Base
  {
public:
                     Base(void){};
                    ~Base(void){};
   int               a;
  };
//+------------------------------------------------------------------+

class A_Association
  {
public:
                     A_Association(void){};
                    ~A_Association(void){};
   void              Association(Base *a_){};
   // At association, data of the bound object 
   // will be available through the object pointer only in the method, 
   // where the pointer is passed.
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class A_Aggregation
  {
   Base             *a;
public:
                     A_Aggregation(void){};
                    ~A_Aggregation(void){};
   void              Aggregation(Base *a_){a=a_;};
   // At aggregation, data of the bound object 
   // will be available through the object pointer in any method of the class.
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class A_Composition
  {
   Base             *a;
public:
                     A_Composition(void){ a=new Base;};
                    ~A_Composition(void){delete a;};
   // At composition, the object becomes the class member.
  };

C'è una funzione in MQL5 per il passaggio di un puntatore attraverso un parametro: 

GetPointer(pointer)

Il suo parametro è il puntatore dell'oggetto.

Per esempio:

void OnStart()
  {
   Base a; 
   A_Association b;
   b.Association(GetPointer(a));
  }


Le funzioni che vengono chiamate su OnInit() dal mio codice spesso usano l'associazione. La composizione viene applicata nella classe CHTML. Io uso l'aggregazione e la composizione insieme per associare gli oggetti all'interno della classe CPlayer. Ad esempio, utilizzando l'aggregazione gli oggetti delle classi CChartData e SBase creano un campo dati comune per tutti gli oggetti creati utilizzando la composizione nel lettore.

Visivamente, può essere rappresentato come segue:

Associazione dei dati

Le classi, i cui oggetti sono creati in modo composito nella classe CPlayer, hanno una struttura modello con un'ulteriore espansione delle funzionalità. L'utilizzo dei modelli è descritto nell'articolo Using Pseudo-Templates as Alternative to C++ Templates, quindi non fornirò qui una descrizione dettagliata.

Il modello per la classe è simile al seguente:

//this_is_the_start_point
//+******************************************************************+
class _XXX_
  {
private:
   long              chart_id;
   string            name;
   SBase            *s;
   CChartData       *d;
public:
   bool              state;
                     _XXX_(){state=0;};
                    ~_XXX_(){};
   void              Create(long Chart_id, SBase *base, CChartData *data);
   void              Update();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void _XXX_::Create(long Chart_id, SBase *base, CChartData *data)
  {
   chart_id=Chart_id;
   s=base; // binding data to the player structure
   d=data; // binding data to the chart structure
   name=" "+ChartSymbol(chart_id);

   if(ObjectFind(chart_id,name)<0)// if there is no object yet
     {//--- try to create the object         
      if(ObjectCreate(chart_id,name,OBJ_TREND,0,0,0,0,0))
        {//---
        }
      else
        {//--- failed to create the object, tell about it
         Print("Failed to create the object"+name+". Error code ",GetLastError());
         ResetLastError();
        }
     }       
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void _XXX_::Update()
  {
  };
//+******************************************************************+
//this_is_the_end_point

Quindi ho creato le classi vuote tramite il modello, le ho collegate, ho controllato se elaborano correttamente tutte le richieste e solo dopo ho iniziato a compilare le classi composite con le funzionalità necessarie. Questo è ciò che viene chiamato programmazione top-down. In caso di guasto, saprai dove cercarne la causa.

Adesso, dato che il concetto generale di costruzione è chiaro, possiamo procedere con le specifiche.

Prima di tutto, diamo un'occhiata al funzionamento delle funzioni, dichiarate nell’Expert Advisor Player History Trade exp v5.

La funzione OnInit() come di solito prepara le informazioni. Crea un oggetto della classe CParser_Tester che analizza un report dello strategy tester, ottiene l'elenco di tutti gli strumenti di trading finanziari, elabora le operazioni, calcola i volumi e i livelli di posizioni e poi disegna la cronologia sul grafico. L'ultimo elemento descrive il motivo per cui l'oggetto non viene eliminato subito dopo il passaggio dei dati. Il problema è che le informazioni vengono preparate prima dell'apertura dei grafici. E gli oggetti grafici richiedono un ID grafico per disegnare. Questo è il motivo per cui l'oggetto della classe CParser_Tester viene poi eliminato.

Inoltre, poiché conosciamo i nomi dei simboli utilizzati per il trading, viene chiamata la funzione Balance_Process(), la quale calcola i saldi e i patrimoni netti di tutti i simboli che sono stati passati ad essa, nonché il saldo totale e il patrimonio netto sulla base della cronologia di M1.

Qui, l'applicazione è particolarmente sensibile alla mancanza di informazioni; questo è il motivo per cui ho implementato l'interruzione dell'esecuzione dell'EA nel caso in cui le informazioni per uno dei simboli non siano scaricate. Quando l'applicazione smette di funzionare, mostra un avviso con le informazioni sul simbolo per le quali è necessario scaricare.

Il risultato del funzionamento della funzione Balance_Process() sono dei file binari della storia del saldo e del patrimonio netto su M1 che vengono ulteriormente tagliati nei periodi necessari dall'indicatore di saldo. Beh, sto andando un po’ avanti: il funzionamento dell'indicatore di bilanciamento sarà descritto in seguito.

Il prossimo passo per avviare l’Expert Advisor è la selezione dei simboli. Qui analizziamo il parametro di input "elenco dei grafici obbligatori"; nel caso in cui il simbolo necessario sia nell'elenco "Market Watch", aggiungilo all’array di simboli. In questo modo, ci proteggiamo dagli "sciocchi" dato che un utente può specificare un abracadabra anziché il nome di simbolo oppure può stamparlo in modo errato.

Poiché possediamo l'elenco verificato di simboli richiesti da un utente per l'apertura, possiamo aprire i grafici. Ciò avviene utilizzando la seguente funzione:

ChartOpen(symbol,period)

Questa funzione apre un grafico con il simbolo e il punto passati ad essa come parametri. In teoria, questa funzione restituisce l'ID del grafico aperto, anche se non accade sempre.

Come risultato della perdita dell'ID, l'applicazione non funziona correttamente. Per evitare che questo accada, ho creato due funzioni:

ChartTotal(arrayID);   // get the list of charts before opening additional charts
CurrentChart(arrayID); // get the list of chart for operation

Una funzione viene eseguita prima di aprire i grafici e l'altra viene eseguita dopo. La funzione ChartTotal() ottiene l'elenco dei grafici aperti prima dell'avvio dell'EA (incluso il grafico su cui viene eseguito l'EA) e salva i loro ID nell’array di input.

La funzione CurrentChart() ottiene queste informazioni, crea un nuovo elenco considerando i grafici già aperti; poi, in base alla differenza di elenchi, passa gli ID dei grafici creati dall'EA all'array parametrico. Questo schema è affidabile, perché funziona in base all'apertura del grafico.

Ora che abbiamo gli ID dei grafici necessari, possiamo tenerli sotto controllo. Per farlo, esamina tutti i grafici in un loop e, usando l'oggetto del CParser_Tester (se ricordi, prima ho detto che ne avremmo avuto bisogno), disegna la cronologia delle operazioni e crea gli oggetti per la gestione del grafico.

L'ultima azione su OnInit() consiste nel creare il timer e chiamarlo per svolgere le sue funzioni. Tutte le altre azioni verranno eseguite su OnTimer().

Il primo problema di creazione del lettore appare nella fase iniziale di sviluppo. È il problema della creazione di un timer. La funzione EventSetTimer(timer) consente di creare un timer con frequenza non inferiore a 1 secondo. Con questa variante, i tick verrebbero generati una volta al secondo. Anche per le limitazioni della visione umana, un secondo è troppo lungo. Ho bisogno di almeno 100 millisecondi.

Ecco perché ho implementato un loop all'interno del timer, il quale esce diversi millisecondi prima dell’arrivo di un nuovo evento Timer. Ma questa implementazione ha reso impossibili molte soluzioni tecniche. Ad esempio, scompare la possibilità di ricevere eventi perché aspettano costantemente che il timer esca dal ciclo. E l'impossibilità di ricevere eventi elimina la possibilità di posizionare gli oggetti dei lettori nell’indicatore ed eseguire calcoli paralleli di tutti i grafici contemporaneamente. Ma anche con la conseguente elaborazione dei grafici, l'Expert Advisor funziona abbastanza velocemente.

L'evento di attivazione del grafico viene sostituito con la classe composita CClick, i cui oggetti creano un segnale di modifica del grafico attivo in fase di elaborazione nel ciclo della funzione Click(n). La funzione Click() è un trigger che tiene traccia delle modifiche del pulsante di attivazione del grafico. Se rileva che il pulsante è premuto, passa tutti gli altri oggetti allo stato passivo. Il pulsante di attivazione del grafico è sempre vicino all'utente, ma non è visibile perché possiede le dimensioni dell'intero grafico, è colorato come lo sfondo e si trova sullo sfondo. Quando un grafico è attivato, il pulsante viene spostato dietro i bordi visibili del grafico: ciò consente di vedere gli oggetti grafici dei controlli del lettore, i quali sono nascosti dal pulsante di attivazione del grafico in modalità passiva.

Inoltre, poiché abbiamo rilevato il grafico principale utilizzando la funzione Click(), vai al calcolo del movimento temporale e chiama la funzione Progress(Time) del player attivo. Questa funzione esegue i seguenti calcoli: controlla se un utente esegue azioni di navigazione - in caso contrario, controlla se è il momento di andare alla barra successiva; se è il momento, controlla se l'avanzamento deve essere spostato nella sezione successiva.

Alla fine, quando usciamo dalla funzione Progress(Time), il ciclo ha le informazioni sull'ora attuale, le quali vengono utilizzate per ulteriori calcoli. Quindi le impostazioni del grafico attivo vengono copiate nei grafici slave. Ciò avviene utilizzando un ciclo nella funzione CopyPlayer(n). Dopodiché, nella funzione Play(Time) vai all'esecuzione di tutte le modifiche che devono essere apportate al grafico per far pensare a un utente che il tempo si muove, le quotazioni arrivano e il trading viene eseguito.


Classi composite del lettore.

  1. CArrayRuler* - memorizza e cerca informazioni per spostarsi rapidamente tra le barre di un intervallo di tempo corrente.
  2. CRuler* - memorizza e cerca le informazioni della cronologia M1 per la generazione di tick.
  3. CSpeed - controlla le impostazioni di velocità e il periodo del generatore di tick.
  4. CProgress - combina tutti i pulsanti di avanzamento in un unico oggetto, osserva che viene premuto un solo pulsante, cambia i colori dei pulsanti.
  5. CPlay - è responsabile dell'avvio e dell'arresto del lettore, inoltre controlla l'indicatore di bilanciamento.
  6. CClick - è responsabile dei segnali di attivazione del grafico.
  7. CBackGround - l'oggetto nasconde la barra dello zero agli utenti, così come nasconde le barre future quando lo spostamento del grafico dallo stato del bordo destro è abilitato.
  8. CBarDraw - disegna la barra dello zero a seconda della scala e del tipo di grafico (barre, candele o linea).
  9. CHistoryDraw - crea un'illusione per l'utente per cui l'ultima operazione cambia in tempo reale.

* - le classi non includono oggetti grafici.

Come ho già accennato, gli oggetti delle classi CChartData e SBase creano un campo dati comune per tutti gli oggetti all'interno del lettore utilizzando l'aggregazione. L'oggetto della classe CChartData viene utilizzato per l'archiviazione e l'aggiornamento delle informazioni sul grafico e per la sua gestione. Gestendo il grafico, intendiamo modificarne l'impostazione copiando le impostazioni del grafico principale. Ecco come si esegue la sincronizzazione dei grafici. Un utente crea solo un segnale iniziale modificando le impostazioni del grafico attivo, quindi diverse funzioni del lettore effettuano il resto delle operazioni di sincronizzazione.

Ecco come si fa:

La funzione CopyPlayer(n), descritta nell’Expert Advisor, chiama la funzione CPlayer::Copy(CPlayer *base) in un ciclo che passa associativamente il puntatore al lettore del grafico attivo. All'interno di CPlayer::Copy(CPlayer *base) dal puntatore del lettore, il puntatore dell'oggetto CChartData del lettore attivo viene passato associativamente. Pertanto, le informazioni sullo stato del grafico attivo vengono inserite nell'oggetto della classe CChartData del grafico slave per la copia. Successivamente, le informazioni vengono aggiornate nella funzione CPlayer::Update(), in cui vengono eseguiti tutti i controlli necessari e tutti gli oggetti vengono commutati negli stati necessari.

Prima, ho promesso di dirti come aggiungere i periodi nell'elenco dei periodi disponibili del generatore. Per farlo, apri il file include "Player5_1.mqh". La matrice statica TFarray[] viene dichiarata all'inizio del file. Occorre aggiungere un periodo alla sua posizione nell'enumerazione che riempie l’array. Non dimenticare di modificare le dimensioni dell’array e della variabile CountTF. Dopodiché, compila l’Expert Advisor Player History Trades exp v5.


I grafici di bilanciamento e drawdown

L'indicatore di bilanciamento viene gestito dall'oggetto della classe CPlay. Contiene metodi e pulsanti di controllo.

I metodi di controllo dell'indicatore sono:

   Ind_Balance_Create();                 // add the indicator
   IndicatorDelete(int ind_total);     // delete the indicator
   EventIndicators(bool &prev_state);   // send an event to the indicator
   StateIndicators();                  // state of the indicator, state checks

I metodi di aggiunta/eliminazione funzionano a seconda dello stato del pulsante name_on_balance. Utilizzano le funzioni standard MQL5 IndicatorCreate() e ChartIndicatorDelete().

L'indicatore riceve un evento ed esegue calcoli che si trovano nella funzione OnChartEvent() dell'indicatore in base al codice dell'evento. Gli eventi possono essere di tre tipi. 

Ovvero, "aggiorna l'indicatore", "calcola il saldo totale" e "calcola il saldo per un simbolo". Pertanto, quando si inviano gli eventi, a seconda dello stato del pulsante name_all_balance, l'utente controlla il tipo di calcolo. Ma il codice dell'indicatore stesso non contiene alcuna analisi della cronologia di trading, del calcolo della posizione o del ricalcolo del profitto. L'indicatore non ne ha bisogno.

L'indicatore di bilanciamento è destinato alla visualizzazione dei dati cronologici, quindi non ha senso rifare tutto di nuovo ogni volta che si modifica la tipologia o si aggiunge/rimuove l'indicatore. L'indicatore legge il file binario di dati calcolato per l'intervallo di tempo M1 e quindi, a seconda dell'intervallo di tempo corrente del grafico, divide i dati.

Questo file binario viene preparato dalla funzione Balance_Process() chiamata su OnInit(). Se l'utente aggiunge un simbolo che non è stato utilizzato per il trading e non esiste un file binario corrispondente, l'indicatore visualizzerà la cronologia del saldo totale in entrambe le varianti.

Ora parliamo del formato dei dati passati all'indicatore. Per dividere correttamente le informazioni, non è sufficiente conoscere quattro i punti di una barra (Aperto, Alto, Basso e Chiuso).

Oltre a questo, è necessario sapere qual è il primo, se alto o basso. Per ripristinare le informazioni, la funzione Balance_Process() utilizza lo stesso principio della modalità "1 minute OHLC" dello strategy tester: se il prezzo di chiusura di una barra è inferiore al prezzo aperto, il secondo punto sarà il massimo o, altrimenti, il minimo.

Per il terzo punto si utilizza lo stesso schema. Di conseguenza, otteniamo il formato dei dati (open, 2-nd point, 3-rd point, close) dove tutto è coerente e definito. Questo formato viene utilizzato per dividere la cronologia M1 delle quotazioni. E il risultato viene utilizzato per il calcolo della cronologia del saldo e del patrimonio netto, a seconda della cronologia di trading analizzata (nello stesso formato).


Conclusione

In conclusione, voglio dire che questo sviluppo non pretende di essere un visualizzatore di tester, anche se possiamo usarlo in questo modo. Tuttavia, se le idee implementate in esso sembreranno utili per il visualizzatore reale, ne sarò felice. Lo sviluppo del lettore ha lo scopo di aiutare i trader e gli scrittori EA con la preparazione per la prossima championship e con il duro lavoro di analisi delle strategie trading.

Inoltre, voglio dire che il linguaggio MQL5 è un potente strumento per la programmazione che consente di implementare progetti piuttosto enormi. Se stai ancora leggendo questo articolo, probabilmente avrai notato che il progetto "lettore" è composto da quasi 8000 righe di codice. Non riesco a immaginare di poter scrivere un codice del genere in MQL4 e la questione non riguarda il descriverlo per intero con le procedure. Se c'è uno sviluppo già pronto, può essere rifatto nello stile della procedura. Ma sviluppare tali progetti da zero è davvero difficile.

Buona Fortuna!


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/242

Grafici e diagrammi in HTML Grafici e diagrammi in HTML
Oggi è difficile trovare un computer che non abbia un browser installato. Da tanto tempo i browser si evolvono e migliorano. Questo articolo tratta un modo semplice e sicuro per creare grafici e diagrammi sulla base delle informazioni ottenute dal client terminal MetaTrader 5 per la loro visualizzazione nel browser.
Moving mini-max: un nuovo indicatore per l'analisi tecnica e la sua implementazione in MQL5 Moving mini-max: un nuovo indicatore per l'analisi tecnica e la sua implementazione in MQL5
Nel seguente articolo descriverò un processo di implementazione dell'indicatore Moving Mini-Max basato su un documento di Z.G.Silagadze "Moving Mini-max: a new indicator for technical analysis". L'idea dell'indicatore si basa sulla simulazione di fenomeni di tunneling quantistico proposta da G. Gamov nella teoria del decadimento alfa.
Implementazione degli indicatori come classi mediante esempi di Zigzag e ATR Implementazione degli indicatori come classi mediante esempi di Zigzag e ATR
Il dibattito su un modo ottimale per calcolare gli indicatori è infinito. Dove dovremmo calcolare i valori dell'indicatore? Nell'indicatore stesso o occorre incorporare l'intera logica in un Expert Advisor che lo utilizza? L'articolo descrive una delle varianti dello spostamento del codice sorgente di un indicatore personalizzato iCustom direttamente nel codice di un Expert Advisor o di uno script con ottimizzazione dei calcoli e modellazione del valore prev_calculated.
Collegare NeuroSolutions Neuronets Collegare NeuroSolutions Neuronets
Oltre alla creazione di neuronet, la suite software NeuroSolutions consente di esportarli come DLL. Questo articolo descrive il processo di creazione di un neuronet, la generazione di un DLL e la connessione a un Expert Advisor per il trading su MetaTrader 5.