#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 del 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; } |