English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
L'Istogramma dei Prezzi (Market Profile) e la sua implementazione in MQL5

L'Istogramma dei Prezzi (Market Profile) e la sua implementazione in MQL5

MetaTrader 5Esempi | 15 dicembre 2021, 17:01
338 0
Dmitry Voronkov
Dmitry Voronkov

"Market Profile cerca di fornire questa logica interna nel contesto del mercato.
È un metodo di analisi che parte dalla comprensione che solo il prezzo
non comunica informazioni al partecipante, proprio come le parole
senza sintassi
o il contesto potrebbe non avere alcun significato. Il volume è parte integrante dell'espressione diretta
del mercato - capisci e comprendi il linguaggio del mercato."
Robin Mesh

Introduzione

Molto tempo fa, sfogliando una rivista ad abbonamento ho trovato un articolo "Profilo di mercato e comprendere il linguaggio del mercato" (ottobre 2002) nella rivista russa "Valutny Spekulant" (Attualmente si chiama "Active Trader"). L'articolo originale è stato pubblicato "Nuovo Pensiero sull’Analisi Tecnica: Modelli di Trading dai Maestri".

Il Market Profile è stato sviluppato dal geniale pensatore Peter Steidlmayer. Ha trovato l'espressione naturale del mercato (volume) e l'ha organizzata in maniera leggibile (la curva a campana), in modo che le informazioni oggettive generate dal mercato siano accessibili ai partecipanti al mercato. Steidlmayer ha suggerito di utilizzare la rappresentazione alternativa delle informazioni su "orizzontale" e movimenti di mercato "verticali" che portano a un insieme completamente diverso di modelli. Ha assunto che ci sia un impulso sottostante del mercato o un modello fondamentale chiamato ciclo di equilibrio e squilibrio.

Market Profile misura il movimento orizzontale del mercato attraverso quello verticale.  Chiamiamolo "equillibrium" attraverso "disequillibrium". Questa relazione è il principio organizzativo fondamentale del mercato. L'intero stile di trading di un trader può cambiare a seconda della parte del ciclo di equilibrio / squilibrio in cui si trova il mercato. Il profilo di mercato può determinare sia quando il mercato passerà dall'equilibrio allo squilibrio sia quanto grande sarà la mossa.

I due concetti base di Market Profile sono:

  1. Il mercato è un'asta, e si muove nella direzione della fascia di prezzo dove l'offerta e la domanda sono più o meno uguali.
  2. Il mercato ha due fasi: attività orizzontale e attività verticale. Il mercato si muove verticalmente quando domanda e offerta non sono uguali o sono in squilibrio e orizzontalmente quando sono in equilibrio o equilibrati.

Il mercato di equilibrio mostrato utilizzando il profilo di mercato nel grafico sottostante tende a formare una curva a campana quasi perfetta, ruotata di 90 gradi a causa dell'orientamento del grafico:

 

Fig 1. Il Market Profile del mercato di equilibrio

Il mercato di tendenza, non di equilibrio, forma anche una curva a campana, ma il suo centro è spostato verso l'alto o verso il basso. Altre configurazioni che formano due picchi di campane, a seconda del movimento dei prezzi e della fiducia degli attori del mercato, sono possibili.

Fig 2. Il Market Profile del mercato di squilibrio (tendenza)

L'uso delle forme del profilo giornaliero per determinare il grado di equilibrio / livello di squilibrio del mercato può essere utile, perché ti dà un punto di partenza per comprendere i cambiamenti tra i vari partecipanti al mercato.

Un'opportunità di trading con il massimo beneficio appare quando sta per verificarsi il passaggio dall'equilibrio allo squilibrio. Inoltre, se riesci a identificare quell'opportunità di trading e stimare con precisione l'entità potenziale di quel cambiamento, puoi stimare la qualità di quel commercio e la quantità di tempo necessaria per esso.

È necessario notare che in questo articolo considereremo il codice per disegnare una versione semplificata del Market Profile, il cosiddetto Istogramma dei Prezzi basato sulla relazione tra prezzo e tempo.

Puoi trovare l'esempio della metodologia di lavoro con questo strumento può essere trovato su http://www.enthios.com/, dove un gruppo di trader ha studiato l'istogramma dei prezzi dal 1998. La strategia Enthios Universal e l'esempio del suo utilizzo si possono trovare anche lì.

1. Istogramma dei Prezzi

L'istogramma dei Prezzi è uno strumento molto affidabile. È un po’ intuitivo ma estremamente efficace. L'istogramma dei prezzi mostra semplicemente i punti di trading "più convenienti" del mercato. Questo è un indicatore anticipatore, perché mostra i punti in cui il mercato può cambiare direzione in anticipo. Gli indicatori come le medie mobili o gli oscillatori non possono specificare i punti esatti di resistenza e supporto, possono solo mostrare il fatto se il mercato è ipercomprato o ipervenduto.

Di solito, l'istogramma dei prezzi (o profilo di mercato) viene applicato a grafici dei prezzi di 30 minuti per studiare l'attività di mercato durante un giorno. Preferisco usare i grafici a 5 minuti per i mercati azionari e i grafici a 15-30 minuti per il FOREX.

