Descargar MetaTrader 5

Líneas de tendencia basadas en los fractales usando MQL4 y MQL5

6 agosto 2015, 12:19
Almat Kaldybay
0
1 263

Índice


Introducción

Hace poco me he puesto a pensar en la aplicación de las líneas de tendencia. Me he preguntado sobre el método para determinar los puntos a través de los cuales van a pasar las líneas, así como sobre la precisión del trazado de estas líneas. He decidido tomar los fractales como la base.

Suelo hacer el análisis de los mercados en mi trabajo principal donde puede dedicar al trading un poco de tiempo. Además, no es suficiente simplemente trazar las líneas en un período de tiempo mayor; la línea tiene que trazarse por los extremos con la precisión de hasta 15 minutos. Esta necesidad se debe a que el tiempo del fractal en un período de tiempo mayor no siempre coincide con el tiempo del mismo extremo en M15. En total, la automatización viene a ayudarnos. Resultó que había empezado a escribir el código en MQL5, luego pasé a MQL4 porque necesitaba el mismo programa para MetaTrader 4.

En este artículo quiero presentar mi solución del problema planteado usando MQL4 y MQL5. El artículo ofrece la vista comparativa, pero sería incorrecto comparar la eficacia de MQL4 y MQL5 en este artículo. Tampoco descarto que existen las soluciones más eficientes que figuran aquí. Este artículo puede ser útil para los principiantes que escriben los scripts tanto en MQL4 como en MQL5, sobre todo para los que van a usar en su trabajo los fractales y las líneas de tendencia.


1. Parámetros de entrada, función DeInit() y declaración inicial de variables

He utilizado las siguientes variables como los parámetros de entrada:

input color Resistance_Color=Red;       // establecemos el color de la línea de resistencia
input ENUM_LINE_STYLE Resistance_Style; // establecemos el estilo de la línea de resistencia
input int Resistance_Width=1;           // establecemos el ancho de la línea de resistencia
input color Support_Color=Red;          // establecemos el color de la línea de soporte
input ENUM_LINE_STYLE Support_Style;    // establecemos el estilo de la línea de soporte
input int Support_Width=1;              // establecemos el ancho de la línea de soporte

En MQL4 y MQL5 estos parámetros son iguales.

En el lenguaje MQL5 es necesario crear previamente el indicador:

//--- manejador del indicador iFractals 
int Fractal;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- obtenemos el manejador del indicador iFractals 
   Fractal=iFractals(Symbol(),PERIOD_D1);
//---
   return(INIT_SUCCEEDED);
  }

Puesto que el programa tiene que construir los objetos gráficos, sería lógico prever su eliminación al eliminar el Asesor Experto del gráfico:

void OnDeinit(const int reason)
  {
   ObjectDelete(0,"TL_Resistance");
   ObjectDelete(0,"TL_Support");
  }

Para construir dos líneas (soporte y resistencia), necesitamos cuatro puntos. Para determinar el punto del paso de la línea, hay que saber el tiempo y el precio.

Las coordenadas de la línea se determinan en el siguiente orden: primero, se determina la barra extrema; sabiendo la barra extrema, se puede determinar el precio y el tiempo del extremo.

En la función OnTick() declaramos las variables:

MQL4
//--- declaración de las variables
int n,UpperFractal_1,UpperFractal_2,LowerFractal_1,LowerFractal_2;
MQL5
//--- declaración de las variables
int n,UpperFractal_1,UpperFractal_2,LowerFractal_1,LowerFractal_2;
//--- declaración de los arrays para escribir los valores de los búfers del indicador iFractal
double FractalDown[],FractalUp[];
double UpFractal_1,UpFractal_2,LowFractal_1,LowFractal_2;

Primeramente, he declarado sólo las variables para almacenar los índices de las barras con los fractales formados.

En MQL4:

  1. n - la variable que es necesaria para buscar el fractal más cercano conocido usando el operador del ciclo for;
  2. UpperFractal_1, UpperFractal_2,  LowerFractal_1, LowerFractal_2 - estas variables van a almacenar el índice de la barra del primer y el segundo extremo más cercano con el precio máximo/mínimo (en términos de determinación de fractales);

En MQL5 aparecen las variables adicionales:

  1. FractalDown[],FractalUp[]; - declaración de los arrays con el tipo de datos double en los que van a escribirse los valores del búfer del indicador iFractals;
  2. A continuación, los variables con el tipo double: UpFractal_1,UpFractal_2,LowFractal_1,LowFractal_2. Van a almacenar los valores de precio de los extremos.

2. Búsqueda de los fractales más cercanos

Para encontrar el índice de la barra en la que se ha formado el fractal, usamos el operador del ciclo for.

