//+------------------------------------------------------------------+ //| Demo_iBands.mq5 | //| Copyright 2011, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2000-2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property description "El indicador demuestra cómo hay que obtener los datos" #property description "de los búfers indicadores para el indicador técnico iBands." #property description "El símbolo y el período de tiempo en el que se calcula el indicador" #property description "se establecen mediante los parámetros symbol y period." #property description "El modo de crear el manejador (handle) se establece mediante el parámetro 'type' (tipo de función)." #property indicator_chart_window #property indicator_buffers 3 #property indicator_plots 3 //--- construcción de Upper #property indicator_label1 "Upper" #property indicator_type1 DRAW_LINE #property indicator_color1 clrMediumSeaGreen #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- construcción de Lower #property indicator_label2 "Lower" #property indicator_type2 DRAW_LINE #property indicator_color2 clrMediumSeaGreen #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- construcción de Middle #property indicator_label3 "Middle" #property indicator_type3 DRAW_LINE #property indicator_color3 clrMediumSeaGreen #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //+------------------------------------------------------------------+ //| Enumeración de modos de crear el manejador | //+------------------------------------------------------------------+ enum Creation { Call_iBands, // usar iBands Call_IndicatorCreate // usar IndicatorCreate }; //--- parámetros de entrada input Creation type=Call_iBands; // tipo de función input int bands_period=20; // período de la media móvil input int bands_shift=0; // sangría input double deviation=2.0; // número de desviaciones estándares input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; // tipo de precio input string symbol=" "; // símbolo input ENUM_TIMEFRAMES period=PERIOD_CURRENT; // período de tiempo //--- búfers indicadores double UpperBuffer[]; double LowerBuffer[]; double MiddleBuffer[]; //--- variable para guardar el manejador del indicador iBands int handle; //--- variable para guardar string name=symbol; //--- nombre del indicador en el gráfico string short_name; //--- vamos a guardar el número de los valores en el indicador Bollinger Bands int bars_calculated=0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- vinculación de los arrays a los búfers indicadores SetIndexBuffer(0,UpperBuffer,INDICATOR_DATA); SetIndexBuffer(1,LowerBuffer,INDICATOR_DATA); SetIndexBuffer(2,MiddleBuffer,INDICATOR_DATA); //--- estableceremos el desplazamiento para cada línea PlotIndexSetInteger(0,PLOT_SHIFT,bands_shift); PlotIndexSetInteger(1,PLOT_SHIFT,bands_shift); PlotIndexSetInteger(2,PLOT_SHIFT,bands_shift); //--- determinamos el símbolo para el que se construye el indicador name=symbol; //--- eliminaremos los espacios del lado izquierdo y derecho StringTrimRight(name); StringTrimLeft(name); //--- si después de eso la longitud de la cadena name obtiene el valor cero, if(StringLen(name)==0) { //--- cogeremos el símbolo del gráfico en el que está iniciado el indicador name=_Symbol; } //--- crearemos el manejador del indicador if(type==Call_iBands) handle=iBands(name,period,bands_period,bands_shift,deviation,applied_price); else { //--- llenaremos la estructura con los valores de los parámetros del indicador MqlParam pars[4]; //--- período de la media móvil pars[0].type=TYPE_INT; pars[0].integer_value=bands_period; //--- desplazamiento pars[1].type=TYPE_INT; pars[1].integer_value=bands_shift; //--- número de desviaciones estándares pars[2].type=TYPE_DOUBLE; pars[2].double_value=deviation; //--- tipo de precio pars[3].type=TYPE_INT; pars[3].integer_value=applied_price; handle=IndicatorCreate(name,period,IND_BANDS,4,pars); } //--- si no se puede crear el manejador if(handle==INVALID_HANDLE) { //--- avisaremos sobre el fallo y mostraremos el número del error PrintFormat("Fallo al crear el manejador del indicador iBands para el par %s/%s, código del error %d", name, EnumToString(period), GetLastError()); //--- el trabajo del indicador se finaliza anticipadamente return(INIT_FAILED); } //--- mostraremos para qué par símbolo/período ha sido calculado el indicador Bollinger Bands short_name=StringFormat("iBands(%s/%s, %d,%d,%G,%s)",name,EnumToString(period), bands_period,bands_shift,deviation,EnumToString(applied_price)); IndicatorSetString(INDICATOR_SHORTNAME,short_name); //--- inicialización correcta del indicador 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[]) { //--- número de valores copiados desde el indicador iBands int values_to_copy; //--- vamos a averiguar el número de valores calculados en el indicador int calculated=BarsCalculated(handle); if(calculated<=0) { PrintFormat("BarsCalculated() ha devuelto %d, el código del error %d",calculated,GetLastError()); return(0); } //--- si se trata de la primera inicialización de la calculación de nuestro indicador o se ha cambiado el número de valores en el indicador iBands //--- o si es necesario calcular el indicador para dos o más barras (entonces algo se ha cambiado en el historial) if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1) { //--- si el tamaño de los arrays indicadores supera el número de valores en el indicador iBands para el par symbol/period, entonces no copiamos todo //--- en caso contrario, copiaremos menos que el tamaño de los búfers indicadores if(calculated>rates_total) values_to_copy=rates_total; else values_to_copy=calculated; } else { //--- significa que no es la primera vez que se calcula nuestro indicador y desde el momento de la primera llamada de OnCalculate()) //--- se ha añadido no más de una barra para la calculación values_to_copy=(rates_total-prev_calculated)+1; } //--- llenamos el array con los valores desde el indicador Bollinger Bands //--- si FillArraysFromBuffer ha devuelto false, significa que los datos aún no están listos - entonces finalizamos el proceso if(!FillArraysFromBuffers(MiddleBuffer,UpperBuffer,LowerBuffer,bands_shift,handle,values_to_copy)) return(0); //--- creamos el mensaje string comm=StringFormat("%s ==> Actualizados los valores en el indicador %s: %d", TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS), short_name, values_to_copy); //--- mostraremos en el gráfico un mensaje de servicio Comment(comm); //--- recordaremos el número de valores en el indicador Bollinger Bands bars_calculated=calculated; //--- devolveremos el valor prev_calculated para la siguiente llamada return(rates_total); } //+------------------------------------------------------------------+ //| Llenamos los búfers indicadores desde el indicador iBands | //+------------------------------------------------------------------+ bool FillArraysFromBuffers(double &base_values[], // búfer indicador de la línea media de Bollinger Bands double &upper_values[], // búfer indicador del borde superior double &lower_values[], // búfer indicador del borde inferior int shift, // desplazamiento int ind_handle, // manejador del indicador iBands int amount // número de valores a copiar ) { //--- actualizaremos el código del error ResetLastError(); //--- llenamos una parte del array MiddleBuffer con los valores desde el búfer indicador con el índice 0 if(CopyBuffer(ind_handle,0,-shift,amount,base_values)<0) { //--- si el proceso de copiado ha fallado, comunicaremos el código del error PrintFormat("Fallo al copiar los datos desde el indicador iBands, código del error %d",GetLastError()); //--- finalizaremos con el resultado nulo - eso quiere decir que el indicador será considerado como no calculado return(false); } //--- llenamos una parte del array UpperBuffer con los valores desde el búfer indicador con el índice 1 if(CopyBuffer(ind_handle,1,-shift,amount,upper_values)<0) { //--- si el proceso de copiado ha fallado, comunicaremos el código del error PrintFormat("Fallo al copiar los datos desde el indicador iBands, código del error %d",GetLastError()); //--- finalizaremos con el resultado nulo - eso quiere decir que el indicador será considerado como no calculado return(false); } //--- llenamos una parte del array LowerBuffer con los valores desde el búfer indicador con el índice 2 if(CopyBuffer(ind_handle,2,-shift,amount,lower_values)<0) { //--- si el proceso de copiado ha fallado, comunicaremos el código del error PrintFormat("Fallo al copiar los datos desde el indicador iBands, código del error %d",GetLastError()); //--- finalizaremos con el resultado nulo - eso quiere decir que el indicador será considerado como no calculado return(false); } //--- todo ha salido bien return(true); } //+------------------------------------------------------------------+ //| Indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(handle!=INVALID_HANDLE) IndicatorRelease(handle); //--- limpiaremos el gráfico tras eliminar el indicador Comment(""); } |