2. Punto di Controllo

Nella figura sopra puoi vedere il livello in cui il mercato è stato scambiato la quantità massima di tempo; è delineato con la linea più lunga nell'istogramma. Si chiama Punto di Controllo, oppure POC. A volte, come si vede nella figura, l'istogramma ha due cime, una delle quali è un po’ più bassa. In tal caso, vediamo che l'indicatore mostra solo un POC, ma in realtà ce ne sono due e dovrebbe essere preso in considerazione.

Inoltre, il livello percentuale dell'intervallo nell'istogramma crea anche livelli aggiuntivi, i cosiddetti Livelli POC secondari:

Fig 3. Punti di controllo

Cosa mostra POC? Il prezzo che viene ricordato dalla maggior parte dei trader. Più a lungo il mercato viene scambiato a questo prezzo, più a lungo il mercato lo ricorda.

Psicologicamente POC agisce come un centro di attrazione.

Il grafico seguente mostra cosa è successo pochi giorni prima. È una buona dimostrazione della potenza dell'istogramma dei prezzi.

Fig 4. Il Punto di Controllo non è assoluto; mostra la gamma di trade

Il Punto di Controllo non è assoluto; indica l'intervallo di trading. Pertanto, il trader dovrebbe essere pronto ad agire quando il mercato si avvicina al POC. Aiuta a ottimizzare gli ordini, utilizzando le osservazioni storiche.

Consideriamo la Fig. 4. Il POC del 29.12.2009 si trova al prezzo 68.87. È chiaro anche senza l'istogramma e la linea POC che il mercato era all'interno dell'intervallo 68.82 ~ 68.96 quasi tutto il giorno. Il mercato ha chiuso a fine giornata a 5 punti al di sotto del POC. Il giorno successivo ha causato l'apertura del mercato con un gap down.

È importante capire che non possiamo prevedere se il mercato salirà o scenderà. Possiamo solo supporre che il mercato tornerà alla linea POC e all'accumulo massimo delle righe dell’istogramma. Ma cosa succederà quando il prezzo toccherà il POC? La stessa cosa che accade con un oggetto elastico che cade a terra, salterà indietro.  Se succede rapidamente, come una palla da tennis che colpisce con una racchetta, il prezzo tornerà molto rapidamente al livello iniziale.

Dopo l'apertura del mercato il 30.12.2009 vediamo che è stato un gap e poi il mercato ha toccato il POC del giorno precedente, per poi tornare rapidamente al prezzo di apertura e aggiornare il minimo.

Si noti che il POC non è assolutamente accurato (i trader esperti sanno che non ci sono chiari livelli di resistenza quando il prezzo raggiunge un intervallo massimo, minimo o di concentrazione). Ciò che accade a questo punto dipende dai player di mercato. Se il desiderio collettivo (ad esempio, la pubblicazione di notizie) coincide, allora il mercato passerà attraverso il POC, ma è raro e può essere utilizzato per sviluppare un sistema di trading.

Attenzione che il comportamento del mercato è stato lo stesso al 31.12.2009. Quando il prezzo ha toccato POC, gli acquirenti hanno ceduto ai venditori.

3. Punto Vergine di Controllo

Il Virgin POC (Virgin Point of Contro) è un livello che il prezzo non ha raggiunto nei prossimi giorni.

La logica è semplice, come descritto sopra, il POC è un punto di attrazione per il mercato. Man mano che il prezzo si allontana dal POC, la forza di attrazione aumenta. E più il prezzo si allontana dal Virgin POC, maggiore è la possibilità che quando ritorna a questo livello si verificherà il rimbalzo e probabilmente si verificherà anche un'inversione del prezzo.

Fig 5. Precedente e attuale Virgin POC

Alla Fig. 5 gli ex FIC Vergini che erano i livelli di supporto e resistenza sono contrassegnati da cerchi. I Virgin POC funzionanti sono contrassegnati con valori di prezzo.

Una volta che il prezzo ha toccato il Virgin POC, cessa di essere una "vergine". Psicologicamente, il mercato non lo vede più come un livello sostanziale di supporto o resistenza. I trader possono ancora vedere i livelli dei prezzi, che inizialmente ha formato il POC, ma come un semplice accumulo di prezzi.

Puoi avere maggiori dettagli sui livelli di prezzo nel libro "Master-trading: X-Files" di Eric Naiman (Capitolo 4, "Il livello dei prezzi è una linea di base").

4. Implementazione dell'Istogramma dei Prezzi in MQL5