Vamos a determinar dos primeros índices de la barra que corresponden al primer y al segundo fractal superior:

MQL4
//--- encontramos el índice de la barra del primer fractal superior más cercano
   for(n=0; n<(Bars-1);n++)
     {
      if(iFractals(NULL,1440,MODE_UPPER,n)!=NULL)
         break;
      UpperFractal_1=n+1;
     }
//--- encontramos el índice de la barra del segundo fractal superior más cercano
   for(n=UpperFractal_1+1; n<(Bars-1);n++)
     {
      if(iFractals(NULL,1440,MODE_UPPER,n)!=NULL)
         break;
      UpperFractal_2=n+1;
     }
 MQL5
//--- primero, en los arrays hay que escribir los valores de los búferes del indicador Fractal
//--- llenando los arrays con los datos del búfer
   CopyBuffer(Fractal,0,TimeCurrent(),Bars(Symbol(),PERIOD_D1),FractalUp);
   CopyBuffer(Fractal,1,TimeCurrent(),Bars(Symbol(),PERIOD_D1),FractalDown);
//--- indexación como en las series temporales
   ArraySetAsSeries(FractalUp,true);
   ArraySetAsSeries(FractalDown,true);
//--- luego utilizamos el operador del ciclo for para buscar el primer fractal superior
   for(n=0; n<Bars(Symbol(),PERIOD_D1); n++)
     {
      //--- si el valor no es vacío, interrumpimos el ciclo
      if(FractalUp[n]!=EMPTY_VALUE)
         break;
     }
//--- escribimos el valor de precio del primer fractal en una variable
   UpFractal_1=FractalUp[n];
//--- escribimos el índice del primer fractal en una variable
   UpperFractal_1=n;
//--- buscando el segundo fractal superior
   for(n=UpperFractal_1+1; n<Bars(Symbol(),PERIOD_D1); n++)
     {
      if(FractalUp[n]!=EMPTY_VALUE) //si el valor no es vacío, interrumpimos el ciclo
         break;
     }
//--- escribimos el valor de precio del segundo fractal en una variable
   UpFractal_2=FractalUp[n];
//--- escribimos el índice del segundo fractal en una variable
   UpperFractal_2=n;

Aquí se ilustra claramente una de las principales diferencias entre MQL5 y MQL4: el uso de la función para acceder a las series temporales.

Si en MQL4 he pasado directamente a la búsqueda del índice de la barra en la que se ha formado el fractal, en MQL5 primero he accedido al indicador iFractals mediante la función CopyBuffer() para indicar al programa que los arrays FractalUp[] y FractalDown[] van a almacenar los valores de precio de los fractales superiores e inferiores. Luego, he definido la indexación de estos arrays como en las series temporales usando la función ArraySetAsSeries().

Ahora, si en MQL4 he encontrado sólo los índices de las barras con los fractales conocidos, en MQL5 he usado la función CopyBuffer() para conocer los índices de las barras y los valores de precio de los fractales.

De la misma manera se buscan dos fractales inferiores:

MQL4
//--- encontramos el índice de la barra del primer fractal inferior más cercano
   for(n=0; n<(Bars-1);n++)
     {
      if(iFractals(NULL,1440,MODE_LOWER,n)!=NULL)
         break;
      LowerFractal_1=n+1;
     }
//--- encontramos el índice de la barra del segundo fractal inferior más cercano
   for(n=LowerFractal_1+1; n<(Bars-1);n++)
     {
      if(iFractals(NULL,1440,MODE_LOWER,n)!=NULL)
         break;
      LowerFractal_2=n+1;
     }
 MQL5
//--- búsqueda de los valores de fractales inferiores
//--- búsqueda del primer fractal inferior
   for(n=0; n<Bars(Symbol(),PERIOD_D1); n++)
     {
      //--- si el valor no es vacío, interrumpimos el ciclo
      if(FractalDown[n]!=EMPTY_VALUE)
         break;
     }
//--- escribimos el valor de precio del primer fractal en una variable
   LowFractal_1=FractalDown[n];
//--- escribimos el índice del primer fractal en una variable
   LowerFractal_1=n;
//--- búsqueda del segundo fractal inferior
   for(n=LowerFractal_1+1; n<Bars(Symbol(),PERIOD_D1); n++)
     {
      if(FractalDown[n]!=EMPTY_VALUE)
         break;
     }
//--- escribimos el valor de precio del segundo fractal en una variable
   LowFractal_2=FractalDown[n];
//--- escribimos el índice del segundo fractal en una variable
   LowerFractal_2=n;

Como podemos ver en la tabla, el código en MQL4 y MQL5 es muy parecido. Hay un aligera diferencia en la sintaxis.


3. Búsqueda de los valores de precio y de tiempo de los fractales

