Indicadores: Bollinger Squeeze Basic MT5

 

Bollinger Squeeze Basic MT5:

Bollinger Squeeze Basic MetaTrader indicador - es un indicador complejo basado en Momentum, las bandas de Bollinger, y el canal de Keltner. El indicador se dibuja en la ventana separada del gráfico como un histograma de Momentum y un rango de puntos al mostrar la relación entre los valores actuales de las bandas de Bollinger y el canal de Keltner. Este indicador está disponible para las versiones MT4 y MT5 de la plataforma de negociación.

Bollinger Squeeze Basic MT5

Author: Tuan Nguyen Van

 
Suena a tendencia y confirmación en el mismo indicador. ¡Interesante!
 

Hola Gracias por compartir su código Indicador, Traté de convertir el Sqeeze Momentum Indicador de Trading View, aquí está el código que tengo.. es un poco diferente.. ¡Me gustaría saber de usted en esto! Gracias.


//+------------------------------------------------------------------------+
//|SqueezeMomentumIndicator.mq5
//|Convertido de Pine Script por LazyBear |
//||
//+------------------------------------------------------------------------+
#property copyright "Converted from Pine Script by LazyBear"
#property link      ""
#property version   "1.02"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  clrLime, clrGreen, clrRed, clrMaroon
#property indicator_style1  STYLE_SOLID
#property indicator_width1  4
#property indicator_label1  "Squeeze Momentum"
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  clrBlue, clrBlack, clrGray
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2
#property indicator_label2  "Squeeze"

//--- parámetros de entrada
input int    LengthBB = 20;         // Longitud BB
input double MultBB = 2.0;          // BB MultFactor
input int    LengthKC = 20;         // Longitud KC
input double MultKC = 1.5;          // KC MultFactor
input bool   UseTrueRange = true;   // Usar TrueRange (KC)

//--- tampones indicadores
double MomentumBuffer[];       // Valores de impulso
double MomentumColorBuffer[];  // Colores de impulso
double SqueezeBuffer[];        // Valores de compresión
double SqueezeColorBuffer[];   // Colores exprimidos

//+------------------------------------------------------------------+
//| Función personalizada de inicialización del indicador|
//+------------------------------------------------------------------+
int OnInit()
{
   //--- asignación de búferes indicadores
   SetIndexBuffer(0, MomentumBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, MomentumColorBuffer, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, SqueezeBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, SqueezeColorBuffer, INDICATOR_COLOR_INDEX);
   
   //--- establecer índices de color
   PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 4); // 4 colores para el histograma
   PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, 3); // 3 colores para la línea
   
   //--- fijar el nombre del indicador
   IndicatorSetString(INDICATOR_SHORTNAME, "SQZMOM_LB [LazyBear]");
   
   //--- fijar precisión
   IndicatorSetInteger(INDICATOR_DIGITS, 5);
   
   //--- establecer arrays como series
   ArraySetAsSeries(MomentumBuffer, true);
   ArraySetAsSeries(MomentumColorBuffer, true);
   ArraySetAsSeries(SqueezeBuffer, true);
   ArraySetAsSeries(SqueezeColorBuffer, true);
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Media móvil simple|
//+------------------------------------------------------------------+
double SimpleMA(const double &price[], int period, int shift)
{
   double sum = 0.0;
   for(int i = 0; i < period; i++)
   {
      sum += price[shift + i];
   }
   return sum / period;
}

//+------------------------------------------------------------------+
//| Desviación estándar|
//+------------------------------------------------------------------+
double StdDev(const double &price[], int period, int shift)
{
   double avg = SimpleMA(price, period, shift);
   double sum = 0.0;
   
   for(int i = 0; i < period; i++)
   {
      sum += MathPow(price[shift + i] - avg, 2);
   }
   
   return MathSqrt(sum / period);
}

//+------------------------------------------------------------------+
//| Regresión lineal|
//+------------------------------------------------------------------+
double LinReg(const double &price[], int period, int shift)
{
   double sum_x = 0.0;
   double sum_y = 0.0;
   double sum_xy = 0.0;
   double sum_x2 = 0.0;
   
   for(int i = 0; i < period; i++)
   {
      sum_x += i;
      sum_y += price[shift + i];
      sum_xy += i * price[shift + i];
      sum_x2 += i * i;
   }
   
   double m = period;
   double slope = (m * sum_xy - sum_x * sum_y) / (m * sum_x2 - sum_x * sum_x);
   double intercept = (sum_y - slope * sum_x) / m;
   
   return intercept;
}