La mia prima versione dell’Istogramma dei Prezzi è apparsa nel 2006 è stata scritta in MQL4 in MetaTrader4 per uso personale. Durante lo sviluppo di questo indicatore ho affrontato alcuni problemi, eccone alcuni:

    1. numero molto breve di barre nella cronologia per M5, per non parlare di M1;
    2. la necessità di sviluppare funzioni speciali per lavorare con la cronologia, come tornare indietro di un giorno considerando i giorni festivi, controllare l'orario di chiusura del mercato il venerdì, controllare l'orario di apertura e chiusura per il mercato CFD, ecc;;
    3. ricalcolo dell'indicatore quando si modificano i tempi e, di conseguenza, i ritardi del terminale.

    Pertanto, quando è iniziato il beta-testing di МetaТrader5 e MQL5, ho deciso di convertirlo in MQL5.

    Come si suol dire, "il primo pancake è sempre un po’ complicato", ho cercato di implementarlo come un indicatore.

    Partiamo dal bene: la presenza della lunga storia del minuto quotazioni per tutti i simboli, la possibilità di ottenere dati storici per un certo periodo di tempo in qualsiasi intervallo di tempo.

    Ora spiegherò perché si è scoperto. Non ho considerato le caratteristiche degli indicatori MQL5:

      1. il runtime dell'indicatore è critico;
      2. le caratteristiche del lavoro dell'indicatore dopo le modifiche del timeframe.

      L'esecuzione della funzione OnCalculate(), che corrisponde all’handler degli eventi Calculate ha un runtime critico. Di conseguenza, l'elaborazione di 260 giorni (periodo annuale) utilizzando la cronologia delle barre dei minuti richiede molto tempo, fino a diversi minuti. Naturalmente possiamo accettarlo, se i calcoli vengono eseguiti contemporaneamente dopo l'indicatore allegato al grafico. Ma questo non è il caso dei cambiamenti del timeframe. Quando l'indicatore passa al diverso timeframe, la vecchia copia dell'indicatore viene distrutta e creata quella nuova. Ecco perché dopo i cambiamenti del timeframe dobbiamo ricalcolare di nuovo gli stessi livelli e passa molto tempo.

      Ma come dire, se non sai cosa fare - "Leggi prima la documentazione", nel nostro caso, è la documentazione di MQL5. La soluzione era molto semplice: implementare questo indicatore come Expert Advisor che non fa trading.

      I vantaggi dell’Expert Advisor sono:

        1. il tempo di elaborazione non è critico per l’handler di eventi Init in OnTick ();
        2. la possibilità di ottenere i parametri dell’handler OnDeinit (const int reason).

        Gli Expert Advisor si differenziano dagli indicatori quanto segue: dopo la modifica del timeframe l'expert advisor genera semplicemente l'evento DeInit con REASON_CHARTCHANGE parametro reason, non scarica l'Expert Advisor dalla memoria e serve i valori delle variabili globali. Ci consente di eseguire tutti i calcoli contemporaneamente dopo l’aggiunta dell’Expert Advisor, modificando i suoi parametri e nuovi dati che appaiono, nel nostro caso per un nuovo giorno di trading.

        Introduciamo alcune definizioni che saranno necessarie in seguito.

        La programmazione orientata agli oggetti (OOP) - è uno stile di programmazione i cui concetti di base sono i concetti di oggetti e classi.

        L'oggetto Object è un'entità nello spazio virtuale, con stato e comportamento specificati; ha alcuni valori di proprietà (chiamate come attributi) e operazioni con esse (chiamate come metodi).

        In OOP la Classe è uno speciale tipo di dati astratti, caratterizzato per mezzo della sua costruzione. La classe è un concetto chiave in OOP. La classe è diversa dagli altri tipi di dati astratti. La definizione dei dati in classe contiene anche i metodi di classe della sua elaborazione dei dati (interfaccia).

        Nella programmazione esiste un concetto di interfaccia software che significa un elenco di possibili calcoli che possono essere eseguiti da alcune parti del programma, inclusi algoritmi, descrizione degli argomenti e ordine dei parametri di input per procedere e i suoi valori restituiti. L'interfaccia del tipo di dati astratta è stata sviluppata per una descrizione formalizzata di tale elenco. Gli algoritmi stessi e il codice che eseguirà tutti questi calcoli non sono specificati e chiamati come implementazione dell'interfaccia.

        La creazione della classe è la creazione di una struttura con campi e metodi. L'intera classe può essere considerata come un modello per la creazione di oggetti che sono istanze di classe. Le istanze di classe vengono create utilizzando lo stesso modello, quindi hanno gli stessi campi e metodi.

        Iniziamo...

        Il codice sorgente si trova in 4 file. Il file principale è PriceHistogram.mq5, gli altri file sono: ClassExpert.mqh, ClassPriceHistogram.mqh e ClassProgressBar.mqh. I file con estensione .mqh contengono la descrizione e i metodi delle classi. Tutti i file devono trovarsi nella stessa directory, la mia directory è: \MQL5\ Experts\PriceHistogram.

        4.1. PriceHistogram.mq5

        La prima affermazione nel codice sorgente è:

        #include "ClassExpert.mqh"

        La direttiva del compilatore #include include il testo del file specificato. Nel nostro caso è la descrizione della classe CExpert (discussa di seguito).

        Il prossimo è un blocco di variabili di input che sono parametri di Expert Advisor.

        // The block input parameters
        input int         DayTheHistogram   = 10;          // Days for histogram
        input int         DaysForCalculation= 500;         // Days for calculation(-1 all)
        input uint        RangePercent      = 70;          // Percent range
        input color       InnerRange        =Indigo;       // Inner range
        input color       OuterRange        =Magenta;      // Outer range
        input color       ControlPoint      =Orange;       // Point of Control
        input bool        ShowValue         =true;         // Show Values
        

        Successivamente viene dichiarata la variabile ExtExpert (di tipo classe CExpert).

        Il prossimo è il gestore eventi standard che si trovano nei programmi MQL5. I gestori eventi richiedono i metodi corrispondenti della classe CExpert.

        Esiste un unico metodo che esegue alcune operazioni prima dell'esecuzione di CExpert - è il metodo OnInit():
        int OnInit()
          {
        //---
        // We check for symbol synchronization before the start of calculations
           int err=0;
           while(!(bool)SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED) && err<AMOUNT_OF_ATTEMPTS)
             {
              Sleep(500);
              err++;
             }
        // CExpert class initialization
           ExtExpert.RangePercent=RangePercent;
           ExtExpert.InnerRange=InnerRange;
           ExtExpert.OuterRange=OuterRange;
           ExtExpert.ControlPoint=ControlPoint;
           ExtExpert.ShowValue=ShowValue;
           ExtExpert.DaysForCalculation=DaysForCalculation;
           ExtExpert.DayTheHistogram=DayTheHistogram;
           ExtExpert.Init();
           return(0);
          }
        

        Quando ho scritto la prima versione di Expert Advisor e l'ho eseguita, ho qualche problema a capire perché termina con errore dopo il riavvio del terminale client o la modifica di un simbolo. E si verifica quando il terminale client è stato disconnesso o un simbolo non viene utilizzato per molto tempo.

        È fantastico che gli sviluppatori abbiano aggiunto il debugger a MetaEditor5. Ricordo molti comandi Print() e Comment(), usati per controllare i valori delle variabili in MetaEditor4. Grazie mille agli sviluppatori di MetaEditor5.

        Nel mio caso, tutto è stato facile; l'esperto inizia prima della connessione al server e dell'aggiornamento dei dati storici. Per risolvere questo problema, ho dovuto utilizzare SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED), che segnala che i dati sono sincronizzati o meno e il ciclo mentre (), il caso dell'assenza di connessione utilizza la variabile contatore err.

        Una volta che i dati sono stati sincronizzati o il ciclo è stato completato a causa del contatore in assenza di connessione, passiamo i parametri di input della nostra classe di esperti CExpert e chiamiamo il metodo di inizializzazione della classe Init ().

        Come vedi, grazie al concetto di classi in MQL5, il nostro file PriceHistogram.mq5 si è trasformato in un semplice modello e tutte le ulteriori elaborazioni sono nella classe CExpert, dichiarata nel file ClassExpert.mqh.

        4.2. ClassExpert.mqh

        Consideriamo la sua descrizione.

        //+------------------------------------------------------------------+
        //|   Class CExpert                                                  |
        //|   Class description                                              |
        //+------------------------------------------------------------------+
        class CExpert
          {
        public:
           int               DaysForCalculation; // Days to calculate (-1 for all)
           int               DayTheHistogram;    // Days for Histogram 
           int               RangePercent;       // Percent range
           color             InnerRange;         // Internal range color
           color             OuterRange;         // Outer range color
           color             ControlPoint;       // Point of Control (POC) Color
           bool              ShowValue;          // Show value
        

        La sezione pubblica è aperta e accessibile dalle variabili esterne. Noterai che i nomi delle variabili coincidono con i nomi della sezione dei parametri di input descritta in PriceHistogram.mq5. Non è necessario perché i parametri di input sono globali. Ma in questo caso - è un tributo alle buone regole di allevamento, è auspicabile evitare l'uso di variabili esterne all'interno della classe.

        private:
           CList             list_object;        // The dynamic list of CObject class instances
           string            name_symbol;        // Symbol name
           int               count_bars;         // Number of daily bars
           bool              event_on;           // Flag of events processing
        

        La sezione privata è chiusa dall'esterno e accessibile solo all'interno della classe. Vorrei delineare la variabile list_object di tipo CList, che è una classe della libreria MQL5 standard. La classe CList è una classe dinamica con un elenco di istanze dellaclasse e CObject dei suoi eredi. Utilizzerò questo elenco per l'archiviazione dei riferimenti per gli elementi della classe CPriceHistogram, che è un erede della classe CObject; prenderemo in considerazione i dettagli di seguito. La descrizione della classe CList si trova nel file List.mqh ed è in #include utilizzando la direttiva del compilatore #include <Arrays\List.mqh>.

        public:
           // Class constructor
                             CExpert();
           // Class destructor
                            ~CExpert(){Deinit(REASON_CHARTCLOSE);}
           // Initialization method
           bool              Init();
           // Deinitialization method
           void              Deinit(const int reason);
           // Method of OnTick processing
           void              OnTick();
           // Method of OnChartEvent() event processing
           void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
           // Method of OnTimer() event processing
           void              OnTimer();
        };

        Di seguito è riportata una sezione relativa ai metodi pubblici. Come hai intuito, questi metodi (funzioni) sono disponibili al di fuori della classe.

        E infine, la parentesi graffa con un punto e virgola completa la descrizione della classe.

        Consideriamo i metodi di classe in dettaglio.

        Il costruttore class è un blocco speciale di istruzioni, chiamato quando viene creato l'oggetto. Il costruttore è simile al metodo, ma differisce dal metodo che non ha esplicitamente un certo tipo di dati restituiti.

        Nel linguaggio MQL5, i costruttori non possono avere parametri di input e ogni classe deve avere un solo costruttore. Nel nostro caso, il costruttore è un'inizializzazione primaria di variabili.

        Il distruttore è un metodo di classe speciale utilizzato per la reinizializzazione dell'oggetto (ad esempio, memoria libera). Nel nostro caso il metodo è chiamato Deinit (REASON_CHARTCLOSE);

        Init() è un metodo per l'inizializzazione della classe. Questo è il metodo più importante della classe CExpert; Le la creazione di oggetti di istogramma è stata eseguita lì. Si prega di guardare i commenti per i dettagli. Ma vorrei considerare i punti.

        Il primo, per costruire un istogramma giornaliero dei prezzi abbiamo bisogno dei dati di open time per giorni per procedere. Qui vorrei divagare e attirare la vostra attenzione sulle caratteristiche del lavoro con le time serie.  Per la richiesta di dati dagli altri intervalli di tempo abbiamo avuto bisogno di un tempo, quindi le funzioni Barre () e CopyTime (), così come altre funzioni per lavorare con le time serie non sempre restituiscono i dati desiderati dalla prima chiamata.

        Quindi ho dovuto mettere questa funzione nel ciclo do (...) while (), ma per renderla finita, ho usato la variabile contatore.

         int err=0;
         do
           {
            // Calculate the number of days which available from the history
            count_bars=Bars(NULL,PERIOD_D1);
            if(DaysForCalculation+1<count_bars)
               count=DaysForCalculation+1;
            else
               count=count_bars;
            if(DaysForCalculation<=0) count=count_bars;
            rates_total=CopyTime(NULL,PERIOD_D1,0,count,day_time_open);
            Sleep(1);
            err++;
           }
         while(rates_total<=0 && err<AMOUNT_OF_ATTEMPTS);
         if(err>=AMOUNT_OF_ATTEMPTS)
           {
           Print("There is no accessible history PERIOD_D1");
           name_symbol=NULL;
           return(false);
           }

        In secondo luogo, la cronologia dei minuti di MetaTrader 5 è uguale ai giorni disponibili, quindi può richiedere molto tempo per procedere, quindi è necessario visualizzare il processo di calcolo. La classe CProgressBar (#include "ClassProgressBar.mqh") è stato sviluppato per questo scopo. Crea la barra di avanzamento nella finestra del grafico e la aggiorna durante il processo di calcolo.

         // We create the progress bar on the char to shot the loading process
         CProgressBar   *progress=new CProgressBar;
         progress.Create(0,"Loading",0,150,20);
         progress.Text("Calculation:");
         progress.Maximum=rates_total; 

        Il terzo, in ciclo, utilizzando l'istruzione "new", creiamo l'oggetto CPriceHistogram, lo configuriamo usando i suoi metodi e lo inizializziamo chiamando Init(). In caso di esito positivo, lo aggiungiamo all'elenco list_object, in modo eccessivo eliminiamo il hist_obj utilizzando l'istruzione delete. La descrizione della classe CPriceHistogram verrà presentata ulteriormente, vedere i commenti nel codice.

         // In this cycle there is creation of object CPriceHistogram
         // its initialization and addition to the list of objects
         for(int i=0;i<rates_total;i++)
           {
            CPriceHistogram  *hist_obj=new CPriceHistogram();
            //         hist_obj.StepHistigram(step);
            // We set the flag to show text labels
            hist_obj.ShowLevel(ShowValue);
            // We set POCs colour
            hist_obj.ColorPOCs(ControlPoint);
            // We set colour for inner range
            hist_obj.ColorInner(InnerRange);
            // We set colour for outer range
            hist_obj.ColorOuter(OuterRange);
            // We set the percent range
            hist_obj.RangePercent(RangePercent);
            //  hist_obj.ShowSecondaryPOCs((i>=rates_total-DayTheHistogram),PeriodSeconds(PERIOD_D1));
            if(hist_obj.Init(day_time_open[i],day_time_open[i]+PeriodSeconds(PERIOD_D1),(i>=rates_total-DayTheHistogram)))
               list_object.Add(hist_obj);
            else
               delete hist_obj; // Delete object if there was an error
            progress.Value(i);
           }; 

        OnTick() è un metodo chiamato quando si riceve un nuovo segno di spunta per un simbolo. Confrontiamo i valori del numero di giorni memorizzati nella variabile count_bars con il numero di barre giornaliere restituite da Barre (Simbolo (), PERIOD_D1) e se non sono uguali chiamiamo forzatamente il metodo Init () per l'inizializzazione della classe, cancellando l'elenco list_object e cambiando la variabile in NULL name_symbol . Se il numero di giorni non è cambiato, il ciclo passa attraverso tutti gli oggetti memorizzati nella classe CPriceHistogram list_object ed eseguire un metodo Redraw (), per coloro che sono Vergini ( «virgin»).

        Il Deinit() è un metodo per la reinizializzazione di classe. Nel caso di REASON_PARAMETERS (i parametri di input sono stati modificati dall'utente) cancelliamo l'elenco list_object e impostiamo name_symbol variabile su NULL. In altri casi, l'expert non fa nulla, ma se vuoi aggiungere qualcosa, leggi i commenti.

        OnEvent() è un metodo per l'elaborazione degli eventi del terminale client. Gli eventi vengono generati dal terminale client quando l'utente lavora con il grafico. I dettagli possono essere trovati nella documentazione del linguaggio MQL5. In questo l’Expert Advisor è stato utilizzato il CHARTEVENT_OBJECT_CLICK dell'evento grafico. Cliccando sull'elemento istogramma mostra i livelli POC secondari e inverte il colore dell'istogramma.

        OnTimer(void) è un metodo per l'elaborazione degli eventi timer. Non viene utilizzato nei miei programmi, ma se si desidera aggiungere alcune azioni timer (ad esempio, per mostrare l'ora) - è qui. Prima dell'uso è necessario aggiungere la seguente riga al costruttore della classe:

        EventSetTimer(time in seconds);

        E la seguente riga al distruttore:

        EventKillTimer(); 

        prima di chiamare il metodo Deinit (REASON_CHARTCLOSE).

        Abbiamo preso in considerazione la classe CExpert; è stata creata per la dimostrazione dei metodi della classe CPriceHistogram.

        4.3. ClassPriceHistogram.mqh
        //+------------------------------------------------------------------+
        //|   Class CPriceHistogram                                          |
        //|   Class description                                              |
        //+------------------------------------------------------------------+
        class CPriceHistogram : public CObject
          {
        private:
           // Class variables
           double            high_day,low_day;
           bool              Init_passed;      // Flag if the initialization has passed or not
           CChartObjectTrend *POCLine;
           CChartObjectTrend *SecondTopPOCLine,*SecondBottomPOCLine;
           CChartObjectText  *POCLable;
           CList             ListHistogramInner; // list for inner lines storage 
           CList             ListHistogramOuter; // list for outer lines storage
           bool              show_level;         // to show values of level
           bool              virgin;             // is it virgin
           bool              show_second_poc;    // show secondary POC levels
           double            second_poc_top;     // value of the top secondary POC level
           double            second_poc_bottom;  // value of the bottom secondary POC level
           double            poc_value;          // POC level value
           color             poc_color;          // color of POC level
           datetime          poc_start_time;
           datetime          poc_end_time;
           bool              show_histogram;     // show histogram  
           color             inner_color;        // inner color of the histogram
           color             outer_color;        // outer color of the histogram
           uint              range_percent;      // percent range
           datetime          time_start;         // start time for construction
           datetime          time_end;           // final time of construction
        public:
           // Class constructor
                             CPriceHistogram();
           // Class destructor
                            ~CPriceHistogram(){Delete();}
           // Class initialization
           bool              Init(datetime time_open,datetime time_close,bool showhistogram);
           // To level value
           void              ShowLevel(bool show){show_level=show; if(Init_passed) RefreshPOCs();}
           bool              ShowLevel(){return(show_level);}
           // To show histogram
           void              ShowHistogram(bool show);
           bool              ShowHistogram(){return(show_histogram);}
           // To show Secondary POC levels
           void              ShowSecondaryPOCs(bool show){show_second_poc=show;if(Init_passed)RefreshPOCs();}
           bool              ShowSecondaryPOCs(){return(show_second_poc);}
           // To set color of POC levels
           void              ColorPOCs(color col){poc_color=col; if(Init_passed)RefreshPOCs();}
           color             ColorPOCs(){return(poc_color);}
           // To set internal colour of histogram
           void              ColorInner(color col);
           color             ColorInner(){return(inner_color);}
           // To set outer colour of histogram
           void              ColorOuter(color col);
           color             ColorOuter(){return(outer_color);}
           // To set percent range
           void              RangePercent(uint percent){range_percent=percent; if(Init_passed)calculationPOCs();}
           uint              RangePercent(){return(range_percent);}
           // Returns value of virginity of POC level
           bool              VirginPOCs(){return(virgin);}
           // Returns starting time of histogram construction
           datetime          GetStartDateTime(){return(time_start);}
           // Updating of POC levels
           bool              RefreshPOCs();
        private:
           // Calculations of the histogram and POC levels
           bool              calculationPOCs();
           // Class delete
           void              Delete();
          }; 

        Nella descrizione della classe, ho cercato di fornire commenti per variabili e metodi di classe. Consideriamo alcuni di loro in dettaglio.

        //+------------------------------------------------------------------+
        //|   Class initialization                                           |
        //+------------------------------------------------------------------+
        bool CPriceHistogram::Init(datetime time_open,datetime time_close,bool showhistogram) 

        Questo metodo utilizza tre parametri di input: l'apertura dell'edificio, l'ora di chiusura della costruzione e una bandiera che indica di costruire un istogramma o solo i livelli di LOC.

        Nel mio esempio (classe CExpert) i parametri di input vengono passati al giorno di apertura e all'ora di apertura del giorno successivo day_time_open [i] + PeriodSeconds (PERIOD_D1). Ma quando usi questa classe, nulla impedisce di chiedere, ad esempio, il tempo della sessione europea, americana o la dimensione del divario nella settimana, nel mese, ecc.

        //+---------------------------------------------------------------------------------------+
        //|   Calculations of the histogram and POCs levels                                       |
        //+---------------------------------------------------------------------------------------+
        bool CPriceHistogram::calculationPOCs() 

        In questo metodo, l'origine di tutti i livelli e i calcoli della loro costruzione, è un metodo privato chiuso, inaccessibile dall'esterno.

        // We get the data from time_start to time_end
           int err=0;
           do
             {
              //--- for each bar we are copying the open time
              rates_time=CopyTime(NULL,PERIOD_M1,time_start,time_end,iTime);
              if(rates_time<0)
                 PrintErrorOnCopyFunction("CopyTime",_Symbol,PERIOD_M1,GetLastError());
        
              //--- for each bar we are copying the High prices
              rates_high=CopyHigh(NULL,PERIOD_M1,time_start,time_end,iHigh);
              if(rates_high<0)
                 PrintErrorOnCopyFunction("CopyHigh",_Symbol,PERIOD_M1,GetLastError());
        
              //--- for each bar we are copying the Low prices
              rates_total=CopyLow(NULL,PERIOD_M1,time_start,time_end,iLow);
              if(rates_total<0)
                 PrintErrorOnCopyFunction("CopyLow",_Symbol,PERIOD_M1,GetLastError());
        
              err++;
             }
           while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS&&!IsStopped());
           if(err>=AMOUNT_OF_ATTEMPTS)
             {
              return(false);
             }
           poc_start_time=iTime[0];
           high_day=iHigh[ArrayMaximum(iHigh,0,WHOLE_ARRAY)];
           low_day=iLow[ArrayMinimum(iLow,0,WHOLE_ARRAY)];
           int count=int((high_day-low_day)/_Point)+1;
        // Count of duration of a finding of the price at each level
           int ThicknessOfLevel[];    // create an array for count of ticks
           ArrayResize(ThicknessOfLevel,count);
           ArrayInitialize(ThicknessOfLevel,0);
           for(int i=0;i<rates_total;i++)
             {
              double C=iLow[i];
              while(C<iHigh[i])
                {
                 int Index=int((C-low_day)/_Point);
                 ThicknessOfLevel[Index]++;
                 C+=_Point;
                }
             }
           int MaxLevel=ArrayMaximum(ThicknessOfLevel,0,count);
           poc_value=low_day+_Point*MaxLevel;

        Innanzitutto, otteniamo i dati della cronologia delle barre dei minuti per un certo periodo di tempo (iTime [], iHigh[], iLow[]). Quindi troviamo l'elemento massimo e minimo di iHigh[] i e Low[]. Quindi calcoliamo il numero di punti (conteggio) dal minimo al massimo e riserviamo l’array ThicknessOfLevel con gli elementi ThicknessOfLevel. Nel ciclo passiamo attraverso la candela di ogni minuto da Bassa ad Alta e aggiungiamo i dati della presenza del periodo di tempo a questo livello di prezzo. Quindi troviamo l'elemento massimale dell'array ThicknessOfLevel, sarà il livello al quale il prezzo è stato il tempo più lungo. Questo è il nostro livello POC.

        // Search for the secondary POCs
           int range_min=ThicknessOfLevel[MaxLevel]-ThicknessOfLevel[MaxLevel]*range_percent/100;
           int DownLine=0;
           int UpLine=0;
           for(int i=0;i<count;i++)
             {
              if(ThicknessOfLevel[i]>=range_min)
                {
                 DownLine=i;
                 break;
                }
             }
           for(int i=count-1;i>0;i--)
             {
              if(ThicknessOfLevel[i]>=range_min)
                {
                 UpLine=i;
                 break;
                }
             }
           if(DownLine==0)
              DownLine=MaxLevel;
           if(UpLine==0)
              UpLine=MaxLevel;
           second_poc_top=low_day+_Point*UpLine;
           second_poc_bottom=low_day+_Point*DownLine;
        

        Il prossimo passo è trovare i livelli POC secondari. Ricordiamo che il nostro diagramma è diviso. Ricordiamo che il nostro istogramma è diviso in due gamme, quella interna ed esterna (visualizzata in diversi colori) e la gamma dimensionale è definita in percentuale di tempo del prezzo a questo livello. L'intervallo dei confini interni sono livelli POC secondari.

        Dopo aver trovato l'intervallo percentuale POC secondario - Bordi, procedere alla costruzione dell'istogramma.

        // Histogram formation 
           if(show_histogram)
             {
              datetime Delta=(iTime[rates_total-1]-iTime[0]-PeriodSeconds(PERIOD_H1))/ThicknessOfLevel[MaxLevel];
              int step=1;
              
              if(count>100)
                 step=count/100// Calculate the step of the histogram (100 lines as max)
        
              ListHistogramInner.Clear();
              ListHistogramOuter.Clear();
              for(int i=0;i<count;i+=step)
                {
                 string name=TimeToString(time_start)+" "+IntegerToString(i);
                 double StartY= low_day+_Point*i;
                 datetime EndX= iTime[0]+(ThicknessOfLevel[i])*Delta;
        
                 CChartObjectTrend *obj=new CChartObjectTrend();
                 obj.Create(0,name,0,poc_start_time,StartY,EndX,StartY);
                 obj.Background(true);
                 if(i>=DownLine && i<=UpLine)
                   {
                    obj.Color(inner_color);
                    ListHistogramInner.Add(obj);
                   }
                 else
                   {
                    obj.Color(outer_color);
                    ListHistogramOuter.Add(obj);
                   }
                }
             }
        
        

        Va detto che per ridurre il carico sul terminale, porto sullo schermo un massimo di 100 righe per ogni istogramma. Le righe dell'istogramma sono memorizzate in due elenchi e ListHistogramInner ListHistogramOuter, che sono gli oggetti già noti a noi classe CList. Ma questi puntatori sono memorizzati in una classe standard di oggetti CChartObjectTrend. Perché due liste, credo si possa intuire dal titolo per poter cambiare l'istogramma dei colori.

        // We receive data beginning from the final time of the histogram till current time
           err=0;
           do
             {
              rates_time=CopyTime(NULL,PERIOD_M1,time_end,last_tick.time,iTime);
              rates_high=CopyHigh(NULL,PERIOD_M1,time_end,last_tick.time,iHigh);
              rates_total=CopyLow(NULL,PERIOD_M1,time_end,last_tick.time,iLow);
              err++;
             }
           while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<AMOUNT_OF_ATTEMPTS);
        // If there isn't history, the present day, level is virgin, we hoist the colours
           if(rates_time==0)
             {
              virgin=true;
             }
           else
        // Otherwise we check history
             {
              for(index=0;index<rates_total;index++)
                 if(poc_value<iHigh[index] && poc_value>iLow[index]) break;
        
              if(index<rates_total)   // If level has crossed
                 poc_end_time=iTime[index];
              else
                 virgin=true;
             }
           if(POCLine==NULL)
             {     
              POCLine=new CChartObjectTrend();
              POCLine.Create(0,TimeToString(time_start)+" POC ",0,poc_start_time,poc_value,0,0);
             }
           POCLine.Color(poc_color);
           RefreshPOCs();

        Ho provato a progettare il CPriceHistogram con tutti i metodi necessari, se insufficiente, puoi aggiungerti e ti aiuterò con esso.

        Sommario

        Ancora una volta vorrei ricordare che l'Istogramma dei Prezzi è affidabile, ma lo strumento intuitivo, quindi i segnali di conferma sono necessari per il suo utilizzo.

        Grazie per il tuo interesse. Sono pronto a rispondere a tutte le tue domande.

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

        Come Scambiare i Dati: Una DLL per MQL5 in 10 minuti Come Scambiare i Dati: Una DLL per MQL5 in 10 minuti
        Ora, non sono così tanti gli sviluppatori che ricordano come scrivere una semplice DLL e quali sono le caratteristiche speciali dei diversi binding di sistema. Usando diversi esempi, cercherò di mostrare l'intero processo di creazione della semplice DLL in 10 minuti, oltre a discutere alcuni dettagli tecnici della nostra implementazione vincolante. Mostrerò il processo passo dopo passo della creazione di DLL in Visual Studio con esempi di scambio di diversi tipi di variabili (numeri, array, stringhe, ecc.). Inoltre spiegherò come proteggere il tuo terminale client da arresti anomali nelle DLL personalizzate.
        Strategie d'Ordine. Expert Advisor Multiuso Strategie d'Ordine. Expert Advisor Multiuso
        Questo articolo è incentrato sulle strategie che utilizzano attivamente gli ordini in sospeso, un metalinguaggio che può essere creato per descrivere formalmente tali strategie e l'uso di un Expert Advisor multiuso il cui funzionamento si basa su tali descrizioni
        Scambio di Dati tra Indicatori: È Facile Scambio di Dati tra Indicatori: È Facile
        Vogliamo creare un tale ambiente che fornisca l'accesso ai dati degli indicatori allegati a un grafico e che abbia le seguenti proprietà: assenza di copia dei dati; modifica minima del codice dei metodi disponibili, se è necessario utilizzarli; È preferibile il codice MQL (ovviamente dobbiamo usare DLL, ma useremo solo una dozzina di stringhe di codice C++). L'articolo descrive un metodo semplice per sviluppare un ambiente di programma per il terminale MetaTrader, che fornirebbe i mezzi per accedere ai buffer degli indicatori da altri programmi MQL.
        Operazioni di Trading in MQL5 - È Facile Operazioni di Trading in MQL5 - È Facile
        Quasi tutti i trader vengono sul mercato per fare soldi, ma alcuni trader apprezzano anche il processo in sé. Tuttavia, non è solo il trading manuale che ti può offrire un'esperienza entusiasmante. Anche lo sviluppo automatizzato dei sistemi di trading può essere piuttosto coinvolgente. Creare un robot di trading può essere interessante quanto leggere un buon romanzo giallo.