Para trazar una línea, necesitamos encontrar el tiempo y el precio del fractal. Claro que en MQL4 podríamos usar las series temporales predefinidas High[] y Low[], la función iTime(), pero también necesitamos precisar adicionalmente las coordenadas temporales de la línea, es que de eso va a depender la corrección del trazado de la línea de tendencia.

En la fig. 1-2 se muestra la diferencia entre los valores temporales de los extremos para los períodos H4 y M15.

Fig. 1. Tiempo del extremo con la posición del período H4

Fig. 1. Tiempo del extremo con la posición del período H4

Fig. 2. Tiempo del extremo con la posición del período M15

Fig. 2. Tiempo del extremo con la posición del período M15

He llegado a la conclusión que la precisión del valor temporal del extremo hasta 15 minutos es absolutamente suficiente para mis propósitos.

En general, el principio de la precisión del extremos es el mismo tanto para MQL4, como para MQL5, pero hay unas pequeñas diferencias en los detalles:

MQL4MQL5
  1. Se determina el valor temporal del extremo en el período de tiempo mayor;
  2. A base del valor temporal encontrado,  se busca el índice de la barra extrema sobre el período de tiempo menor usando la función iBarShift()
  3. Puesto que se 24 horas representan un array de 96 barras de 15 minutos, buscamos el extremo (el valor máximo o el mínimo en el erray de 96 elementos) entre estos 96 elementos a través de las funciones iHigh()iLow() y iTime(), así como ArrayMaximum() y ArrayMinimum().
  1. Se determina el valor temporal del extremo en el período de tiempo mayor;
  2. A base del valor temporal encontrado, se determina el tiempo de formación de la siguiente barra del día. Es necesario para el uso posterior de las funciones CopyHigh(), CopyLow() y CopyTime();
  3. Declaramos y llenamos los arrays para almacenar los datos de precio y de tiempo para el período de 15 minutos;
  4. Usando las funciones ArrayMaximum() y ArrayMinimum(), buscamos los valores máximos y mínimos de precio; así como los valores temporales de los extremos concretados. 

A continuación, viene el código para cada uno de estos pasos:

 MQL4
// Paso 1. Se determina el valor temporal del extremo en el período de tiempo mayor:
//--- determinación del tiempo de los fractales
   datetime UpFractalTime_1=iTime(NULL, 1440,UpperFractal_1);
   datetime UpFractalTime_2=iTime(NULL, 1440,UpperFractal_2);
   datetime LowFractalTime_1=iTime(NULL, 1440,LowerFractal_1);
   datetime LowFractalTime_2=iTime(NULL, 1440,LowerFractal_2);
// Paso 2.  Se busca el índice de la barra extrema en el extremo menor:   
//--- buscamos el índice del fractal en M15
   int UpperFractal_1_m15=iBarShift(NULL, 15, UpFractalTime_1,true);
   int UpperFractal_2_m15=iBarShift(NULL, 15, UpFractalTime_2,true);
   int LowerFractal_1_m15=iBarShift(NULL, 15, LowFractalTime_1,true);
   int LowerFractal_2_m15=iBarShift(NULL, 15, LowFractalTime_2,true);
// Paso 3. El uso de los arrays para buscar los extremos precisos en el período M15:
//--- uso de los arrays para buscar los extremos precisos
//--- introducimos la variable i para usarla en el operador del ciclo for
   int i;
//--- 1. En primer lugar, vamos a encontrar los extremos inferiores
//--- 3.1 Búsqueda del primer extremo inferior
//--- declaración del array para almacenar los valores de los índices de las barras
   int Lower_1_m15[96];
//--- declaración del array para almacenar los valores de precios
   double LowerPrice_1_m15[96];
//--- iniciamos el ciclo for:
   for(i=0;i<=95;i++)
     {
      //--- llenamos el array con los datos de los índices de las barras
      Lower_1_m15[i]=LowerFractal_1_m15-i;
      //--- llenamos el array con los datos de precio
      LowerPrice_1_m15[i]=iLow(NULL,15,LowerFractal_1_m15-i);
     }
//--- determinar el valor de precio mínimo en el array
   int LowestPrice_1_m15=ArrayMinimum(LowerPrice_1_m15,WHOLE_ARRAY,0);
//--- determinar la barra con el precio mínimo en el array
   int LowestBar_1_m15=Lower_1_m15[LowestPrice_1_m15];
//--- determinar el tiempo de la barra con el precio mínimo en el array
   datetime LowestBarTime_1_m15=iTime(NULL,15,Lower_1_m15[LowestPrice_1_m15]);

