Utilidad para la selección y navegación en MQL5 y MQL4: aumentando la informatividad de los gráficos

21 junio 2019, 14:07
Roman Klymenko
0
859

Introducción

En los artículos anteriores (Utilidad para la selección y navegación en MQL5 y MQL4: añadiendo la búsqueda automática de patrones y visualización de símbolos encontrados, Utilidad para la selección y navegación en MQL5 y MQL4: añadiendo las pestañas de «recordatorios» y guardando objetos gráficos, Desarrollando una utilidad para la selección y navegación de instrumentos en los lenguajes MQL5 y MQL4) ya hicimos bastante sobre este asunto. Pero aún así, eso no es suficiente para una negociación intradía de calidad. Hoy, añadiremos una nueva funcionalidad que permitirá encontrar los puntos de entrada en la transacción, o los puntos de salida de ella.

Cada elemento de la nueva funcionalidad será descrito en un apartado separado del artículo. Primero, vamos a considerar, ¿para qué es necesario eso? Luego, se mostrará la función o el código que hace eso, para el caso si Usted quiere implementar lo mismo en sus proyectos.


Ocultar símbolos cuya tendencia actual se diferencia de la tendencia del día anterior

Parámetro de entrada: Ocultar si la tendencia de hoy != ayer
Área: Configuraciones de la filtración

Muchos gurús del trading recomiendan para la negociación intradía seleccionar sólo las acciones para las cuales la tendencia de hoy coincide con la tendencia de ayer. Simplificando, si el precio de una acción crecía ayer, entonces, hoy también tiene que crecer. Consecuentemente, el trading este día es posible sólo en Long, y viceversa.

Para filtrar esos símbolos, se usa la siguiente función:

/*
Devuelve true si la tendencia de hoy no es igual a la de ayer
symname - nombre del símbolo para la verificación
*/
bool check_no_trend(string symname){
   MqlRates rates2[];
   ArraySetAsSeries(rates2, true);
   if(CopyRates(symname, PERIOD_D1, 0, 2, rates2)==2){
      if( rates2[0].close>rates2[0].open && rates2[1].close>rates2[1].open ){
         return false;
      }
      if( rates2[0].close<rates2[0].open && rates2[1].close<rates2[1].open ){
         return false;
      }
   }
   return true;
}


Mostrar el inicio de la sesión

Parámetro de entrada: Mostrar el comienzo del día (en los períodos hasta el día)
Área: Configuraciones de los gráficos

El comienzo de la sección de trading es el momento cuando se abren los mercados de acciones, si se trata de las acciones. Например, 16:30 para el mercado de acciones americano, 10:00 para el mercado europeo y ruso. Si se trata del mercado Forex, tomamos la medianoche como el inicio de la sesión.

En los marcos temporales (timeframe) pequeños, por ejemplo M5, resulta difícil determinar inmediatamente el inicio de la sesión actual. Por ejemplo, para ver rápidamente si una acción está subiendo o cayendo hoy. Por tanto, vamos a añadir una configuración que nos permita ver inmediatamente a partir de qué barra ha comenzado el día de trading actual del instrumento.

Función para visualizar el inicio de la sesión:

/*
Muestra el comienzo del día en el gráfico
currChart - id del gráfico
day - número del día (0 - actual)
*/
void showNdays(long currChart, int day){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_D1, day, 1, rates)>0){
      ObjectCreate(currChart, exprefix+"_Nday", OBJ_VLINE, 0, rates[0].time, 0);
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_BACK,true); 
   }
}

En el gráfico, eso se ve como una línea vertical roja:

Mostrar el inicio de la sesión

Tal vez, alguien note que una funcionalidad semejante ya existe en MetaTrader. Además, se puede observar no sólo el inicio de la última sesión, sino también, en general, el inicio de cada sesión. Para eso, basta con marcar la casilla Mostrar separadores de períodos en las propiedades del gráfico. Pero, en la práctica, en algunas ocasiones y en determinados timeframes, esta funcionalidad es redundante y hace que el gráfico sea muy colorido e inconveniente para la lectura. Por ejemplo:

Mostrar separadores de períodos


Mostrar Low y High del día de ayer y anteayer

Parámetro de entrada: Mostrar low y high del día de ayer y Mostrar low y high del día de anteayer
Área: Configuraciones de los gráficos

Al trabajar dentro del día, High y Low de ayer y anteayer son los niveles muy populares de soporte y resistencia. La situación cuando el precio baja, alcanza High de ayer/anteayer y rebota, tiene lugar muy a menudo. De acuerdo con mis propias observaciones, puedo decir que el precio en los casos de 70% o más no rompe High/Low desde la primera vez tanto ayer, como anteayer.

