#property description "L'indicatore mostra candele di un timeframe più grande sul timeframe corrente."
//--- impostazioni indicatore
#property indicator_chart_window
#property indicator_buffers 16
#property indicator_plots 8
//---- plot 1
#property indicator_label1 "BearBody"
#property indicator_color1 clrSeaGreen,clrSeaGreen
//---- plot 2
#property indicator_label2 "BearBodyEnd"
#property indicator_color2 clrSeaGreen,clrSeaGreen
//---- plot 3
#property indicator_label3 "BearShadow"
#property indicator_color3 clrSalmon,clrSalmon
//---- plot 4
#property indicator_label4 "BearShadowEnd"
#property indicator_color4 clrSalmon,clrSalmon
//---- plot 5
#property indicator_label5 "BullBody"
#property indicator_color5 clrOlive,clrOlive
//---- plot 6
#property indicator_label6 "BullBodyEnd"
#property indicator_color6 clrOlive,clrOlive
//---- plot 7
#property indicator_label7 "BullShadow"
#property indicator_color7 clrSkyBlue,clrSkyBlue
//---- plot 8
#property indicator_label8 "BullShadowEnd"
#property indicator_color8 clrSkyBlue,clrSkyBlue
//--- costanti predefinite
#define INDICATOR_EMPTY_VALUE 0.0
//--- parametri di input
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // Timeframe per il calcolo dell'indicatore
input datetime InpDateStart=D'2013.01.01 00:00'; // Data di inizio analisi
//--- buffer indicatore per candele ribassiste
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- indicator buffers for bullish candlesticks
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- variabili globali
datetime ExtTimeBuff[]; // più largo buffer di tempo del timeframe
int ExtSize=0; // grandezza del buffer tempo
int ExtCount=0; // indice dentro il buffer tempo
int ExtStartPos=0; // posizione iniziale per il calcolo dell'indicatore
bool ExtStartFlag=true; // flag ausiliaria per la ricezione della posizione iniziale
datetime ExtCurrentTime[1]; // ultimo orario di creazione della barra più ampia
datetime ExtLastTime; // ultimo orario dal timeframe più ampio, per cui viene eseguito il calcolo
bool ExtBearFlag=true; // flag per definire l'ordine di scrittura dei dato nei buffer indicatore bearish
bool ExtBullFlag=true; // flag per definire l'ordine di scrittura dei dato nei buffer indicatore bullish
int ExtIndexMax=0; // indice dell'elemento massimo nell' array
int ExtIndexMin=0; // indice dell'elemento minimo nell'array
int ExtDirectionFlag=0; // direzione del movimento di prezzo per la corrente candela
//--- spostamento tra il prezzo di apertura e di chiusura della candela per il corretto disegnamento
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+--------------------------------------------------------------------------------+
//| Riempie la parte fondamentale della candela |
//+--------------------------------------------------------------------------------+
void FillCandleMain(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
int &index_max,int &index_min)
{
//--- trova l'indice degli elementi massimi e minimi nell'array
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // massimo in High
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // minimo in Low
//--- definisce quante barre dal corrente lasso di tempo devono essere compilate
int count=fill_index-start+1;
//--- se il prezzo di chiusura alla prima barra eccede quella dell'ultima barra, la candela è ribassista
if(open[start]>close[last])
{
//--- se la candela è stata rialzista prima, cancella i valori del buffer indicatori rialzista
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- candela bearish(ribassista)
ExtDirectionFlag=-1;
//--- genera la candela
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- esce dalla funzione
return;
}
//--- se il prezzo di chiusura alla prima barra è inferiore a quello dell'ultima barra, la candela è rialzista
if(open[start]<close[last])
{
//--- se la candela è stata ribassista prima, cancella i valori del buffer indicatori ribassista
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- candela bullish(rialzista)
ExtDirectionFlag=1;
//--- genera la candela
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- esce dalla funzione
return;
}
//--- se siete in questa parte della funzione, il prezzo di apertura alla prima barra è pari a
//--- al prezzo di chiusura dell''ultima barra; tale candela è considerata ribassista
//--- se la candela è stata rialzista prima, cancella i valori del buffer indicatore rialzista
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- candela bearish
ExtDirectionFlag=-1;
//--- se i prezzi close ed open sono uguali, utilizza lo shift per una corretta visualizzazione
if(high[index_max]!=low[index_min])
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],start,count,ExtBearFlag);
else
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,
open[start],open[start]-ExtEmptyBodySize,high[index_max],
high[index_max]-ExtEmptyBodySize,start,count,ExtBearFlag);
}
//+--------------------------------------------------------------------------------+
//| Riempie la fine della candela |
//+--------------------------------------------------------------------------------+
void FillCandleEnd(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
const int index_max,const int index_min)
{
//--- non disegnare in caso di barra singola
if(last-start==0)
return;
//--- se il prezzo di chiusura alla prima barra eccede quella dell'ultima barra, la candela è ribassista
if(open[start]>close[last])
{
//--- genera la fine della candela
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- esce dalla funzione
return;
}
//--- se il prezzo di chiusura alla prima barra è inferiore a quello dell'ultima barra, la candela è rialzista
if(open[start]<close[last])
{
//--- genera la fine della candela
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- esce dalla funzione
return;
}
//--- se siete in questa parte della funzione, il prezzo di apertura alla prima barra è pari a
//--- al prezzo di chiusura dell''ultima barra; tale candela è considerata ribassista
//--- genera la fine della candela
if(high[index_max]!=low[index_min])
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],fill_index,ExtBearFlag);
else
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],high[index_max]-ExtEmptyBodySize,fill_index,ExtBearFlag);
}
//+--------------------------------------------------------------------------------+
//| Funzione di inizializzazione Indicatore Personalizzato |
//+--------------------------------------------------------------------------------+
int OnInit()
{
//--- imposta l'indicatore del periodo
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- mostra i dati dei prezzi in primo piano
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- lega i buffer indicatore
SetIndexBuffer(0,ExtBearBodyFirst);
SetIndexBuffer(1,ExtBearBodySecond);
SetIndexBuffer(2,ExtBearBodyEndFirst);
SetIndexBuffer(3,ExtBearBodyEndSecond);
SetIndexBuffer(4,ExtBearShadowFirst);
SetIndexBuffer(5,ExtBearShadowSecond);
SetIndexBuffer(6,ExtBearShadowEndFirst);
SetIndexBuffer(7,ExtBearShadowEndSecond);
SetIndexBuffer(8,ExtBullBodyFirst);
SetIndexBuffer(9,ExtBullBodySecond);
SetIndexBuffer(10,ExtBullBodyEndFirst);
SetIndexBuffer(11,ExtBullBodyEndSecond);
SetIndexBuffer(12,ExtBullShadowFirst);
SetIndexBuffer(13,ExtBullShadowSecond);
SetIndexBuffer(14,ExtBullShadowEndFirst);
SetIndexBuffer(15,ExtBullShadowEndSecond);
//--- imposta alcuni valori proprietà, per creare l'indicatore
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // tipo di costruzione grafica
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // stile di disegno della linea
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // spessore di disegno della linea
}
//---
return(INIT_SUCCEEDED);
}
//+--------------------------------------------------------------------------------+
//| Funzione di iterazione indicatore personalizato |
//+--------------------------------------------------------------------------------+
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[])
{
//--- nel caso in cui non ci siano ancora barre calcolate
if(prev_calculated==0)
{
//--- riceve l' orario di arrivo del frame's bar più grande
if(!GetTimeData())
return(0);
}
//--- imposta l'indicizzazione diretta
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- variabile iniziale per il calcolo delle barre
int start=prev_calculated;
//--- se la barra viene generata, ricalcola il valore dell'indicatore su di essa
if(start!=0 && start==rates_total)
start--;
//--- Il ciclo per calcolare i valori degli indicatori
for(int i=start;i<rates_total;i++)
{
//--- riempie gli elementi del buffer indicatore per valori vuoti
FillIndicatorBuffers(i);
//--- esegue il calcolo per le barre iniziando dalla data InpDateStart
if(time[i]>=InpDateStart)
{
//--- definisce la posizione, dal quale i valori devono essere mostrati, per la prima volta
if(ExtStartFlag)
{
//--- conserva il numero di barre iniziali
ExtStartPos=i;
//--- definisce la prima data dal timeframe più grande che eccedente time[i]
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- modifica il valore del flag per non eseguire nuovamente questo blocco
ExtStartFlag=false;
}
//--- controlla se ci sono ancora elementi nell'array
if(ExtCount<ExtSize)
{
//--- attende il valore del timeframe corrente per raggiungere quello del timeframe più ampio
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- disegna la parte principale della candela (senza riempire l'area tra l'ultima e la penultima barra)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- riempie la fine della candela (l'area tra l'ultima e la penultima barra)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- slitta la posizione iniziale per disegnare la prossima candela
ExtStartPos=i;
//--- incrementa il contatore dell'array
ExtCount++;
}
else
continue;
}
else
{
//--- resetra i valori dell'array
ResetLastError();
//--- riceve l'ultima data dal timeframe più grande
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Data copy error, code = ",GetLastError());
return(0);
}
//--- se la nuova data è successiva, arresta la generazione di candele
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- sgombera l'area tra l' ultima e penultima barra nel principale buffer indicatore
ClearEndOfBodyMain(i-1);
//--- compila l'area utilizzando buffer indicatori ausiliari
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- slitta la posizione iniziale per disegnare la prossima candela
ExtStartPos=i;
//--- resetta il flag della direzione del prezzo
ExtDirectionFlag=0;
//--- memorizza la nuova ultima data
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- genera la candela
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- restituisce il valore di prev_calculated per la prossima chiamata
return(rates_total);
}
//+--------------------------------------------------------------------------------+
//| Controlla la correttezza del periodo dell'indicatore specificato |
//+--------------------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- il periodo dell'indicatore deve eccedere il timeframe con il quale esso viene visualizzato
if(current_period>=high_period)
{
Print("Error! Il valore del periodo dell'indicatore deve superare il valore del timeframe corrente! ");
return(false);
}
//--- se il periodo dell'indicatore è di una settimana o mese, il periodo è corretto
if(high_period>32768)
return(true);
//--- converte i valori del periodo in minuti
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- il periodo dell'indicatore deve essere multiplo del timeframe su cui è visualizzato
if(high_period%current_period!=0)
{
Print("Error! Il valore del periodo dell' indicatore deve essere multiplo del valore del periodo del timeframe corrente! ");
return(false);
}
//--- il periodo dell'indicatore deve superare il timeframe su cui è visualizzato, di 3 o più volte
if(high_period/current_period<3)
{
Print("Error! Il periodo dell'indicatore dovrebbe superare l'attuale timeframe di 3 o più volte! ");
return(false);
}
//--- Il periodo indicatore è corretto per il timeframe corrente
return(true);
}
//+--------------------------------------------------------------------------------+
//| Riceve i dati temporali dal lasso di tempo più ampio |
//+--------------------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- resetta il valore dell' errore
ResetLastError();
//--- copia tutti i dati per il tempo corrente
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- riceve il codice dell'errore
int code=GetLastError();
//--- stampa il messaggio d'errore
PrintFormat("Errore copia dei dati! %s",code==4401
? "Lo storico è ancora in fase di uploading!"
: "Code = "+IntegerToString(code));
//--- restituisce false per fare un nuovo tentativo di download dei dati
return(false);
}
//--- riceve la grandezza dell'array
ExtSize=ArraySize(ExtTimeBuff);
//--- imposta l'indice di loop per l'array a zero
ExtCount=0;
//--- imposta la posizione della candela corrente sul timeframe, a zero
ExtStartPos=0;
ExtStartFlag=true;
//--- memorizza l'ultimo valore di tempo dal timeframe più ampio
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- esecuzione avvenuta
return(true);
}
//+-----------------------------------------------------------------------------------------+
//| La funzione costituisce la parte principale della candela. A seconda del flag |
//| del suo valore, la funzione definisce quali dati e array devono |
//| essere usati per la corretta visualizzazione. |
//+-----------------------------------------------------------------------------------------+
void FormCandleMain(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int start,const int count,const bool flag)
{
//--- controlla il valore del flag
if(flag)
{
//--- genera il corpo della candela
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- genera l'ombra della candela
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- genera il corpo della candela
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- genera l'ombra della candela
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+-------------------------------------------------------------------------------+
//| La funzione costituisce l'estremità della candela. A seconda del valore della flag, |
//| la funzione definisce quali dati ed array devono |
//| essere usati per la corretta visualizzazione. |
//+-------------------------------------------------------------------------------+
void FormCandleEnd(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int end,bool &flag)
{
//--- controlla il valore del flag
if(flag)
{
//--- genera la fine del corpo della candela
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- genera la fine dell'ombra della candela
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- cambia il valore della flag in quello opposto
flag=false;
}
else
{
//--- genera la fine del corpo della candela
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- genera la fine dell'ombra della candela
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- cambia il valore della flag in quello opposto
flag=true;
}
}
//+--------------------------------------------------------------------------------------------+
//| Cancella la fine della candela (l'area tra l'ultima e la penultima |
//| barra |
//+--------------------------------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+-----------------------------------------------------------------------------------------+
//| Cancella la candela |
//+-----------------------------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- controlla
if(count!=0)
{
//--- riempie il buffer indicatore con valori vuoti
ArrayFill(body_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(body_snd,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_snd,start,count,INDICATOR_EMPTY_VALUE);
}
}
//+-----------------------------------------------------------------------------------------+
//| Genera la parte principale della candela |
//+-----------------------------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- controlla
if(count!=0)
{
//--- riempie il buffer indicatore con i valori
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+---------------------------------------------------------------------------------------+
//| Genera la fine della candela |
//+---------------------------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- riempie il buffer indicatore con i valori
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+--------------------------------------------------------------------------------+
//| _* Riempie gli elementi del buffer indicatore per valori vuoti |
//+--------------------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- imposta un valore vuoto nella cella del buffer indicatore
ExtBearBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
}
|