//--- 3.2 Búsqueda del segundo extremo inferior
   int Lower_2_m15[96];
   double LowerPrice_2_m15[96];
   for(i=0;i<=95;i++)
     {
      //--- llenamos el array con los datos de los índices de las barras
      Lower_2_m15[i]=LowerFractal_2_m15-i;
      //--- llenamos el array con los datos de precio
      LowerPrice_2_m15[i]=iLow(NULL,15,LowerFractal_2_m15-i);
     }
//--- determinar el valor de precio mínimo en el array
   int LowestPrice_2_m15=ArrayMinimum(LowerPrice_2_m15,WHOLE_ARRAY,0);
//--- determinar la barra con el precio mínimo en el array
   int LowestBar_2_m15=Lower_2_m15[LowestPrice_2_m15];
//--- determinar el tiempo de la barra con el precio mínimo en el array
   datetime LowestBarTime_2_m15=iTime(NULL,15,Lower_2_m15[LowestPrice_2_m15]);

//--- 3.3 Búsqueda del primer extremo superior
   int Upper_1_m15[96];
   double UpperPrice_1_m15[96];
   for(i=0;i<=95;i++)
     {
      //--- llenamos el array con los datos de los índices de las barras
      Upper_1_m15[i]=UpperFractal_1_m15-i;
      //--- llenamos el array con los datos de precio
      UpperPrice_1_m15[i]=iHigh(NULL,15,UpperFractal_1_m15-i);
     }
//--- determinar el valor de precio máximo en el array
   int HighestPrice_1_m15=ArrayMaximum(UpperPrice_1_m15,WHOLE_ARRAY,0);
//--- determinar la barra con el precio máximo en el array
   int HighestBar_1_m15=Upper_1_m15[HighestPrice_1_m15];
//--- determinar el tiempo de la barra con el precio máximo en el array
   datetime HighestBarTime_1_m15=iTime(NULL,15,Upper_1_m15[HighestPrice_1_m15]);

//--- 3.4 Búsqueda del segundo extremo superior
   int Upper_2_m15[96];
   double UpperPrice_2_m15[96];
   for(i=0;i<=95;i++)
     {
      //--- llenamos el array con los datos de los índices de las barras
      Upper_2_m15[i]=UpperFractal_2_m15-i;
      //--- llenamos el array con los datos de precio
      UpperPrice_2_m15[i]=iHigh(NULL,15,UpperFractal_2_m15-i);
     }
 MQL5
// Paso 1. Se determina el valor temporal del extremo en el período de tiempo mayor:
//--- declaración del array para almacenar el tiempo del índice correspondiente de la barra en el período de tiempo mayor
   datetime UpFractalTime_1[],LowFractalTime_1[],UpFractalTime_2[],LowFractalTime_2[];
//--- determinación del tiempo de los fractales en el período de tiempo mayor
   CopyTime(Symbol(),PERIOD_D1,UpperFractal_1,1,UpFractalTime_1);
   CopyTime(Symbol(),PERIOD_D1,LowerFractal_1,1,LowFractalTime_1);
   CopyTime(Symbol(),PERIOD_D1,UpperFractal_2,1,UpFractalTime_2);
   CopyTime(Symbol(),PERIOD_D1,LowerFractal_2,1,LowFractalTime_2);
// Paso 2. Determinación del tiempo de formación de la siguiente barra del día:
//--- determinación del tiempo de formación de la siguiente barra del día (punto del stop para la función CopyHigh(), CopyLow() y CopyTime())
   datetime UpFractalTime_1_15=UpFractalTime_1[0]+86400;
   datetime UpFractalTime_2_15=UpFractalTime_2[0]+86400;
   datetime LowFractalTime_1_15=LowFractalTime_1[0]+86400;
   datetime LowFractalTime_2_15=LowFractalTime_2[0]+86400;
// Paso 3. Declaramos y llenamos los arrays para almacenar los datos de precio y de tiempo para el período de 15 minutos:  
//--- declaración de los arrays para almacenar los datos sobre los valores máximos y mínimos de precios
   double High_1_15[],Low_1_15[],High_2_15[],Low_2_15[];
//--- llenar los arrays con datos usando las funciones CopyHigh() y CopyLow()
   CopyHigh(Symbol(),PERIOD_M15,UpFractalTime_1[0],UpFractalTime_1_15,High_1_15);
   CopyHigh(Symbol(),PERIOD_M15,UpFractalTime_2[0],UpFractalTime_2_15,High_2_15);
   CopyLow(Symbol(),PERIOD_M15,LowFractalTime_1[0],LowFractalTime_1_15,Low_1_15);
   CopyLow(Symbol(),PERIOD_M15,LowFractalTime_2[0],LowFractalTime_2_15,Low_2_15);
//--- declaramos los arrays para almacenar los valores temporales que corresponden a los índices de las barras de los extremos de precio  
   datetime High_1_15_time[],High_2_15_time[],Low_1_15_time[],Low_2_15_time[];
//--- llenamos los arrays con los datos
   CopyTime(Symbol(),PERIOD_M15,UpFractalTime_1[0],UpFractalTime_1_15,High_1_15_time);
   CopyTime(Symbol(),PERIOD_M15,UpFractalTime_2[0],UpFractalTime_2_15,High_2_15_time);
   CopyTime(Symbol(),PERIOD_M15,LowFractalTime_1[0],LowFractalTime_1_15,Low_1_15_time);
   CopyTime(Symbol(),PERIOD_M15,LowFractalTime_2[0],LowFractalTime_2_15,Low_2_15_time);
// Paso 4. Búsqueda de los valores máximos y mínimos de precio; así como los valores temporales de los extremos concretados:
//--- usando las funciones ArrayMaximum() y ArrayMinimum() encontramos los valores máximos y mínimos de precios y de tiempo
   int Max_M15_1=ArrayMaximum(High_1_15,0,96);
   int Max_M15_2=ArrayMaximum(High_2_15,0,96);
   int Min_M15_1=ArrayMinimum(Low_1_15,0,96);
   int Min_M15_2=ArrayMinimum(Low_2_15,0,96);

En conclusión, hemos determinado las siguientes coordenadas de las líneas de tendencia:

1. Para la línea de soporte:

MQL4MQL5
  1. La primera coordenada de tiempo -  LowestBarTime_2_m15;
  2. La primera coordenada de precio  - LowerPrice_2_m15[LowestPrice_2_m15];
  3. La segunda coordenada de tiempo  - LowestBarTime_1_m15;
  4. La segunda coordenada de precio  - LowerPrice_1_m15[LowestPrice_1_m15].
  1. La primera coordenada de tiempo - Low_2_15_time[Min_M15_2];
  2. La primera coordenada de precio - Low_2_15[Min_M15_2];
  3. La segunda coordenada de tiempo - Low_1_15_time[Min_M15_1];
  4. La segunda coordenada de precio - Low_1_15[Min_M15_1].

2. Para la línea de resistencia:

MQL4MQL5
  1. La primera coordenada de tiempo -  HighestBarTime_2_m15;
  2. La primera coordenada de precio - UpperPrice_2_m15[HighestPrice_2_m15];
  3. La segunda coordenada de tiempo - HighestBarTime_1_m15;
  4. La segunda coordenada de precio  - UpperPrice_1_m15[HighestPrice_1_m15].
  1. La primera coordenada de tiempo - High_2_15_time[Max_M15_2];
  2. La primera coordenada de precio - High_2_15[Max_M15_2];
  3. La segunda coordenada de tiempo - High_1_15_time[Max_M15_1];
  4. La segunda coordenada de precio - High_1_15[Max_M15_1].


4. Creación de los objetos y modificación de sus propiedades. Redibujar las líneas

Ahora cuando ya sabemos las coordenadas de las líneas, nos queda crear los objetos gráficos:

MQL4
//--- crear la línea de soporte
   ObjectCreate(0,"TL_Support",OBJ_TREND,0,LowestBarTime_2_m15,LowerPrice_2_m15[LowestPrice_2_m15],
                LowestBarTime_1_m15,LowerPrice_1_m15[LowestPrice_1_m15]);
   ObjectSet("TL_Support",OBJPROP_COLOR,Support_Color);
   ObjectSet("TL_Support",OBJPROP_STYLE,Support_Style);
   ObjectSet("TL_Support",OBJPROP_WIDTH,Support_Width);
//--- crear la línea de resistencia
   ObjectCreate(0,"TL_Resistance",OBJ_TREND,0,HighestBarTime_2_m15,UpperPrice_2_m15[HighestPrice_2_m15],
                HighestBarTime_1_m15,UpperPrice_1_m15[HighestPrice_1_m15]);
   ObjectSet("TL_Resistance",OBJPROP_COLOR,Resistance_Color);
   ObjectSet("TL_Resistance",OBJPROP_STYLE,Resistance_Style);
   ObjectSet("TL_Resistance",OBJPROP_WIDTH,Resistance_Width);