Por eso, nunca hay que despreciar estos niveles de soporte y resistencia.

Para mostrar Low y High del día seleccionado, se usa la siguiente función:

/*
Mostrar Low y High del día especificado en el gráfico
currChart - id del gráfico
day - número del día mostrado
*/
void showHOBeforeDay(long currChart, int day=1){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   
   color curColor=clrAquamarine;
   switch(day){
      case 2:
         curColor=clrOlive;
         break;
   }
   
   if(CopyRates(ChartSymbol(currChart), PERIOD_D1, day, 1, rates)>0){
      ObjectCreate(currChart, exprefix+"_beforeday_high_line"+(string) day, OBJ_HLINE, 0, 0, rates[0].high);
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_COLOR,curColor); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_BACK,true); 
      
      ObjectCreate(currChart, exprefix+"_beforeday_low_line"+(string) day, OBJ_HLINE, 0, 0, rates[0].low);
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_COLOR,curColor); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_BACK,true); 
   }
}

En el gráfico, Low y High de ayer se muestran con líneas horizontales claras, mientras que Low y High de anteayer, con líneas de color glauco:

Mostrar low y high del día de ayer/anteayer


Mostrar precios redondos más cercanos

Parámetro de entrada: Mostrar precios redondos más cercanos (período < 1day)
Área: Configuraciones de los gráficos

Otros niveles naturales de soporte/resistencia son los precios redondos. Es decir, son los precios de los instrumentos que se terminan en .00 o .50. Muchos traders a menudo buscan los segmentos planos cerca de los niveles redondos semejantes.

Los precios terminados en .25 y .75 también tienen las mismas propiedades. Pero ellos actúan como niveles con probabilidad menor, por eso, no vamos a monitarearlos para no «embasurar» el gráfico.

Para mostrar los precios redondos, se usa la siguiente función:

/*
Mostrar en el gráfico 3 niveles redondos más próximos al precio actual.
currChart - id del gráfico
*/
void showRoundPrice(long currChart){
   string name=ChartSymbol(currChart);
   int tmpPrice;
   
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(name, PERIOD_D1, 0, 1, rates)==1){
      switch((int) SymbolInfoInteger(name, SYMBOL_DIGITS)){
         case 0:
            break;
         case 2:
         case 3:
         case 5:
            tmpPrice=(int) rates[0].close;

            ObjectCreate(currChart, exprefix+"_round_line_00_0", OBJ_HLINE, 0, 0, (double) tmpPrice-1 );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_0", OBJ_HLINE, 0, 0, (double) tmpPrice-0.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_BACK,true); 
            
            ObjectCreate(currChart, exprefix+"_round_line_00_1", OBJ_HLINE, 0, 0, (double) tmpPrice );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_1", OBJ_HLINE, 0, 0, (double) tmpPrice+0.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_00_2", OBJ_HLINE, 0, 0, (double) tmpPrice+1 );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_2", OBJ_HLINE, 0, 0, (double) tmpPrice+1.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_BACK,true); 
            
            break;
      }
   }
}

En el gráfico, los niveles redondos se muestran con líneas horizontales punteadas:

Mostrar precios redondos más cercanos


Mostrar el cierre de la hora

Parámetro de entrada: Mostrar el cierre de la hora (período < 1hour)
Área: Configuraciones de los gráficos

Continuando el tema de los niveles naturales de soporte/resistencia, se puede mencionar los niveles del cierre de la hora. Se considera que el precio de cierre de la hora también puede actuar como un nivel de soporte/resistencia en los timeframes más pequeños. La verdad es que no lo he notado en la práctica. No obstante, vamos a implementar la posibilidad de visualizar un modelo semejante por lo menos para las últimas 4 horas.

Función para destacar el cierre de la hora en el gráfico:

/*
Mostrar el cierre de las últimas 4 horas en el gráfico
currChart - id del gráfico
*/
void showCloseHour(long currChart){
   MqlDateTime tmpTime;
   int tmpOffset=0;
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_M30, 0, 9, rates)>0){
      tmpOffset=0;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_0", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_1", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_2", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_3", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_BACK,true); 
      
   }
}

En el gráfico, el cierre de las últimas 4 horas se muestra como las líneas verticales amarillas:

Mostrar el cierre de la hora


Mostrar el precio máximo y mínimo del año

Parámetro de entrada: Mostrar el precio máx./min. del año
Área: Configuraciones de los gráficos

