Ciao! Sono imbattuto nelle mie peregrinazioni in una formulètta molto carina, che si chiama TVB. Molto bello. Ti Voglio Bene. Promette bene no?
Ecco, no.
Nello specifico, l’indicatore TVB indica il True Value of Bar, cioè il valore reale di una barra.
Come si calcola questo indicatore? La formula è la seguente:
TVB= 3*Close-(Open+High+Low)
Analizziamo cosa ci potrebbe dire questo indicatore:
- Prendo il close, quindi analizzo i dati High, Open e Low in base alla chiusura della barra.
- Lo moltiplico per 3 e ci sottraggo la somma di High, Open e Low, andandomi a suggerire che più Open e High sono maggiori di Close più il valore finale sarà negativo, viceversa il valore sarà positivo se High sarà simile a Close e Open sarà maggiore di Close.
- L’indicatore quindi mi si presenterà come un indi a zero-line cross, e mi restituirà valori positivi o negativi.
Perché mi piace molto questo indicatore?
Innanzitutto perché permette di avere un valore “arbitrario”, una sorta di “punteggio” dato alla barra, in base al suo sviluppo.
Inoltre, potrebbe diventare un buon indicatore di inversione e di inizio trend, grazie alla capacità che ha di rivelare la forza dei 4 livelli HLOC di ciascuna quantizzazzione temporale (ahahahah volevo fare il figo. Intendo barra. Candela. Time Frame. Niente di complesso)
Conoscendo il motivo che ti spinge a leggere questo blog, ti guiderò nella costruzione dell’indicatore per MT4.
Cominciamo a creare un nuovo file
E ricordiamoci di flaggare “indicatore in una finestra separata:
Da qui, abbiamo il nostro file semplice semplice per la creazione del nostro indi, e, siccome utilizzeremo degli array già presenti nella funzione OnCalculate, non avremo bisogno di particolari funzioni, ma solo di un corretto utilizzo degli stessi.
Cominciamo a dichiarare i buffer che serviranno per plottare il nostro indi. Io voglio che il valore TVB sia reso come istogramma basato su una zero-line. Non ci vuole una scienza, perchè sarà automatico.
Tuttavia
Voglio che l’istogramma sia colorato in un modo diverso se è >0 oppure <0. Per fare ciò, dichiaro due buffer (ne dichiaro 3 in realtà, così ne ho uno vuoto per il gran finale):
#property indicator_buffers 3 #property indicator_plots 3
E per ciascun buffer dichiaro le caratteristiche dello stesso (nome, tipo, colore, stile,dimensione):
//--- plot positivo #property indicator_label1 "Positive" #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrSteelBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 3 //--- plot negativo #property indicator_label2 "Negative" #property indicator_type2 DRAW_HISTOGRAM #property indicator_color2 clrCrimson #property indicator_style2 STYLE_SOLID #property indicator_width2 3
Ciascun buffer viene plottato in base ai valori contenuti in un array. un array che deve contenere numeri con la virgola, per cui dichiareremo i buffer come di tipo “double“:
double Positive[]; double Negative[];
Tutto questo lo dichiariamo nella prima parte del codice, fuori dalle tre principali funzioni di un file mq4.
Ora ci occupiamo dell’OnInit(), la funzione che viene richiamata quando attiviamo per la prima volta l’indicatore. Dovremo quindi dare alcune istruzioni per inizializzare correttamente il tutto. All’interno delle graffe della funzione OnInit(), andiamo a scrivere:
IndicatorShortName("Ti Voglio Bene");
//Dichiaro che l'index dei dati "positive" sarà il numero 0, e l'1 per i dati "negative"
SetIndexBuffer(0,Positive);
SetIndexBuffer(1,Negative);
//Dichiaro che il numero di cifre dopo la virgola sarà uguale a quello dell simbolo su cui l'indicatore si applica
IndicatorDigits(_Digits);
// Dichiaro che gli array andranno letti dalla candela più recente alla meno recente
ArraySetAsSeries(Positive,true);
ArraySetAsSeries(Negative,true);
Benissimo. Ora andiamo a scrivere la funzione che ci calcolerà il valore TVB, secondo la formula espressa all’inizio dell’articolo. Ci portiamo nella sezione OnCalculate, che si presenta così:
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- //--- return value of prev_calculated for next call return(rates_total); }
Noi utilizzeremo gli array ricorsivi open[], close[], high[] e low[].
Scriviamo la formula, e facciamo in modo che venga calcolata su tutto il grafico. Per fare ciò, dobbiamo dire a cosa corrisponde ciascun dato all’interno dell’array. Utilizzeremo un for loop per ottenere questa cosa.
int limit=prev_calculated; for(int i=limit; i<rates_total; i++) { double value=3*close[i]-(open[i]+high[i]+low[i]); Positive[i]=value; }
La variabile value ci serve per la prossima tappa: il cambio colore. Ora, se montiamo l’indi sul grafico, dovrebbe renderizzare così:
Ora andiamo a produrre il cambio colore: Io voglio che quando il valore del TVB sia negativo, diventi rosso e quando è positivo diventi blu. In Meta Trader 4 questo è ottenimbile utilizzando due diversi buffer (tant’è che te li ho fatti scrivere prima! 🙂
Andiamo a mettere una condizione IF, grazie alla quale possiamo attivare o disattivare i buffer:
Cancelliamo la linea dopo il calcolo della variabile value e inseriamo due condizioni:
if(value>0) { Positive[i]=value; Negative[i]=EMPTY_VALUE; } if(value<0) { Positive[i]=EMPTY_VALUE; Negative[i]=value; }
Dichiarando il valore del buffer come EMPTY_VALUE stiamo dicendo alla MT che in quel posto dell’array il valore è vuoto, quindi il plot dell’indicatore NON va tracciato. Molto meglio ora:
Abbiamo un indicatore che, per ogni barra, ci traccia il valore assoluto del movimento della barra stessa, indicando se è positivo o negativo. Se noti, non tutte le barre negative hanno un TVB negativo, e viceversa non tutte le barre positive hanno un TVB positivo. Proprio perché dipende dall’escursione tra i vari valori HLOC della barra stessa.
E sticazzi?
Lo so, lo so. Sembra un’informazione molto inutile. E così com’è lo è eccome. Proviamo ad aggiungere un plot che mi tracci la media mobile dei valori TVB. Per fare ciò, dobbiamo rifattorizzare un po’ il lavoro.
Innanzitutto ora la variabile value dovrebbe diventare anch’essa un array. E successivamente su questo array dobbiamo applicare la funzione iMAonArray (media mobile dell’array).
Partiamo aggiungendo un ulteriore buffer per stoccare il valore del TVB in modo assoluto, e utilizziamo un secondo buffer aggiuntivo per il nostro “segnale”.
//--- plot Segnale #property indicator_label3 "Signal" #property indicator_type3 DRAW_LINE #property indicator_color3 clrBlack #property indicator_style3 STYLE_DOT #property indicator_width3 1 #property indicator_color4 clrNONE
Ed andiamo ad aggiungere dei parametri di input per il tipo di media mobile che andiamo ad applicare:
input int InpMAPeriod=14; //MA smoothing period input ENUM_MA_METHOD InpMAMode=MODE_SMA; // MA MODE
E i buffer aggiuntivi
double Value[]; double Signal[];
Aggiungiamo nell’OnInit che li vogliamo ordinati dalla barra più recente (indice = 0) alla meno recente:
SetIndexBuffer(2,Signal); SetIndexBuffer(3,Value); ArraySetAsSeries(Signal,true); ArraySetAsSeries(Value,true);
E modifichiamo il main loop del OnCalculate in questo modo:
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int limit=prev_calculated; for(int i=limit; i<rates_total; i++) { Value[i]=3*close[i]-(high[i]+low[i]+open[i]); if(Value[i]>0) { Positive[i]=Value[i]; Negative[i]=EMPTY_VALUE; } if(Value[i]<0) { Positive[i]=EMPTY_VALUE; Negative[i]=Value[i]; } Signal[i]=iMAOnArray(Value,0,InpMAPeriod,0,InpMAMode,i); } //--- return value of prev_calculated for next call return(rates_total); }
Così facendo abbiamo il nostro zero line cross, che potrebbe indicarci l’inizio (o la fine) di un trend!
Ora non ci resta che fare un backtest, vedendo se questo indi può aiutarci nella costruzione o nel miglioramento della nostra strategia, magari come indicatore di conferma, unito ad un indicatore di segnale.
Scrivi nei commenti se e come vorrai approfondire lo studio di questo indicatore!
E naturalmente, ecco il codice completo di questo articolo!
//+------------------------------------------------------------------+ //| TVB.mq4 | //| D'ario Woollover | //| https://www.automazionetrading.com | //+------------------------------------------------------------------+ #property copyright "D'ario Woollover" #property link "https://www.automazionetrading.com" #property version "1.00" #property strict #property indicator_separate_window #property indicator_buffers 4 #property indicator_plots 4 #property indicator_level1 0.0 //--- plot positivo #property indicator_label1 "Positive" #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrSteelBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 3 //--- plot negativo #property indicator_label2 "Negative" #property indicator_type2 DRAW_HISTOGRAM #property indicator_color2 clrCrimson #property indicator_style2 STYLE_SOLID #property indicator_width2 3 //--- plot Segnale #property indicator_label3 "Signal" #property indicator_type3 DRAW_LINE #property indicator_color3 clrBlack #property indicator_style3 STYLE_SOLID #property indicator_width3 2 #property indicator_label4 "Value" #property indicator_type4 DRAW_NONE #property indicator_color4 clrNONE input int InpMAPeriod=14; //MA smoothing period input ENUM_MA_METHOD InpMAMode=MODE_SMA; // MA MODE //--- i 4 buffer double Positive[]; double Negative[]; double Value[]; double Signal[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping IndicatorShortName("Ti Voglio Bene(" + IntegerToString(InpMAPeriod)+")"); SetLevelValue(0,0.0); SetLevelStyle(STYLE_DOT,1,clrGray); //Dichiaro che l'index dei dati "positive" sarà il numero 0, e l'1 per i dati "negative" SetIndexBuffer(0,Positive); SetIndexBuffer(1,Negative); SetIndexBuffer(2,Signal); SetIndexBuffer(3,Value); //Dichiaro che il numero di cifre dopo la virgola sarà uguale a quello dell simbolo su cui l'indicatore si applica IndicatorDigits(_Digits); // Dichiaro che gli array andranno letti dalla candela più recente alla meno recente ArraySetAsSeries(Positive,true); ArraySetAsSeries(Negative,true); ArraySetAsSeries(Signal,true); ArraySetAsSeries(Value,true); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int limit=prev_calculated; for(int i=limit; i<rates_total; i++) { Value[i]=3*close[i]-(high[i]+low[i]+open[i]); if(Value[i]>0) { Positive[i]=Value[i]; Negative[i]=EMPTY_VALUE; } if(Value[i]<0) { Positive[i]=EMPTY_VALUE; Negative[i]=Value[i]; } Signal[i]=iMAOnArray(Value,0,InpMAPeriod,0,InpMAMode,i); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
C’è un errore nella riga:
const datetime time[], invece doveva essere: const datetime & time[],
ma a parte questo non fa nulla sullo schermo.
Deve essere un aggiornamento della Meta Trader, a volte capita che gli indi sballino un po’.
Grazie per la segnalazione!
Ora funziona, bisogna far ripartire la MT4 !