MQL5
//--- crear la línea de soporte
   ObjectCreate(0,"TL_Support",OBJ_TREND,0,Low_2_15_time[Min_M15_2],Low_2_15[Min_M15_2],Low_1_15_time[Min_M15_1],Low_1_15[Min_M15_1]);
   ObjectSetInteger(0,"TL_Support",OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(0,"TL_Support",OBJPROP_COLOR,Support_Color);
   ObjectSetInteger(0,"TL_Support",OBJPROP_STYLE,Support_Style);
   ObjectSetInteger(0,"TL_Support",OBJPROP_WIDTH,Support_Width);
//--- crear la línea de resistencia
   ObjectCreate(0,"TL_Resistance",OBJ_TREND,0,High_2_15_time[Max_M15_2],High_2_15[Max_M15_2],High_1_15_time[Max_M15_1],High_1_15[Max_M15_1]);
   ObjectSetInteger(0,"TL_Resistance",OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(0,"TL_Resistance",OBJPROP_COLOR,Resistance_Color);
   ObjectSetInteger(0,"TL_Resistance",OBJPROP_STYLE,Resistance_Style);
   ObjectSetInteger(0,"TL_Resistance",OBJPROP_WIDTH,Resistance_Width);

De esta manera, he creado las líneas necesarias y he indicado sus parámetros de acuerdo con los parámetros de entrada que pueden ser establecidos por el usuario a su antojo.

Ahora hace falta implementar el redibujo de las líneas de tendencia.

Si la situación en el mercado cambia, por ejemplo aparece un extremo nuevo, será suficiente eliminar la línea existente:

MQL4
//--- redibujar la línea de soporte
//--- escribimos los valores de las coordenadas temporales de la línea de soporte en las variables
   datetime TL_TimeLow2=ObjectGet("TL_Support",OBJPROP_TIME2);
   datetime TL_TimeLow1=ObjectGet("TL_Support",OBJPROP_TIME1);
//--- si las coordenadas de la línea no coinciden con las coordenadas actuales
   if(TL_TimeLow2!=LowestBarTime_1_m15 && TL_TimeLow1!=LowestBarTime_2_m15)
     {
      //--- eliminamos la línea
      ObjectDelete(0,"TL_Support");
     }
//--- redibujar la línea de resistencia
//--- escribimos los valores de las coordenadas temporales de la línea de resistencia en las variables
   datetime TL_TimeUp2=ObjectGet("TL_Resistance",OBJPROP_TIME2);
   datetime TL_TimeUp1=ObjectGet("TL_Resistance",OBJPROP_TIME1);
//--- si las coordenadas de la línea no coinciden con las coordenadas actuales
   if(TL_TimeUp2!=HighestBarTime_1_m15 && TL_TimeUp1!=HighestBarTime_2_m15)
     {
      //--- eliminamos la línea
      ObjectDelete(0,"TL_Resistance");
     }
MQL5
//--- redibujar la línea de soporte
//--- escribimos los valores de las coordenadas temporales de la línea de soporte en las variables
   datetime TL_TimeLow2=(datetime)ObjectGetInteger(0,"TL_Support",OBJPROP_TIME,0);
   datetime TL_TimeLow1=(datetime)ObjectGetInteger(0,"TL_Support",OBJPROP_TIME,1);
//--- si las coordenadas de la línea no coinciden con las coordenadas actuales
   if(TL_TimeLow2!=Low_2_15_time[Min_M15_2] && TL_TimeLow1!=Low_1_15_time[Min_M15_1])
     {
      //--- eliminamos la línea
      ObjectDelete(0,"TL_Support");
     }
//--- redibujar la línea de resistencia
//--- escribimos los valores de las coordenadas temporales de la línea de resistencia en las variables
   datetime TL_TimeUp2=(datetime)ObjectGetInteger(0,"TL_Resistance",OBJPROP_TIME,0);
   datetime TL_TimeUp1=(datetime)ObjectGetInteger(0,"TL_Resistance",OBJPROP_TIME,1);
//--- si las coordenadas de la línea no coinciden con las coordenadas actuales
   if(TL_TimeUp2!=High_2_15_time[Max_M15_2] && TL_TimeUp1!=High_1_15_time[Max_M15_1])
     {
      //--- eliminamos la línea
      ObjectDelete(0,"TL_Resistance");
     }


5. Control de la carga del historial de las barras

Durante la prueba, me encontré con el problema de que las líneas no siempre se trazaban correctamente.

Al principio, pensé que había un error en el código o mi solución no funcionaba, pero luego comprendí que el problema fue causado por la carga insuficiente del historial de las barras en el período de tiempo menor, en mi caso en M15. Para que el sistema avise al usuario sobre estas situaciones, he decidido introducir la prueba adicional para la búsqueda de la barra en M15.

Para eso, en MQL4 he utilizado las posibilidades de la función iBarShift() que ha sido usada en el segundo paso del apartado “Búsqueda de los valores de precio y de tiempo de los fractales”.

Si la barra no se encuentra, la función iBarShift() devuelve -1. Entonces, se puede mostrar, por ejemplo, el aviso siguiente:

MQL4
//--- control de la carga de las barras en el historial
//--- si no se ha encontrado por lo menos una barra en M15
   if(UpperFractal_1_m15==-1 || UpperFractal_2_m15==-1
      || LowerFractal_1_m15==-1 || LowerFractal_2_m15==-1)
     {
      Alert(“¡El historial cargado no es suficiente para el funcionamiento correcto!”);
     }

En MQL5 he usado la función Bars() que devuelve el valor vacío si los datos de la serie temporal todavía no han sido formados en el terminal:

 
//--- control de la carga de las barras en el historial
//--- 1. determinamos el número de las barras en el intervalo de tiempo especificado
   int High_M15_1=Bars(Symbol(),PERIOD_M15,UpFractalTime_1[0],UpFractalTime_1_15);
   int High_M15_2=Bars(Symbol(),PERIOD_M15,UpFractalTime_2[0],UpFractalTime_2_15);
   int Low_M15_1=Bars(Symbol(),PERIOD_M15,LowFractalTime_1[0],LowFractalTime_1_15);
   int Low_M15_2=Bars(Symbol(),PERIOD_M15,LowFractalTime_2[0],LowFractalTime_2_15);
//--- 2. comprobar si el historial cargado no es suficiente para el redibujo correcto de la línea
//--- si no se ha encontrado por lo menos una barra
   if(High_M15_1==0 || High_M15_2==0 || Low_M15_1==0 || Low_M15_2==0)
     {
      Alert(“¡El historial cargado no es suficiente para el funcionamiento correcto!”);
     }


6. Señales sobre la ruptura de las líneas de tendencia, las notificaciones push

Para completar el cuadro, he decidido incluir la señal sobre la ruptura de la línea de tendencia. Mi línea de tendencia se traza por los extremos del período de tiempo del día, pero para la identificación de la ruptura más temprana, es necesario que la barra en H4 se cierre por debajo o por encima de la línea de tendencia.

En general, se puede dividir el proceso en tres pasos:

  1. Determinar el precio de cierre de la barra y el precio de la línea de tendencia;
  2. Determinar las condiciones de la ruptura de la línea de tendencia;
  3. Enviar las notificaciones push sobre la ruptura de la línea de tendencia.
MQL4
// 1. Obtener los parámetros del precio de la línea de tendencia
//--- determinar el precio de cierre de la barra con el índice 1
   double Price_Close_H4=iClose(NULL,240,1);
//--- determinar el tiempo de la barra con el índice 1
   datetime Time_Close_H4=iTime(NULL,240,1);
//--- determinar el índice de la barra en H4
   int Bar_Close_H4=iBarShift(NULL,240,Time_Close_H4);
//--- determinar el precio de la línea en H4
   double Price_Resistance_H4=ObjectGetValueByShift("TL_Resistance",Bar_Close_H4);
//--- determinar el precio de la línea en H4  
   double Price_Support_H4=ObjectGetValueByShift("TL_Support",Bar_Close_H4);
// 2. Condiciones de la ruptura de las líneas de tendencia
//--- para la ruptura de la línea de soporte
   bool breakdown=(Price_Close_H4<Price_Support_H4);
//--- para la ruptura de la línea de resistencia
   bool breakup=(Price_Close_H4>Price_Resistance_H4);
// 3. Enviar las notificaciones push
   if(breakdown==true)
     {
      //--- enviar no más de una notificación cada 4 horas
      int SleepMinutes=240;
      static int LastTime=0;
      if(TimeCurrent()>LastTime+SleepMinutes*60)
        {
         LastTime=TimeCurrent();
         SendNotification(Symbol()+“Ruptura de la línea de soporte”);
        }
     }
   if(breakup==true)
     {
      //--- enviar no más de una notificación cada 4 horas
      SleepMinutes=240;
      LastTime=0;
      if(TimeCurrent()>LastTime+SleepMinutes*60)
        {
         LastTime=TimeCurrent();
         SendNotification(Symbol()+“Ruptura de la línea de resistencia”);
        }
     }
MQL5
// 1. Obtener los parámetros del precio de la línea de tendencia
   double Close[];
   CopyClose(Symbol(),PERIOD_H4,TimeCurrent(),10,Close);
//--- establecemos el orden de indexación del array
   ArraySetAsSeries(Close,true);
//---
   datetime Close_time[];
   CopyTime(Symbol(),PERIOD_H4,TimeCurrent(),10,Close_time);
//--- establecemos el orden de indexación del array
   ArraySetAsSeries(Close_time,true);
//---
   double Price_Support_H4=ObjectGetValueByTime(0,"TL_Support",Close_time[1]);
   double Price_Resistance_H4=ObjectGetValueByTime(0,"TL_Resistance",Close_time[1]);
// 2. Condiciones de la ruptura de las líneas de tendencia
   bool breakdown=(Close[1]<Price_Support_H4);
   bool breakup=(Close[1]>Price_Resistance_H4);
// 3. Enviar las notificaciones push
   if(breakdown==true)
     {
      //--- enviar no más de una notificación cada 4 horas
      int SleepMinutes=240;
      static int LastTime=0;
      if(TimeCurrent()>LastTime+SleepMinutes*60)
        {
         LastTime=(int)TimeCurrent();
         SendNotification(Symbol()+“Ruptura de la línea de soporte”);
        }
     }
   if(breakup==true)
     {
      //--- enviar no más de una notificación cada 4 horas
      int SleepMinutes=240;
      static int LastTime=0;
      if(TimeCurrent()>LastTime+SleepMinutes*60)
        {
         LastTime=(int)TimeCurrent();
         SendNotification(Symbol()+“Ruptura de la línea de resistencia”);
        }
     }

Para identificar la ruptura, en MQL4 he utilizado la función ObjectGetValueByShift(), y en MQL5 he usado la función ObjectGetValueByTime().

Tal vez, en la función ObjectGetValueByShift() podría poner 1 en vez de Bar_Close_H4, pero he decidido primero determinar el índice para H4. He utilizado la solución para limitar el número de los mensajes a enviar que ha sido publicada en este tema del foro, ¡muchas gracias a esta gente!


7. Aplicación práctica de las líneas de tendencia en el trading

La manera más simple es la siguiente: identificamos la ruptura, esperamos el retroceso del precio y entramos en el mercado después del retroceso correspondiente.

Idealmente, tiene que salir algo parecido a eso:

Fig. 3. Ruptura de la línea de tendencia

Fig. 3. Ruptura de la línea de tendencia

Luego Usted puede usar su imaginación y tratar de identificar las formaciones, es decir las figuras del análisis técnico, por ejemplo, el triángulo:

Fig. 4. Figura “Triángulo”

Fig. 4. Figura “Triángulo”

En la imagen las líneas por el período de tiempo menor no se aclaran.


Conclusión

Pues, hemos llegado al final del artículo. Espero que sea útil. Este artículo está orientado a los novatos en la programación, a los aficionados como yo.

Aprendí mucho cuando escribía este artículo. En primer lugar, empecé a hacer los comentarios más claros al escribir el código; segundo, cuando empecé a escribir el artículo, tenía en MQL5 una solución más compleja y voluminosa para precisar los extremos, sin embargo, durante la escritura del artículo encontré una solución más simple que al final fue descrita aquí.

¡Gracias por leerlo, se aprecia cualquier crítica!


Traducción del ruso hecha por MetaQuotes Software Corp.
Artículo original: https://www.mql5.com/ru/articles/1201

Archivos adjuntos |
trendlines.mq4 (19.87 KB)
trendlines.mq5 (20.95 KB)
Recetas de MQL5 - implementamos el array asociativo o el diccionario para el acceso rápido a los datos Recetas de MQL5 - implementamos el array asociativo o el diccionario para el acceso rápido a los datos

En este artículo se describe un algoritmo especial que permite acceder de manera eficaz a los elementos usando su clave única. Como clave se puede utilizar cualquier tipo básico de datos, por ejemplo, las cadenas o variables de números enteros. Este contenedor de datos suelen llamarlo el diccionario o array asociativo. La solución de muchas tareas con su ayuda resulta más simple y eficaz.

Neuroredes gratis y a mogollón: NeuroPro y MetaTrader 5 Neuroredes gratis y a mogollón: NeuroPro y MetaTrader 5

Si los programas especializados de nueroredes para el trading le parecen caros o complicados (o al contrario, primitivos), entonces pruebe NeuroPro, está en ruso, es gratuito y contiene el conjunto ideal de posibilidades para los aficionados. Prodrá familiarizarse con su uso en MetaTrader 5 en este artículo.

Crear aplicación interactiva para visualizar los canales RSS en MetaTrader 5 Crear aplicación interactiva para visualizar los canales RSS en MetaTrader 5

En este artículo se describe cómo crear la aplicación que visualiza los canales RSS. Además, hablaremos sobre los aspectos del uso de la Biblioteca estándar durante la creación de los programas interactivos en MetaTrader 5.

Estudiamos la clase CCanvas. Implementación de la transparencia de los objetos gráficos Estudiamos la clase CCanvas. Implementación de la transparencia de los objetos gráficos

¿Está harto del gráfico anguloso de las medias móviles? ¿Quiere usted dibujar en el terminal algo más bonito que un simple rectángulo rellenado? Ahora es posible dibujar de manera vistosa en el terminal. Para ello existe la clase de creación de gráficos personalizados CCanvas. Con ayuda de esta clase, es posible conseguir transparencia, mezclar los colores y alcanzar la ilusión de transparencia con ayuda de la superposición y la mezcla de colores.