Además, entre los traders son populares los precios máximos y mínimos. Vamos a mostrarlos en el gráfico.

Para mostrar los precios límite del año, se usa la siguiente función:

/*
Mostrar el precio máximo y mínimo del último año en el gráfico.
currChart - id del gráfico.
*/
void showMaxPrice(long currChart){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_MN1, 0, 12, rates)==12){
      double maxPrice=0;
      double minPrice=0;
      
      
      for(int j=0; j<12; j++){
         if( maxPrice==0 || maxPrice<rates[j].high ){
            maxPrice=rates[j].high;
         }
         if( minPrice==0 || minPrice>rates[j].low ){
            minPrice=rates[j].low;
         }
      }
      
      ObjectCreate(currChart, exprefix+"_maxprice_line", OBJ_HLINE, 0, 0, maxPrice);
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_BACK,true); 

      ObjectCreate(currChart, exprefix+"_minprice_line", OBJ_HLINE, 0, 0, minPrice);
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_BACK,true); 
      
      
   }
}

Los precios máximos/mínimos de los últimos 12 meses se muestran a través de las líneas horizontales de color violeta:

Mostrar el precio máximo/mínimo del año


Mostrar spread al abrir el gráfico

Parámetro de entrada: Mostrar spread al abrir el gráfico
Área: Configuraciones de los gráficos

Si Usted negocia con los Stop los pequeños, el spread actual del instrumento para Ud. es uno de los factores clave para entrar en la transacción. Por eso, es importante saberlo de inmediato en el momento de la apertura del gráfico. Pues, vamos a aumentar la informatividad de nuestros gráficos.

Sólo hay que recordar que mostramos el spread exactamente en el momento de la apertura del gráfico. Tal vez, dentro de un rato el spread del gráfico cambie. El nivel del spread no se muestra en tiempo real, sino se usa sólo para estimar el intervalo actual de los spreads del instrumento.

El spread es devuelto por la siguiente pequeña función:

/*
Devuelve la cadena con el spread actual para el símbolo especificado.
symname - nombre del símbolo
*/
string getmespread_symbol(string symname){
   double curSpread=SymbolInfoDouble(symname, SYMBOL_ASK)-SymbolInfoDouble(symname, SYMBOL_BID);
   return "Spread: "+(string) DoubleToString(curSpread, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+" ("+DoubleToString(curSpread/SymbolInfoDouble(symname, SYMBOL_POINT), 0)+" p)";
}

El spread se muestra en el comentario para el gráfico abierto, entre otra información adicional:

Mostrar spread

Aplicar una plantilla con el nombre al gráfico

Parámetro de entrada: Aplicar una plantilla con el nombre al gráfico
Área: Configuraciones de los gráficos

Las plantillas en MetaTrader se usan para poder aplicar rápidamente las configuraciones preferidas, EAs al gráfico, y lo más importante para nosotros, los indicadores utilizados por Ud. con parámetros preferidos.

Pero «rápido» es un concepto elástico. Para aplicar la plantilla al gráfico, seleccione el elemento Plantilla / «Nombre de plantilla» en el menú contextual. ¿Pero qué pasa si algún indicador, por ejemplo, la media móvil, es importante para Ud. a la hora de tomar decisiones y desea verlo en cada gráfico que abre? Imagine que Ud. abre centenares de gráficos de varios instrumentos al día. ¿Entonces, debería hacer clic en cada uno ellos?

Sería mucho más fácil si se pudiera aplicar automáticamente una determinada plantilla con un conjunto de indicadores a cada gráfico a abrir. Vamos a implementar este recurso.

Para aplicar una plantilla al gráfico, basta con usar el comando ChartApplyTemplate que funciona de la misma manera tanto en MQL5, como en MQL4:

      ChartApplyTemplate(curChartID[ArraySize(curChartID)-1], allApplyTemplate+".tpl");


Mostrar ATR según el método de Gerchik

Parámetro de entrada: Mostrar ATR según el método de Gerchik
Área: Configuraciones de los gráficos

ATR, o sea, el movimiento medio diario del instrumento durante un cierto período, es un importante parámetro en la determinación del rango de la acción del instrumento. Se usa para diferentes propósitos.

Por ejemplo, para decidir si merece la pena entrar en la transacción durante la transacción intradía. Si Ud. espera a hacer un movimiento de 100 puntos en el instrumento, y en media el instrumento recorre 50 puntos, sus posibilidades son pequeñas y es mejor abstenerse de negociar.

Además, se considera que si el instrumento ya ha pasado más de 80% de su ATR diario en una dirección, no tiene sentido abrir transacciones en la misma dirección y se puede trabajar sólo en la dirección opuesta.

ATR según el método de Gerching se diferencia de ATR habitual sólo en que no se toman en cuenta las barras paranormales. Es decir, las barras que son 2 veces más grandes que la media o 0,3 veces más pequeños en comparación con las barras medio estadísticas.

Generalmente, ATR se calcula durante 5 o 3 días.

La siguiente función se encarga de mostrar ATR según el método de Gerchik:

/*
Devolver la cadena con ATR según Gerchik para el símbolo especializado:
symname - nombre del símbolo
*/
string getmeatr_symbol(string symname){
   string msg="";
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   double atr=0;
   double pre_atr=0;
   int curDigits=(int) SymbolInfoInteger(symname, SYMBOL_DIGITS);
   string currencyS=SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT);
   int count=0;
   int copied=CopyRates(symname, PERIOD_D1, 0, 8, rates);
   if(copied>1){
      for(int j=1; j<copied; j++){
         pre_atr+=rates[j].high-rates[j].low;
      }
      pre_atr/=(copied-1);
   }
   if(pre_atr>0){
      for(int j=1; j<copied; j++){
         if( rates[j].high-rates[j].low > pre_atr*2 ) continue;
         if( rates[j].high-rates[j].low < pre_atr*0.3 ) continue;
               
         if( ++count > 5 ){
            break;
         }
               
         atr+=rates[j].high-rates[j].low;
      }
      if( count > 5 ){
         count=5;
      }
      atr= NormalizeDouble(atr/count, curDigits );
   }
   if(atr>0){
      StringAdd(msg, "ATR: "+(string) DoubleToString(atr, curDigits)+" "+currencyS+", today: "+DoubleToString(rates[0].high-rates[0].low, curDigits)+" "+currencyS+" ("+(string) (int) (((rates[0].high-rates[0].low)/atr)*100) +"%)");
   }
   
   return msg;
}