//+------------------------------------------------------------------+
//| Función de iteración del indicador personalizada|
//+------------------------------------------------------------------+
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[])
{
   // Comprobar datos mínimos
   int min_bars = MathMax(LengthBB, LengthKC) + 1;
   if(rates_total < min_bars) return(0);
   
   // Establecer matrices como series para una correcta indexación
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   
   // Calcular el punto de partida
   int limit;
   if(prev_calculated == 0)
      limit = rates_total - min_bars;
   else
      limit = rates_total - prev_calculated;
   
   limit = MathMin(limit, rates_total - min_bars);
   
   // Preparar matrices para el cálculo de la fuente
   double source[];
   ArrayResize(source, rates_total);
   ArraySetAsSeries(source, true);
   
   // Bucle de cálculo principal
   for(int i = limit; i >= 0; i--)
   {
      // Calcular las Bandas de Bollinger
      double basis = 0.0;
      for(int j = 0; j < LengthBB; j++)
         basis += close[i+j];
      basis /= LengthBB;
      
      double dev = 0.0;
      for(int j = 0; j < LengthBB; j++)
         dev += MathPow(close[i+j] - basis, 2);
      dev = MultBB * MathSqrt(dev / LengthBB);
      
      double upperBB = basis + dev;
      double lowerBB = basis - dev;
      
      // Calcular los canales de Keltner
      double ma = 0.0;
      for(int j = 0; j < LengthKC; j++)
         ma += close[i+j];
      ma /= LengthKC;
      
      double range_sum = 0.0;
      for(int j = 0; j < LengthKC; j++)
      {
         double tr;
         if(UseTrueRange && i+j+1 < rates_total)
            tr = MathMax(high[i+j] - low[i+j], 
                 MathMax(MathAbs(high[i+j] - close[i+j+1]), 
                         MathAbs(low[i+j] - close[i+j+1])));
         else
            tr = high[i+j] - low[i+j];
         
         range_sum += tr;
      }
      double range_ma = range_sum / LengthKC;
      
      double upperKC = ma + MultKC * range_ma;
      double lowerKC = ma - MultKC * range_ma;
      
      // Calcular las condiciones de compresión
      bool sqzOn = (lowerBB > lowerKC) && (upperBB < upperKC);
      bool sqzOff = (lowerBB < lowerKC) && (upperBB > upperKC);
      bool noSqz = !sqzOn && !sqzOff;
      
      // Buscar el máximo más alto y el mínimo más bajo para el periodo KC
      double highest = high[i];
      double lowest = low[i];
      
      for(int j = 1; j < LengthKC; j++)
      {
         if(i+j >= rates_total) break;
         if(high[i+j] > highest) highest = high[i+j];
         if(low[i+j] < lowest) lowest = low[i+j];
      }
      
      // Calcular fuente para linreg
      double avg_hl = (highest + lowest) / 2;
      double avg_val = (avg_hl + ma) / 2;
      
      for(int j = 0; j < LengthKC; j++)
      {
         if(i+j >= rates_total) break;
         source[i+j] = close[i+j] - avg_val;
      }
      
      // Calcular el impulso con regresión lineal
      MomentumBuffer[i] = LinReg(source, LengthKC, i);
      
      // Establecer el valor de la línea de compresión (siempre 0)
      SqueezeBuffer[i] = 0;
      
      // Establecer colores basados en condiciones exactamente como en Pine Script
      // bcolor = iff(val > 0, iff(val > nz(val[1]), lima, verde), iff(val < nz(val[1]), rojo, granate))
      if(i < rates_total - 1)
      {
         if(MomentumBuffer[i] > 0)
         {
            if(MomentumBuffer[i] > MomentumBuffer[i+1])
               MomentumColorBuffer[i] = 0; // lima
            else
               MomentumColorBuffer[i] = 1; // verde
         }
         else
         {
            if(MomentumBuffer[i] < MomentumBuffer[i+1])
               MomentumColorBuffer[i] = 2; // rojo
            else
               MomentumColorBuffer[i] = 3; // granate
         }
      }
      else
      {
         // Para el primer compás
         MomentumColorBuffer[i] = (MomentumBuffer[i] > 0) ? 0 : 2; // lima o rojo
      }
      
      // scolor = noSqz ? azul : sqzOn ? negro : gris
      if(noSqz)
         SqueezeColorBuffer[i] = 0; // azul
      else if(sqzOn)
         SqueezeColorBuffer[i] = 1; // negro
      else
         SqueezeColorBuffer[i] = 2; // gris
   }
   
   return(rates_total);
}
//+------------------------------------------------------------------+



Archivos adjuntos: