L'Istogramma dei Prezzi (Market Profile) e la sua implementazione in MQL5
"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:
- Il mercato è un'asta, e si muove nella direzione della fascia di prezzo dove l'offerta e la domanda sono più o meno uguali.
- 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.
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.
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:
- numero molto breve di barre nella cronologia per M5, per non parlare di M1;
- 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;;
- 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:
- il runtime dell'indicatore è critico;
- 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:
- il tempo di elaborazione non è critico per l’handler di eventi Init in OnTick ();
- 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.
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.
//+------------------------------------------------------------------+ //| 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
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso