#property description "El indicador muestra las velas del mayor período en el período actual."
//--- ajustes del indicador
#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
//--- constante predefinida
#define INDICATOR_EMPTY_VALUE 0.0
//--- parámetros de entrada
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // Período para el cálculo del indicador
input datetime InpDateStart=D'2013.01.01 00:00'; // Fecha de inicio del análisis
//--- búferes de indicadores para las velas bajistas
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- búferes de indicadores para las velas alcistas
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- variables globales
datetime ExtTimeBuff[]; // búfer de tiempo del período mayor
int ExtSize=0; // tamaño del búfer de tiempo
int ExtCount=0; // índice dentro del búfer de tiempo
int ExtStartPos=0; // posición inicial para el cálculo del indicador
bool ExtStartFlag=true; // bandera auxiliar para recibir la posición inicial
datetime ExtCurrentTime[1]; // última hora de formación de la barra desde el período mayor
datetime ExtLastTime; // última hora desde el período mayor para el que se ha hecho el cálculo
bool ExtBearFlag=true; // bandera para determinar el orden de escritura de datos en los búferes de indicadores bajistas
bool ExtBullFlag=true; // bandera para determinar el orden de escritura de datos en los búferes de indicadores alcistas
int ExtIndexMax=0; // índice del elemento máximo del array
int ExtIndexMin=0; // índice del elemento mínimo del array
int ExtDirectionFlag=0; // dirección de movimiento del precio para la vela actual
//--- espacio entre el precio de apertura y cierre de la vela para una correcta representación gráfica
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| Coloreado de la parte básica de la vela |
//+------------------------------------------------------------------+
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)
{
//--- buscamos los índices del elemento máximo y del mínimo en los arrays
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // el máximo en High
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // el mínimo en Low
//--- determinamos el número de barras desde el período actual que vamos a colear
int count=fill_index-start+1;
//--- si el precio de cierre de la primera barra supera el precio de cierre de la última - vela bajista
if(open[start]>close[last])
{
//--- si hasta este momento la vela era bajista, entonces limpiamos los valores de los búferes de indicadores bajistas
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- vela bajista
ExtDirectionFlag=-1;
//--- formamos la vela
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- salida de la función
return;
}
//--- si el precio de cierre de la primera barra es inferior al precio de cierre de la última - vela alcista
if(open[start]<close[last])
{
//--- si hasta este momento la vela era alcistas, entonces limpiamos los valores de los búferes de indicadores alcistas
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- vela alcista
ExtDirectionFlag=1;
//--- formamos la vela
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- salida de la función
return;
}
//--- si se encuentra en esta parte de la función, el precio de apertura de la primera barra es igual al
//--- precio de cierre de la última barra; vamos a considerar esta vela bajista
//--- si hasta este momento la vela era bajista, entonces limpiamos los valores de los búferes de indicadores bajistas
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- vela bajista
ExtDirectionFlag=-1;
//--- si los precios de cierre y de apertura son iguales, utilizamos el desplazamiento (shift) para una correcta visualización
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);
}
//+------------------------------------------------------------------+
//| Coloreado de la punta de la vela |
//+------------------------------------------------------------------+
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)
{
//--- no dibujamos en caso de sólo una barra
if(last-start==0)
return;
//--- si el precio de cierre de la primera barra supera el precio de cierre de la última - vela bajista
if(open[start]>close[last])
{
//--- formamos la punta de la vela
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- salida de la función
return;
}
//--- si el precio de cierre de la primera barra es inferior al precio de cierre de la última - vela alcista
if(open[start]<close[last])
{
//--- formamos la punta de la vela
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- salida de la función
return;
}
//--- si se encuentra en esta parte de la función, el precio de apertura de la primera barra es igual al
//--- precio de cierre de la última barra; vamos a considerar esta vela bajista
//--- formamos la punta de la vela
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);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- chequeo del período de tiempo del indicador
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- visualización de los precios en el primer plano
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- enlace de los búferes de indicadores
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);
//--- fijamos algunos valores de propiedades para construir el indicador
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // tipo de construcción gráfica
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // estilo de la línea
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // grosor de la línea
}
//---
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[])
{
//--- si todavía no hay barras calculadas,
if(prev_calculated==0)
{
//--- obtenemos la hora de aparición de las barras desde el período mayor
if(!GetTimeData())
return(0);
}
//--- establecemos la dirección directa para la indexación
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- variable de inicio para el cálculo de las barras
int start=prev_calculated;
//--- si la barra se está formando, volvemos a calcular el valor del indicador sobre esta barra
if(start!=0 && start==rates_total)
start--;
//--- ciclo de cálculo de los valores del indicador
for(int i=start;i<rates_total;i++)
{
//--- llenamos los elementos "i" de los búferes de indicadores con valores vacíos
FillIndicatorBuffers(i);
//--- hacemos el cálculo para las barras a partir de la fecha InpDateStart
if(time[i]>=InpDateStart)
{
//--- definimos por primera vez la posición a partir de la cual empezamos a mostrar valores
if(ExtStartFlag)
{
//--- recordamos el número de la barra inicial
ExtStartPos=i;
//--- determinamos la primera fecha desde el período mayor que supera time[i]
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- cambiamos el valor de la bandera para no volver a entrar en este bloque
ExtStartFlag=false;
}
//--- comprobamos si hay más elementos en el array
if(ExtCount<ExtSize)
{
//--- esperamos hasta que el valor de tiempo del período actual alcance el valor del período mayor
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- dibujamos la parte básica de la vela (sin colorear entre la última barra y la penúltima)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- coloreamos la punta de la vela (área entre la última barra y la penúltima)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- movemos la posición inicial para dibujar la siguiente barra
ExtStartPos=i;
//--- aumentamos el contador del array
ExtCount++;
}
else
continue;
}
else
{
//--- anulamos los valores del error
ResetLastError();
//--- obtenemos la última fecha del período mayor
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Error del copiado de datos, código = ",GetLastError());
return(0);
}
//--- si nueva fecha es mayor, terminamos la formación de la vela
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- limpiamos el área entre la última barra y la penúltima en los búferes de indicadores principales
ClearEndOfBodyMain(i-1);
//--- coloreamos esta área utilizando los búferes de indicadores auxiliares
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- movemos la posición inicial para dibujar la siguiente barra
ExtStartPos=i;
//--- reseteamos la bandera de dirección del precio
ExtDirectionFlag=0;
//--- recordamos la última fecha nueva
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- formamos la vela
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Prueba de la corrección del período del indicador introducido |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- el período del indicador tiene que ser más grande que el período de tiempo (time frame) en el que se visualiza
if(current_period>=high_period)
{
Print("¡Error! ¡El valor del período del indicador tiene que superar al valor del período de tiempo actual!");
return(false);
}
//--- si el período del indicador es una semana o un mes, entonces el período es correcto
if(high_period>32768)
return(true);
//--- convertimos los valores de los períodos a los minutos
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- el período del indicador debe de ser múltiple del período de tiempo en el que se visualiza
if(high_period%current_period!=0)
{
Print("¡Error! ¡El valor del período del indicador tiene que múltiple del valor del período de tiempo actual!");
return(false);
}
//--- el período del indicador tiene que superar al período de tiempo (time frame) en el que se visualiza 3 o más veces
if(high_period/current_period<3)
{
Print("¡Error! ¡El valor del período del indicador tiene que superar al valor del período de tiempo actual 3 o más veces!");
return(false);
}
período del indicador es correcto para el período de tiempo actual
return(true);
}
//+------------------------------------------------------------------+
//| Recepción de datos de tiempo desde el período de tiempo mayor |
//+------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- resetear el valor del error
ResetLastError();
//--- copiamos todos los datos para la hora actual
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- obtenemos el código del error
int code=GetLastError();
//--- imprimimos el texto del error
PrintFormat("¡Error al copiar datos! %s",code==4401
? "¡El historial se sigue cargando!"
: "Código = "+IntegerToString(code));
//--- devolvemos false para volver a intentar cargar datos
return(false);
}
//--- obtenemos el tamaño del array
ExtSize=ArraySize(ExtTimeBuff);
//--- ponemos el índice del ciclo para el array igual a cero
ExtCount=0;
//--- ponemos la posición de la vela actual en este período de tiempo igual a cero
ExtStartPos=0;
ExtStartFlag=true;
//--- recordamos el último valor de tiempo desde el período de tiempo mayor
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- ejecución con éxito
return(true);
}
//+------------------------------------------------------------------+
//| La función forma la parte básica de la vela. Dependiendo del valor de|
//| la bandera, la función determina qué datos y en qué arrays deben |
//| escribirse para una visualización correcta. |
//+------------------------------------------------------------------+
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)
{
//--- comprobamos el valor de la bandera
if(flag)
{
//--- formamos el cuerpo de la vela
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- formamos la sombra de la vela
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- formamos el cuerpo de la vela
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- formamos la sombra de la vela
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+------------------------------------------------------------------+
//| La función forma la punta de la vela. Dependiendo del valor de la bandera, |
//| la función determina qué datos y en qué arrays deben |
//| escribirse para una visualización correcta. |
//+------------------------------------------------------------------+
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)
{
//--- comprobamos el valor de la bandera
if(flag)
{
//--- formamos el fin del cuerpo de la vela
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- formamos el fin de la sombra de la vela
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- cambiamos el valor de la bandera al opuesto
flag=false;
}
else
{
//--- formamos el fin del cuerpo de la vela
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- formamos el fin de la sombra de la vela
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- cambiamos el valor de la bandera al opuesto
flag=true;
}
}
//+------------------------------------------------------------------+
//| Limpiamos la punta de la vela (área entre la última barra y la penúltima |
//| barra) |
//+------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+------------------------------------------------------------------+
//| Limpieza de la vela |
//+------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- prueba
if(count!=0)
{
//--- llenamos los búferes indicadores con valores vacíos
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);
}
}
//+------------------------------------------------------------------+
//| Formación de la parte básica de la vela |
//+------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- prueba
if(count!=0)
{
//--- llenamos los búferes indicadores con valores
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+------------------------------------------------------------------+
//| Formación de la punta de la vela |
//+------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- llenamos los búferes indicadores con valores
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+------------------------------------------------------------------+
//| Llenar los elementos "i" de los búferes de indicadores con valores vacíos|
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- establecemos un valor vacío en la cédula de búferes de indicadores
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;
}
|