Nuestra utilidad mustra ATR en el comentario para el gráfico, igual como el spread considerado en el apartado anterior. Así que se puede ver ATR en la captura de pantalla anterior.


Mostramos las direcciones de los símbolos guías

Parámetro de entrada: Mostrar las direcciones del símbolo #N
Área: Mostrar información adicional

A juzgar por el material ya publicado en este artículo, la negociación intradía es una cosa bastante complicada, ya que es necesario tener en la mente y acompañar muchas cosas. Y como resulta, eso no es todo.

Muchos traders recomiendan observar la dirección actual de los llamados símbolos guías antes de negociar.

Por ejemplo, si Usted opera en el mercado de acciones de los EE.UU., es necesario monitorear:

  • los principales índices americanos, por lo menos Dow Jones o SP500;
  • uno de los índices de otros países: China, Europa, Japón;
  • empresas con capitalización grande en diferentes sectores del mercado: JPMorgan en el sector bancario, Apple en tecnologías, ExxonMobil en energética, IBM y algunos otros.

Además, se puede monitorear el estado de las cotizaciones del petróleo, oro, dólar.

Sería mejor que todos los símbolos guías sigan la misma dirección. Como Ud. probablemente haya adivinado, es mejor negociar sólo en la dirección en la que van los símbolos guías.

Puesto que diferentes brókers tienen el mismo instrumento con nombre diferente, es imposible especificar programaticamente los instrumentos a monitorear. Pero podemos añadir los parámetros de entrada del tipo string, en los cuales el mismo usuario escribirá los tickets de los símbolos necesarios de tal amanera como se lleman en el lado del bróker. Para este propósito, han sido añadidos 7 parámetros a la utilidad.

La dirección del símbolo especificado se devuelve por la siguiente función:

/*
Devolver la cadena con la dirección del movimiento del precio para el símbolo especificado:
symname - nombre del símbolo
show - mostrar la etiqueta con el nombre del símbolo en la cadena
*/
string getmeinfo_symbol(string symname, bool show=true){
   MqlRates rates2[];
   ArraySetAsSeries(rates2, true);
   string msg="";

   if(CopyRates(symname, PERIOD_D1, 0, 1, rates2)>0){
      if(show){
         StringAdd(msg, (string) symname+": ");
      }
      StringAdd(msg, "D1 ");
      if( rates2[0].close > rates2[0].open ){
         StringAdd(msg, "+"+DoubleToString(((rates2[0].close-rates2[0].open)/rates2[0].close)*100, 2) +"% (+"+DoubleToString(rates2[0].close-rates2[0].open, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
      }else{
         if( rates2[0].close < rates2[0].open ){
            StringAdd(msg, "-"+DoubleToString(((rates2[0].open-rates2[0].close)/rates2[0].close)*100, 2) +"% (-"+DoubleToString(rates2[0].open-rates2[0].close, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
         }else{
            StringAdd(msg, "0%");
         }
      }
   }
   if(CopyRates(symname, PERIOD_H1, 0, 1, rates2)>0){
      StringAdd(msg, ", H1 ");
      if( rates2[0].close > rates2[0].open ){
         StringAdd(msg, "+"+DoubleToString(((rates2[0].close-rates2[0].open)/rates2[0].close)*100, 2)+"% (+"+DoubleToString(rates2[0].close-rates2[0].open, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
      }else{
         if( rates2[0].close < rates2[0].open ){
            StringAdd(msg, "-"+DoubleToString(((rates2[0].open-rates2[0].close)/rates2[0].close)*100, 2)+"% (-"+DoubleToString(rates2[0].open-rates2[0].close, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
         }else{
            StringAdd(msg, "0%");
         }
      }
   }
   
   return msg;
}

Las direcciones se muestran en el comentario para el gráfico en el que se ejecuta la utilidad. El elemento tiene la siguiente apariencia.

Mostramos las direcciones de los símbolos guías

Nótese que la dirección del movimiento de los símbolos guías no se actualiza automáticamente. Para que la información sobre ellos se actualice, es necesario ir a una de las pestañas deferente de la que está abierta en este moemento, o hacer clic en la tecla R. Por otra parte, podemos simplificar eso usando un nuevo parámetro de entrada.


Actualización automática de las pestañas de la utilidad

Parámetro de entrada: Actualizar automáticamente la pestaña abierta cada, segundos
Área:Mostrar información adicional

Si quiere que el contenido de la pestaña abierta en este momento se actualice automáticamente, y no sólo cuando se pulsa la tecla R, entonces, simplemente especifique el número de segundos transcurridos los cuales la actualización debe realizarse. El valor de este parámetro más de 0 informa a la utilidad que si ha pasado más del número de segundos especificado desde el momento de la visualización de la pestaña, hay que actualizar esta pestaña. Es decir, eso no significa que la pestaña va a actualizarse estrictamente cada N segundos. Lo más probable, eso significa que será actualizada aproximadamente dentro de N más uno o dos segundos.

El código que implementa esta funcionalidad se encuentra dentro de la función OnTimer y es bastante simple:

   // actualizar el contenido de la pestaña en segundos
   if( autoUpdateAfter>0 && TimeCurrent()-lastUpd >= autoUpdateAfter ){
      start_symbols();
      lastUpd=TimeCurrent();
   }

Naturalmente, cuando la utilidad se inicia, inicializaremos el valor de la variable lastUpd con la hora actual en la función OnInit.

Mostrar la información financiera de la acción

Parámetro de entrada: Mostrar la información sobre la empresa
Área: Datos externos

Si Ud. sigue los indicadores fundamentales de la empresa antes de comprar o vender sus acciones, tal vez, haya soñado desde hace tiempo en que todos estos indicadores se visualicen directamente en la ventana de MetaTrader, para no tener que navegar por diferentes sitios web en busca de los indicadores de cada acción.

Vamos a intentar que eso sea así. Para no complicar mucho, visualizaremos los indicadores en la pestaña Asesores Expertos del terminal inmediatamente después de que el gráfico de alguna acción haya sido abierto a través de nuestra utilidad.

Los indicadores financieros no se sacarán de su caletre. Primero, quería «envolverlos» directamente en el EA, pero el error de la falta de la memoria impidió hacerme eso. Por tanto, todos los indicadores financieros se almacenan separadamente, en la carpeta finder adjunta al artículo. Para que esta funcionalidad opere, descargue el archivo comprimido con esta carpeta, descomprímelo y coloque la carpeta finder dentro de la carpeta Files de su terminal.

Para encontrar la carpeta Files, abra el menú Archivo en la ventana de MetaTrader, y haga clic en el elemento Abrir carpeta de datos. Después de eso, vaya a la carpeta MQL4 o MQL5 en la ventana del navegador que se abre.

Estos indicadores financieros son relevantes en el momento de la escritura de este artículo y, tal vez, a lo largo de algunos meses posteriores. Si en el futuro, necesitará los datos actuales, envíe un mensaje privado.

Pero volvamos a nuestra función de la salida de datos. Esta función limpia el ticket de la empresa de todo lo innecesario que su bróker puede añadir a él, a saber, del prefijo #, así como, de los sufijos .us y .eu que se añaden por algunos brókers. Si su broker añade otra cosa a su tiket, tendrá que añadir al código de la utilidad sus filtros que eliminan estos símbolos.

Si por el ticket no ha sido encontrada ninguna información necesaria en la carpeta finder, se realiza la búsqueda por el nombre de la empresa.

void printTicker(string ticker, string name){
   bool isYes=false;
   int filehandle;
   
   // limpiamos el ticket de los sufijos y prefijos sobrantes
   // también lo pasamos a las minúsculas
   StringToLower(ticker);
   StringReplace(ticker, "#", "");
   StringReplace(ticker, ".us", "");
   StringReplace(ticker, ".eu", "");
   
   // pasamos el nombre de la empresa en las minúsculas
   StringToLower(name);
   
   ResetLastError(); 
   // si la carpeta finder contiene la información sobre esta empresa, la mostramos
   if( FileIsExist("finder\\"+ticker+".dat") ){
      isYes=true;
      filehandle=FileOpen("finder\\"+ticker+".dat",FILE_READ|FILE_TXT); 
      if(filehandle!=INVALID_HANDLE){ 
         int str_size; 
         string str; 
         Print("----------------");
         while(!FileIsEnding(filehandle)){ 
            str_size=FileReadInteger(filehandle,INT_VALUE); 
            str=FileReadString(filehandle,str_size); 
            Print(str);
         }
         FileClose(filehandle); 
      }
   }else if( FileIsExist("finder\\"+name+".dat") ){
      isYes=true;
      filehandle=FileOpen("finder\\"+name+".dat",FILE_READ|FILE_TXT); 
      if(filehandle!=INVALID_HANDLE){ 
         int str_size; 
         string str; 
         Print("----------------");
         while(!FileIsEnding(filehandle)){ 
            str_size=FileReadInteger(filehandle,INT_VALUE); 
            str=FileReadString(filehandle,str_size); 
            Print(str);
        }
         FileClose(filehandle); 
      }
   }
   
   // en caso contrario, escribimos que la información no ha sido encontrada
   if(!isYes){
      Print("No hay datos sobre el símbolo");
   }
}

Como resultado, al abrir el gráfico de cualquier acción con la ayuda de esta utilidad, la información sobre esta empresa se mostrará en la pestaña Asesor Experto. Aproximadamente, así:

Información financiera sobre la empresa


Mostrar el beneficio de hoy

Parámetro de entrada: Mostrar el beneficio de hoy
Área: Mostrar información adicional

Finalmente, vamos a añadir un indicador al gráfico que nos permitirá parar a tiempo durante nuestra negociación diaria, es decir, el número de ganancias o pérdidas obtenidas en un día, así como, el número total de transacciones por día, número de transacciones rentables y no rentables (se muestra en el gráfico precisamente en este orden).

Para MQL4, se puede obtener el beneficio actual usando la función personalizada getmetoday_profit() cuyo código se muestra más abajo. Pero para MQL5, esta función no es suficiente.

En MQL5, primero, comprobamos si es necesario actualizar los datos sobre las posiciones cerradas. Para eso, se utiliza la variable needHistory declarada globalmente. En la función estándar OnInit(), a esta función se le asigna el valor true. Por tanto, al ejecutar la función getmetoday_profit() por primera vez, se carga adicionalmente la información sobre las transacciones desde el historial. Después de eso, el valor de la variable needHistory se hace igual a false.

A continuación, usamos la función estándar de MQL5 OnTrade() para cargar adicionalmente el historial de las transacciones cada vez que cierre alguna posición abierta.

Como resultado, obtenemos el siguiente código:

#ifdef __MQL5__ 
   void OnTrade(){
      if(orders_total==PositionsTotal()){
         return;
      }
      if(orders_total>PositionsTotal()){
         needHistory=true;
      }
      orders_total=(ushort) PositionsTotal();
   }
#endif 
/*
Devuelve la cadena con el tamaño de la ganancia/pérdida de hoy.
*/
string getmetoday_profit(){
   string msg="";
   double curProfit=0;
   int tradeAll=0;
   int tradeMinus=0;
   int tradePlus=0;
   
   MqlDateTime curD;
   TimeCurrent(curD);
   curD.hour=0;
   curD.min=0;
   curD.sec=0;
   
   #ifdef __MQL5__ 
      if( needHistory ){
         HistorySelect(StructToTime(curD),TimeCurrent()); 
      }
      uint totalHistory=HistoryDealsTotal();
      double currHistory=0;
      ulong ticket_history;
      for(uint j=0;j<totalHistory;j++){
         if((ticket_history=HistoryDealGetTicket(j))>0 ){
            double profitHistory=HistoryDealGetDouble(ticket_history,DEAL_PROFIT);
            profitHistory+=HistoryDealGetDouble(ticket_history,DEAL_COMMISSION);
            profitHistory+=HistoryDealGetDouble(ticket_history,DEAL_SWAP);
            if(profitHistory!=0){
               currHistory+=profitHistory;
            }
         }
      }
         
   #else 
      int cntMyPos=OrdersHistoryTotal();
      if(cntMyPos>0){
         for(int ti=cntMyPos-1; ti>=0; ti--){
            if(OrderSelect(ti,SELECT_BY_POS,MODE_HISTORY)==false) continue;
            
            if( OrderCloseTime()<StructToTime(curD) ){ continue; }
            
            double tmpProfit=OrderProfit();
            tmpProfit+=OrderSwap();
            tmpProfit+=OrderCommission();
            
            tradeAll++;
            if(tmpProfit>0){
               tradePlus++;
            }else if(tmpProfit<0){
               tradeMinus++;
            }
            curProfit+=tmpProfit;
         }
      }
   #endif 
   
   if(tradeAll>0){
      StringAdd(msg, "Today: "+DoubleToString(curProfit, 2)+" "+AccountInfoString(ACCOUNT_CURRENCY)+" ("+(string) tradeAll+";+"+(string) tradePlus+";-"+(string) tradeMinus+")");
   }
   
   return msg;
}

El beneficio también se muestra en el gráfico en el que se ejecuta la utilidad. Será así:

Visualización del beneficio de hoy

Nótese que el beneficio diario no se recalcula automáticamente. Para que la información sobre el beneficio actual se actualice, es necesario ir a una de las pestañas deferente de la que está abierta en este momento, o hacer clic en la tecla R.


Conclusiones

Probablemente, éste es el último artículo de esta serie. Espero que la utilidad resultante sea útil para Usted.

Pero si le falta alguna funcionalidad, escríbame de ello. Si estas dudas serán suficientes para un nuevo artículo, el desarrollo de la utilidad continuará.

En conclusión, vamos a hacer un resumen y revisemos brevemente la funcionalidad que hemos implementado en este artículo.

Pues bien, después de iniciar la utilidad, veremos una lista de instrumentos que satisfacen nuestras condiciones. Por encima de esta lista, veremos los botones de las pestañas: All, LONG, SHORT, Range, así como, las pestañas de filtración automática. Por defecto, la pestaña All está abierta:

Gráfico con la utilidad iniciada

Además, en el comentario para el gráfico, podemos observar una línea que comienza con la palabra update. Ahí se muestra la hora de la última actualización del contenido de la pestaña. Usted puede pulsar la tecla R para actualizar la pestaña actual manualmente. Adicionalmente, en los ajustes de la utilidad, se puede indicar la frecuencia en segundos, con la que el contenido de la pestaña actual abierta va a actualizarse.

Por cierto, sobre los ajustes de la utilidad. Si analizamos estos ajustes, será más simple comprender la funcionalidad de nuestra utilidad.

La lista de los instrumentos que se muestran en la pestaña All depende de los ajustes en el grupo Configuraciones de filtración:

Grupo de ajustes Configuraciones de filtración

Si hacemos clic en el botón de algún instrumento mostrado por la utilidad, verá el gráfico de este instrumento con la información adicional sobre él:

Gráfico del instrumento siendo abierto por la utilidad

En primer lugar, son los botones de navegación que saltan a la vista en este gráfico. Puede usarlos para alternar los instrumentos filtrados por la utilidad. Además, utilice estos botones para añadir el instrumento a las pestañas «Recordatorios» ( LONG, SHORT, Range), o bien, eliminarlos de ahí.

También se puede notar que en el comentario para el gráfico ha sido insertada diversa información sobre el instrumento. Y desde luego, se puede notar diferentes líneas horizontales trazadas en el gráfico.

La línea violeta indica en el máximo y mínimo del año.

La línea roja representa el nivel que he trazado antes manualmente. La utilidad puede guardar y recuperar todos los niveles trazados anteriormente en este instrumento.

Como ya ha sido dicho antes en este artículo, la línea de color glauco representa el precio de cierre/apertura del día anteayer. Mientras que la última línea mostrada en la captura de pantalla representa el precio del cierre/apertura del día de ayer.

Los ajustes del grupo Configuraciones de gráficos determinan las líneas y la información a mostrar en el gráfico:

Ajustes del grupo Configuraciones de gráficos

El timeframe y la escala que se usa para visualizar los gráficos también es ejustable. Eso se hace por separado para la pestaña All, pestañas de Recordatorios y para algunas pestañas de filtración automática.

El timeframe para la pestaña All se ajusta en el grupo Mostrar información adicional:

Ajustes del grupo Mostrar información adicional

Por defecto, para todos los botones de los instrumentos en la pestaña All se usa el timeframe D1. Por ejemplo, vamos a cambiarlo por M15:

Gráfico del instrumento con el período 15 minutos

Lo hemos hecho para ver más líneas en el gráfico que la utilidad puede mostrar, ya que estas líneas se muestran sólo en lo períodos de menos de 1 día.

La línea vertical roja muestra la barra del comienzo de la sesión actual, y permite determinar fácilmente de manera visual si el instrumento sube o baja hoy.

La línea horizontal punteada muestra los niveles redondos, es decir, los precios que se terminan en .00 o .50 para las cotizaciones de dos dígitos. O como en nuestro caso, en 0.x1000 o 0.xx500 para las cotizaciones de 4 y 5 dígitos.

Pero volvamos a los ajustes. Las pestañas de la filtración automática también tienen sus ajustes. Los globales se encuentran en el grupo Pestañas adicionales. Además, para algunas pestañas hay grupos separados con los ajustes:

Ajustes de las pestañas de la filtración

Los últimos grupos de ajustes: Abrir gráfico en ventana nueva y Datos externos.

Grupos de ajustes Abrir gráfico en ventana nueva y Datos externos

Los ajustes del grupo Abrir gráfico en ventana nueva afectan el período y la escala de los gráficos que se abren al pulsar el botón New windows.

En suma, eso es todo. La funcionalidad completa de la utilidad ha sido discutida con más detalles en los artículos anteriores de esta serie.


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

Archivos adjuntos |
finder.zip (8456.89 KB)
_finder.ex5 (354.46 KB)
_finder.mq5 (258.68 KB)
_finder.ex4 (230.82 KB)
_finder.mq4 (258.68 KB)
Cómo escribir una biblioteca DLL para MQL5 en 10 minutos (Parte II): Escribiendo en el entorno de Visual Studio 2017 Cómo escribir una biblioteca DLL para MQL5 en 10 minutos (Parte II): Escribiendo en el entorno de Visual Studio 2017

El artículo original «básico» de ningún modo perdió su actualidad, y todos los interesados en este asunto deben leerlo sí o sí. Pero ya pasó bastante tiempo desde aquel entonces, y ahora la versión Visual Studio 2017 es de la actualidad, disponiendo de una interfaz ligeramente modificada, mientras que la propia plataforma MetaTrader 5 tampoco estaba sin desarrollo. El presente artículo describe las etapas de la creación del proyecto DLL, sus configuraciones y el trabajo común con las herramientas del terminal MetaTrader 5.

Estudio de técnicas de análisis de velas (Parte III): Biblioteca para el trabajo con patrones Estudio de técnicas de análisis de velas (Parte III): Biblioteca para el trabajo con patrones

El objetivo de este artículo es crear una herramienta personalizada que nos permita obtener y usar la matriz completa de información sobre los patrones vistos anteriormente. Para ello, desarrollaremos una biblioteca que podremos utilizar en nuestros indicadores, paneles comerciales, expertos, etc.

Web scraping de datos sobre la rentabilidad de los bonos Web scraping de datos sobre la rentabilidad de los bonos

Cuando diseñamos los sistemas del trading automático, casi siempre utilizamos los datos de los indicadores técnicos que analizan el pasado con el fin de predecir el futuro comportamiento del precio. Pero si no tomamos en cuenta las fuerzas fundamentales que mueven el mercado, evidentemente estaremos en una situación menos ventajosa en comparación con los traders que consideran adicionalmente los datos fundamentales en sus decisiones comerciales. Recopilando automáticamente los datos sobre los tipos de interés, Usted podrá mejorar el funcionamiento de su Asesor Experto.

Aplicando OLAP en el trading (parte 1): Fundamentos del análisis corriente de datos multidimensionales Aplicando OLAP en el trading (parte 1): Fundamentos del análisis corriente de datos multidimensionales

En este artículo, se describen los principios básicos de la construcción del framework para el procesamiento analítico en línea (OLAP en inglés), su implementación en MQL en el ambiente de MetaTrader, usando el procesamiento del historial de trading de la cuenta como ejemplo.