#property description "L'indicateur affiche les bougies d'une période supérieure sur les bougies actuelles."
//--- paramètres de l'indicateur
#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
//--- constantes prédéfinies
#define INDICATOR_EMPTY_VALUE 0.0
//--- paramètres d'entrée
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // Période de calcul de l'indicateur
input datetime InpDateStart=D'2013.01.01 00:00'; // Date de début de l'analyse
//--- buffers de l'indicateur pour les bougies baissières
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- buffers de l'indicateur pour les bougies haussières
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- variables globales
datetime ExtTimeBuff[]; // buffer de la période supérieure
int ExtSize=0; // taille du buffer
int ExtCount=0; // indice dans le buffer
int ExtStartPos=0; // position initiale pour le calcul de l'indicateur
bool ExtStartFlag=true; // flag supplémentaire pour conserver la position initiale
datetime ExtCurrentTime[1]; // dernière heure de la génération de la barre de la période supérieure
datetime ExtLastTime; // dernière heure de la période supérieure pour laquelle le calcul est effectué
bool ExtBearFlag=true; // flag pour définir l'ordre d'écriture des données dans les buffers baissiers de l'indicateur
bool ExtBullFlag=true; // flag pour définir l'ordre d'écriture des données dans les buffers haussiers de l'indicateur
int ExtIndexMax=0; // indice de l'élément maximum du tableau
int ExtIndexMin=0; // indice de l'élément minimum du tableau
int ExtDirectionFlag=0; // direction du mouvement des prix pour la bougie courante
//--- décalage entre les prix open et close de la bougie pour un dessin correct
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| Remplissage de la partie basique de la bougie |
//+------------------------------------------------------------------+
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)
{
//--- trouve l'indice des éléments maximum et minimum des tableaux
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // maximum des High
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // minimum des Low
//--- définit combien de barre de la période actuelle doivent être remplies
int count=fill_index-start+1;
//--- si le prix de clôture de la première barre est supérieur à celui de la dernière barre, la bougie est baissière
if(open[start]>close[last])
{
//--- si la bougie était haussière avant, efface les valeurs des buffers haussiers de l'indicateur
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- bougie baissière
ExtDirectionFlag=-1;
//--- génère la bougie
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- sort de la fonction
return;
}
//--- si le prix de clôture de la première barre est inférieur à celui de la dernière barre, la bougie est haussière
if(open[start]<close[last])
{
//--- si la bougie était baissière avant, efface les valeurs des buffers baissiers de l'indicateur
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- bougie haussière
ExtDirectionFlag=1;
//--- génère la bougie
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- sort de la fonction
return;
}
//--- si vous arrivez dans cette partie de la fonction, le prix d'ouverture de la première barre est égal au
//--- prix de clôture de la dernière barre ; une telle bougie est considérée comme baissière
//--- si la bougie était haussière avant, efface les valeurs des buffers haussiers de l'indicateur
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- bougie baissière
ExtDirectionFlag=-1;
//--- si les prix de clôture et d'ouverture sont égaux, utilise le décalage pour un affichage correct
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);
}
//+------------------------------------------------------------------+
//| Remplit la fin de la bougie |
//+------------------------------------------------------------------+
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)
{
//--- ne dessine pas dans le cas d'une barre seule
if(last-start==0)
return;
//--- si le prix de clôture de la première barre est supérieur à celui de la dernière barre, la bougie est baissière
if(open[start]>close[last])
{
//--- génère la fin de la bougie
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- sort de la fonction
return;
}
//--- si le prix de clôture de la première barre est inférieur à celui de la dernière barre, la bougie est haussière
if(open[start]<close[last])
{
//--- génère la fin de la bougie
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- sort de la fonction
return;
}
//--- si vous arrivez dans cette partie de la fonction, le prix d'ouverture de la première barre est égal au
//--- prix de clôture de la dernière barre ; une telle bougie est considérée comme baissière
//--- génère la fin de la bougie
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);
}
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'indicateur personnalisé |
//+------------------------------------------------------------------+
int OnInit()
{
//--- vérifie la période de l'indicateur
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- affiche les prix au premier plan
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- lie les buffers de l'indicateur
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);
//--- définit certaines propriétés pour créer l'indicateur
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // type de construction graphique
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // style de ligne
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // largeur de ligne
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Fonction d'itération de l'indicateur personnalisé |
//+------------------------------------------------------------------+
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[])
{
//--- dans le cas où aucune barre n'est encore calculée
if(prev_calculated==0)
{
//--- récupère l'heure d'arrivée de la barre de la plus grande période
if(!GetTimeData())
return(0);
}
//--- définit l'indexation directe
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- variable de départ pour le calcul des barres
int start=prev_calculated;
//--- si la barre est générée, recalcule la valeur de l'indicateur
if(start!=0 && start==rates_total)
start--;
//--- boucle de calcul des valeurs de l'indicateur
for(int i=start;i<rates_total;i++)
{
//--- remplit i éléments des buffers de l'indicateur avec des valeurs vides
FillIndicatorBuffers(i);
//--- effectue le calcul des barres commençant à la date InpDateStart
if(time[i]>=InpDateStart)
{
//--- définit la position à partir de laquelle les valeurs sont affichées pour la première fois
if(ExtStartFlag)
{
//--- stocke le numéro de la barre initiale
ExtStartPos=i;
//--- définit la première date de la période supérieure excédant time[i]
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- change la valeur du flag afin de ne pas exécuter ce bloc à nouveau
ExtStartFlag=false;
}
//--- vérifie s'il reste des éléments dans le tableau
if(ExtCount<ExtSize)
{
//--- attend que la valeur time actuelle atteigne celle de la période supérieure
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- dessine la partie principale de la bougie (sans remplir la zone entre les deux dernières barres)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- remplit la fin de la bougie (la zone entre les deux dernières barres)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- décale la position initiale pour dessiner la prochaine bougie
ExtStartPos=i;
//--- augmente le compteur du tableau
ExtCount++;
}
else
continue;
}
else
{
//--- réinitialise les valeurs du tableau
ResetLastError();
//--- récupère la dernière date depuis la période supérieure
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Erreur de copie des données, code = ",GetLastError());
return(0);
}
//--- si la nouvelle date est plus tard, stoppe la génération des bougies
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- efface la zone entre les deux dernières barres dans les buffers principaux de l'indicateur
ClearEndOfBodyMain(i-1);
//--- remplit la zone avec les buffers supplémentaires de l'indicateur
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- décale la position initiale pour dessiner la prochaine bougie
ExtStartPos=i;
//--- réinitialise le flag de diraction du prix
ExtDirectionFlag=0;
//--- stocke la nouvelle dernière date
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- génère la bougie
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- retourne la valeur de prev_calculated pour le prochain appel
return(rates_total);
}
//+------------------------------------------------------------------+
//| Vérifie la validité de la période spécifiée de l'indicateur |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- la période de l'indicateur ne devrait pas être supérieure à la période du graphique sur lequel il est affiché
if(current_period>=high_period)
{
Print("Erreur ! La valeur de la période de l'indicateur devrait excéder la valeur de la période actuelle !");
return(false);
}
//--- si la période de l'indicateur est une semaine ou un mois, la période est correcte
if(high_period>32768)
return(true);
//--- convertit les valeurs de la période en minutes
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- la période de l'indicateur devrait être un multiple de la période sur laquelle il est affiché
if(high_period%current_period!=0)
{
Print("Erreur ! La valeur de la période de l'indicateur devrait être un multiple de la valeur de la période actuelle !");
return(false);
}
//--- la période de l'indicateur devrait excéder la période sur laquelle il est affiché par 3 fois ou plus
if(high_period/current_period<3)
{
Print("Erreur ! La période de l'indicateur devrait excéder la période actuelle par 3 fois ou plus !");
return(false);
}
//--- la période de l'indicateur est correcte pour la période actuelle
return(true);
}
//+------------------------------------------------------------------+
//| Récupère les données time de la période supérieure |
//+------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- réinitialise la valeur d'erreur
ResetLastError();
//--- copie toutes les données pour l'heure actuelle
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- récupère le code d'erreur
int code=GetLastError();
//--- affiche le message d'erreur
PrintFormat("Erreur de copie des données ! %s",code==4401
? "L'historique est toujours en cours de chargement !"
: "Code = "+IntegerToString(code));
//--- retourne false pour effectuer une tentative répétée de téléchargement des données
return(false);
}
//--- récupère la taille du tableau
ExtSize=ArraySize(ExtTimeBuff);
//--- définit l'indice de la boucle pour le tableau à zéro
ExtCount=0;
//--- définit la position de la bougie actuelle à zéro
ExtStartPos=0;
ExtStartFlag=true;
//--- stocke la dernière valeur time de la période supérieure
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- exécution réussie
return(true);
}
//+--------------------------------------------------------------------------+
//| La fonction forme la partie principale de la bougie. Suivant la valeur |
//| du flag, la fonction définit quelles données et quels tableaux seront |
//| utilisés pour un affichage correct. |
//+--------------------------------------------------------------------------+
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)
{
//--- vérifie la valeur du flag
if(flag)
{
//--- génère le corps de la bougie
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- génère l'ombre de la bougie
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- génère le corps de la bougie
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- génère l'ombre de la bougie
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+--------------------------------------------------------------------------------+
//| La fonction forme la fin de la bougie. Suivant la valeur du flag, |
//| la fonction définit quelles données et quels tableaux seront |
//| utilisés pour un affichage correct. |
//+--------------------------------------------------------------------------------+
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)
{
//--- vérifie la valeur du flag
if(flag)
{
//--- génère la fin du corps de la bougie
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- génère la fin de l'ombre de la bougie
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- change la valeur du flag à son opposé
flag=false;
}
else
{
//--- génère la fin du corps de la bougie
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- génère la fin de l'ombre de la bougie
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- change la valeur du flag à son opposé
flag=true;
}
}
//+-------------------------------------------------------------------------------------+
//| Efface la fin de la bougie (la zone entre les deux dernières |
//| barres) |
//+-------------------------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+------------------------------------------------------------------+
//| Efface la bougie |
//+------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- vérification
if(count!=0)
{
//--- remplit les buffers de l'indicateur avec des valeurs vides
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);
}
}
//+------------------------------------------------------------------+
//| Génère la partie principale de la bougie |
//+------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- vérification
if(count!=0)
{
//--- remplit les buffers de l'indicateur avec les valeurs
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+------------------------------------------------------------------+
//| Génère la fin de la bougie |
//+------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- remplit les buffers de l'indicateur avec les valeurs
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+------------------------------------------------------------------+
//| Remplit l'élément i des buffers avec des valeurs vides |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- définit une valeur vide dans la cellule des buffers de l'indicateur
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;
}
|