Utilitário para seleção e navegação em MQL5 e MQL4: aumentamos a informatividade de gráficos

28 maio 2019, 08:44
Roman Klymenko
0
513

Introdução

Os artigos anteriores (Utilitário de seleção e navegação em MQL5 e MQL4: adição da busca automática de padrões e exibição dos símbolos detectados; Utilitário de seleção e navegação em MQL5 e MQL4: incrementando abas de lembretes e salvando objetos gráficos; Desenvolvimento de um utilitário de navegação e seleção de símbolos em MQL5 e MQL4) já falaram bastante sobre esse assunto. Mas isso ainda não é suficiente para negociações intradiárias de alta qualidade. Hoje, adicionaremos uma nova funcionalidade que permite encontrar pontos de entrada ou pontos de saída de qualidade.

Cada item da nova funcionalidade será descrito numa seção separada do artigo. Primeiro, consideraremos o porquê disso ser necessário. Em seguida, a função ou código que faz isso será mostrado, caso você queira implementar o mesmo em seus projetos.


Ocultar símbolos cuja tendência é diferente da tendência do dia anterior

Parâmetro de entrada: Ocultar se tendência hoje != ontem
Escopo: Configurações de filtragem

Muitos gurus do trading recomendam para a negociação intradiária escolher apenas ações para as quais a tendência de hoje coincide com a tendência de ontem. Simplificando, se o preço das ações subisse ontem, então hoje ele deveria crescer. E, consequentemente, a negociação neste dia só é possível em Long e vice versa.

Para filtrar esses símbolos, é usada a seguinte função:

/*
Retorna true se a tendência hoje não for igual à tendência de ontem.
symname - nome do símbolo para verificação
*/
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 início da sessão

Parâmetro de entrada: Mostrar o começo do dia (em períodos antes do dia)
Escopo:Configurações dos gráficos

O início do pregão é o momento em que os mercados de ações abrem, se estamos falando de ações. Por exemplo, 16:30 para o mercado de ações americano, 10:00 para o europeu e o russo. Se estivermos falando sobre o mercado Forex, tomaremos a meia-noite como o início da sessão de negociação.

Em timeframes pequenos, por exemplo, M5, é imediatamente difícil determinar o início da sessão atual. Por exemplo, para ver rapidamente se uma ação está subindo ou caindo hoje. Portanto, vamos adicionar uma configuração que nos permita ver imediatamente de qual barra começa o dia de negociação atual do instrumento.

Função para exibir o início da sessão:

/*
Exibe o início do dia no gráfico
currChart - id do gráfico
day - número do dia (0 - atual)
*/
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); 
   }
}

No gráfico, isso fica como uma linha vermelha vertical:

Mostrar início da sessão

Talvez alguém note que funcionalidades semelhantes já existem no MetaTrader. Além disso, pode-se ver não apenas o início da última sessão, mas, em geral, o início de cada sessão. Para fazer isso, basta marcar a caixa Mostrar separadores de período nas propriedades do gráfico. Mas, na prática, em alguns casos e em intervalos de tempo separados, essa funcionalidade é redundante e torna o gráfico muito colorido e não é confortável para a leitura. Por exemplo:

Mostrar separadores de período


Exibir Low e High do dia anterior ou do dia antes de ontem

Parâmetro de entrada: Mostra low e high de ontem e Mostrar low e high de antes de ontem
Escopo:Configurações de gráfico

Ao trabalhar no dia, High e Low de ontem e de anteontem são níveis muito populares de suporte e resistência. A situação quando o preço cai, atinge o High de ontem/anteontem e repercute, acontece com muita frequência. De acordo com minhas próprias observações, posso dizer que o preço em 70% ou mais dos casos, desde a primeira vez, não rompe High/Low tanto ontem como anteontem.

Portanto, nunca devemos desprezar esses níveis de suporte e resistência.

Para exibir Low e High do dia selecionado, é usada a seguinte função:

/*
Exibir no gráfico Low e High do dia especificado
currChart - id do gráfico
day - número do dia exibido
*/
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); 
   }
}

No gráfico, Low e High de ontem são exibidos como linhas horizontais claras, enquanto Low e High de anteontem - com linhas cor-de-pântano:

Mostrar Low e High de ontem e de anteontem


Mostrar preços arredondados mais próximos

Parâmetro de entrada: Mostrar preços arredondados mais próximos (período < 1day)
Escopo:Configurações dos gráficos

Os preços arredondados são considerados outros níveis naturais de suporte/resistência. Ou seja, preços de instrumentos que terminam em .00 ou .50. Muitos traders muitas vezes procuram apenas negociações em níveis arredondados semelhantes.

Também os preços, terminando em 0,25 e 0,75, tem uma propriedade semelhantes. Mas eles agem como níveis com uma probabilidade menor, por isso, não os monitoramos, para não atrapalhar o gráfico.

Para exibir preços arredondados, é usada a seguinte função:

/*
Exibir no gráfico 3 níveis arredondados mais próximos do preço atual.
currChart - id do 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;
      }
   }
}

No gráfico, os níveis arredondados são mostrados com linhas horizontais tracejadas:

Mostrar preços arredondados mais próximos


Mostrar encerramento de hora

Parâmetro de entrada: Mostrar encerramento de hora (período < 1hour)
Escopo:Configurações dos gráficos

Continuando o tema dos níveis naturais de suporte/resistência, podemos mencionar os níveis de encerramento da hora. Acredita-se que o preço de fechamento de uma hora também pode ser o nível de suporte/resistência em timeframe menores. Na prática, eu realmente não noto isso. No entanto, vamos implementar um recurso para exibir um modelo semelhante pelo menos nas últimas 4 horas.

A função para destacar encerramento de hora no gráfico:

/*
Mostrar no gráfico o encerramento das últimas 4 horas
currChart - id do 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); 
      
   }
}

No gráfico, o encerramento das últimas 4 horas é exibido como linhas verticais amarelas:

Mostrar encerramento de hora


Mostrar o preço máximo e mínimo do ano

Parâmetro de entrada: Mostrar preço max./min. do ano
Escopo:Configurações dos gráficos

Além disso, entre os traders são populares os preços mais altos e mais baixos do ano. Vamos exibi-los no gráfico.

Para exibir os preços limite para o ano, é usada a seguinte função:

/*
Exibir no gráfico o preço máximo e mínimo do último ano.
currChart - id 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); 
      
      
   }
}

Os preços máximo e mínimo dos últimos 12 meses são exibidos com linhas horizontais roxas:

Mostrar o preço máximo/mínimo do ano


Mostrar spread ao abrir o gráfico

Parâmetro de entrada: Mostrar spread ao abrir o gráfico
Escopo:Configurações dos gráficos

Se você negociar com pequenos stop-loss, o spread atual do instrumento para você é um dos fatores decisivos para entrar no trade. Portanto, é importante saber imediatamente no momento da abertura do gráfico. Aumentemos a informatividade de nossos gráficos.

Só deve ser lembrado que exibimos o spread exatamente no momento de abrir o gráfico. Talvez num momento o spread do gráfico mude. O nível de spread não é exibido em tempo real, ele é usado apenas para estimar o intervalo atual de spreads do instrumento.

O spread retorna a seguinte função pequena:

/*
Retorna uma string com o spread atual para o símbolo especificado.
symname - nome do 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)";
}

O spread é exibido nos comentários do gráfico aberto, entre outras informações adicionais:

Mostrar spread

Aplicar ao gráfico um modelo chamado

Parâmetro de entrada: Aplicar ao gráfico um modelo chamado
Escopo:Configurações dos gráficos

Os modelos no MetaTrader são usados para colocar rapidamente no gráfico configurações preferidas, EA e, mais importante, indicadores usados com seus parâmetros preferidos.

Mas "rápido" é um conceito aberto a interpretações. Para aplicar um modelo a um gráfico, é necessário selecionar no menu de contexto do gráfico o item Modelo/"Nome do Modelo". Mas e se algum indicador for importante para você tomar uma decisão, e você quiser vê-lo em todos os gráficos que abrir. Imagine que você abre centenas de gráficos de vários instrumentos por dia. Então, você deveria clicar em cada um deles?

Seria muito mais fácil se fosse possível aplicar automaticamente um modelo específico com um conjunto de indicadores para cada gráfico aberto. Implementemos esse recurso.

Para aplicar o modelo aos gráficos, basta usar o comando ChartApplyTemplate, que funciona igual em MQL5 e em MQL4:

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


Mostrar ATR segundo método de Gerchik

Parâmetro de entrada: Mostrar ATR segundo método de Gerchik
Escopo:Configurações dos gráficos

ATR, isto é, o movimento médio diário do instrumento durante um certo período é um parâmetro importante na determinação do alcance do instrumento. Ele é usado para propósitos diferentes.

Por exemplo, para decidir se deve entrar no trade durante negociação intraday. Se você espera fazer um movimento de 100 pontos no instrumento e em média o instrumento percorrer 50 pontos por dia, suas chances são pequenas e é melhor se abster do negociar.

Além disso, considera-se que se o instrumento já passou mais de 80% do seu ATR diário numa direção, não faz sentido abrir transações na mesma direção, o que se pode fazer é trabalhar apenas na direção oposta.

ATR segundo o método Gerchik difere do ATR usual apenas em que não são levadas em conta as barras paranormais. Ou seja, barras que são 2 vezes mais que a média ou menor que 0,3 das barras médias.

Normalmente, o ATR é considerado durante 5 ou 3 dias.

A seguinte função é responsável por exibir o ATR de acordo com o método de Gerchik:

/*
Retornar a string com o ATR segundo o método de Gerchik para o símbolo especificado:
symname - nome do 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;
}

Nosso utilitário exibe o ATR nos comentários do gráfico, bem como o spread discutido na seção anterior. O ATR pode ser visto na captura de tela anterior.


Mostramos as direções dos símbolos-guia

Parâmetro de entrada: Exibição da direção do símbolo #N
Escopo:Exibição de informações adicionais

A julgar pelo material já publicado neste artigo, a negociação intradia é uma coisa muito complicada, pois é necessário ter em mente e acompanhar muitas coisas. E, como se constata, isso não é tudo.

Muitos traders recomendam que, antes de negociar, é necessário observar a direção atual dos chamados símbolos guia.

Por exemplo, se você está negociando no mercado de ações dos EUA, é necessário acompanhar:

  • os principais índices dos EUA, pelo menos o Dow Jones ou o SP500;
  • um dos índices dos países restantes: China, Europa, Japão;
  • grandes empresas capitalizadas em diferentes setores do mercado: JPMorgan no setor bancário, Apple em tecnologia, ExxonMobil em energia, IBM e alguns outros.

Também é possível monitorar o estado das cotações do petróleo, ouro, dólar.

É melhor que todos os símbolos-guia sigam numa só direção. Como você provavelmente adivinhou, é melhor negociar apenas na direção em que os símbolos-guia vão.

Como diferentes corretoras têm o instrumento de maneiras diferentes, é impossível especificar programaticamente os instrumentos a serem monitorados. Mas podemos adicionar parâmetros de entrada do tipo string, em que o próprio usuário insere os tickers dos símbolos precisados, como chamados pela corretora. Para esses propósitos, ao utilitário foram adicionados 7 parâmetros.

A direção do símbolo especificado é retornada pela seguinte função:

/*
Devolver uma linha com a direção do preço para o símbolo especificado:
symname - nome do símbolo
show - exibir na string um rótulo com o nome do símbolo
*/
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;
}

As direções são exibidas nos comentários do gráfico no qual está sendo executado o utilitário. Isto tem a seguinte aparência.

Mostramos as direções dos símbolos-guia

Note que a direção do movimento dos símbolos-guia não é atualizada automaticamente. Para atualizar as informações sobre elas, é preciso ir a uma das guias, diferente da que está aberta no momento, ou pressionar a tecla R. No entanto, podemos simplificar isso, usando o novo parâmetro de entrada.


Atualização automática das guias do utilitário

Parâmetro de entrada: Atualizar a guia aberta a cada segundo
Escopo:Exibição de informações adicionais

Se você quiser que o conteúdo da guia aberta no momento seja atualizado automaticamente, e não apenas pressionando a tecla R, basta definir o número de segundos após o qual a atualização deve ocorrer. O valor desse parâmetro maior que 0 informa ao utilitário que, se desde que a guia foi exibida tiver passado mais do que o número especificado de segundos, essa guia deverá ser atualizada. Ou seja, isso não significa que a guia será atualizada estritamente a cada N segundos. Provavelmente, significa que, após aproximadamente N mais um ou dois segundos, ele será atualizado.

O código que implementa essa funcionalidade está localizado dentro da função OnTimer e é muito simples:

   // atualizar o conteúdo da guia em segundos
   if( autoUpdateAfter>0 && TimeCurrent()-lastUpd >= autoUpdateAfter ){
      start_symbols();
      lastUpd=TimeCurrent();
   }

Naturalmente, quando o utilitário arranca, na função OnInit, inicializamos o valor da variável lastUpd com a hora atual.

Mostramos informações financeiras das ações

Parâmetro de entrada: Parâmetro de entrada
Escopo: dados externos

Se você seguir os indicadores fundamentais da empresa antes de comprar ou vender suas ações, provavelmente sonhou que todos esses indicadores fossem exibidos diretamente na janela do MetaTrader, para não ter de navegar por sítios diferentes e olhar os indicadores de cada ação.

Vamos tentar fazer isso acontecer. Para não complicar muito, vamos exibir indicadores na guia Especialistas do terminal, assim que o horário de qualquer ação foi aberto com a ajuda do nosso utilitário.

Os indicadores financeiros em si não serão retirados do teto. No começo, eu queria “costurá-los” diretamente no EA, mas o erro de memória insuficiente não permitia isso. Portanto, todos os indicadores financeiros são armazenados separadamente na pasta finder anexado a este artigo. Para que esta funcionalidade opere, você precisa baixar o arquivo com esta pasta, descompactá-lo e colocar a pasta finder dentro da pasta Files de seu terminal.

Para encontrar a pasta Files em si, na janela MetaTrader, abra o menu Arquivo, e clique no item Abrir catálogo de dados. Depois disso, na janela do Explorador de Arquivos que se abre, vá para a pasta MQL4 ou MQL5.

Esses indicadores financeiros são relevantes no momento de escrita deste artigo, possivelmente, nos próximos meses. Se, no futuro, você precisar de dados relevantes, mande uma mensagem privada.

Mas voltando à nossa função de saída de dados. Esta função faz com que o ticker da empresa seja livrado de coisas desnecessárias que sua corretora pode adicionar a ele, nomeadamente, do prefixo #, bem como dos sufixos .us e .eu, que algumas delas adicionam. Se sua corretora adicionar outra coisa ao ticker, você terá que adicionar ao código do utilitário seus próprios filtros para remover esses símbolos.

Se, segundo o ticker, não foram encontradas as informações necessárias na pasta finder, em seguida, é realizada a pesquisa da empresa por nome.

void printTicker(string ticker, string name){
   bool isYes=false;
   int filehandle;
   
   // limpamos o ticker de sufixos e prefixos desnecessários
   // também o mudamos para minúscula
   StringToLower(ticker);
   StringReplace(ticker, "#", "");
   StringReplace(ticker, ".us", "");
   StringReplace(ticker, ".eu", "");
   
   // convertemos o nome da empresa em minúscula
   StringToLower(name);
   
   ResetLastError(); 
   // se na pasta finder houver informação sobre essa empresa, enviamo-la
   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); 
      }
   }
   
   // caso contrário, escrevemos que a informação não foi encontrada
   if(!isYes){
      Print("Não há dados do símbolo");
   }
}

Como resultado, ao abrir o gráfico de qualquer ação usando esse utilitário, serão exibidas informações sobre esta empresa na guia Especialistas. Isso fica mais ou menso desta forma:

Informações financeiras da empresa


Mostrar lucros de hoje

Parâmetro de entrada: Mostrar lucros de hoje
Escopo:Exibição de informações adicionais

Finalmente, vamos adicionar um indicador ao gráfico que nos permitirá parar durante nosso pregão intradia atempadamente, quer dizer, parar a quantia de lucro ou perda recebida durante o dia, bem como o número total de trades por dia, o número de trades lucrativos e o número de trades não lucrativos (exibidos no gráfico exatamente nesta ordem).

Para MQL4, pode-se obter o lucro atual usando a função do usuário getmetoday_profit(), seu código é apresentado abaixo. Mas para MQL5 esta função não é suficiente.

Em MQL5, primeiro verificamos se é necessário atualizar informações sobre posições fechadas. Para fazer isso, é usada a variável needHistory declarada globalmente. Na função padrão OnInit(), esta variável é configurada como true. Portanto, ao iniciar a função getmetoday_profit() pela primeira vez, há um carregamento de informações sobre trades a partir do histórico. Depois disso, o valor da variável needHistory se torna false.

guida, usamos a função padrão MQL5 OnTrade(), para recarregar o histórico de trades sempre que uma das nossas posições abertas for fechada.

Como resultado, obtemos o seguinte código:

#ifdef __MQL5__ 
   void OnTrade(){
      if(orders_total==PositionsTotal()){
         return;
      }
      if(orders_total>PositionsTotal()){
         needHistory=true;
      }
      orders_total=(ushort) PositionsTotal();
   }
#endif 
/*
Retorna uma string com o tamanho do lucro/perda de hoje.
*/
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;
}

O lucro também é exibido no gráfico em que está sendo executado o utilitário. Fica assim:

Exibindo lucros de hoje

Note que os ganhos diários não são automaticamente recalculados. Para atualizar as informações de lucro atuais, é necessário ir para uma das guias, diferente da que está aberta atualmente, ou pressionar R.


Fim do artigo

Provavelmente, este é o último artigo desta série. Espero que o utilitário resultante seja útil para você.

E se você ainda precisar de alguma funcionalidade, escreva-me sobre isso. Se surgirem mais dúvidas para um novo artigo, o desenvolvimento do utilitário continuará, de certeza.

Em conclusão, ressumamos e revisemos brevemente a funcionalidade que implementamos durante esta série de artigos.

Iniciado o utilitário, aparece uma lista de instrumentos atendendo às nossas condições. Acima dessa lista, podemos ver os botões das guias: All, LONG, SHORT, Range, bem como guias de autofiltragem. Por padrão, a guia All está aberta:

Gráfico com o utilitário em execução

Também nos comentários dos gráficos, podemos ver uma linha que começa com a palavra update. Esta linha exibe a hora da última atualização do conteúdo da guia. Você pode pressionar a tecla R para atualizar a guia atual manualmente. Adicionalmente, nas configurações do utilitário, você pode especificar a frequência em segundos com a qual será atualizado o conteúdo da guia aberta atual.

Falando de configurações do utilitário, será mais fácil entender a funcionalidade do nosso utilitário se considerarmos essas configurações.

A lista de instrumentos exibidos na guia All depende das configurações do grupo Configurações de filtragem:

Grupo de configurações Configurações de filtragem

Se você clicar no botão de qualquer instrumento, exibido pelo utilitário, você verá um gráfico com informações adicionais:

Gráfico do instrumento sendo aberto pelo utilitário

Primeiro, os botões de navegação são evidentes neste gráfico. Com a ajuda deles, você pode alternar instrumentos filtrados pelo utilitário. Além disso, usando esses botões, você pode adicionar/remover instrumentos às/das guias (LONG, SHORT, Range).

Também é possível notar que aos comentários do gráfico são adicionadas várias informações sobre o instrumento. E, claro, você pode ver várias linhas horizontais no gráfico.

A linha roxa indica o máximo ou mínimo do ano.

A linha vermelha é o nível que eu tracei anteriormente manualmente. O utilitário pode salvar e restaurar todos os níveis executados por você anteriormente para esse instrumento.

Como mencionado anteriormente neste artigo, a linha cor-de-pântano é o preço de fechamento/abertura do dia anterior. A última linha mostrada na captura de tela é o preço de fechamento/abertura de ontem.

A linhas e informações a exibir no gráfico do instrumento são determinadas pelas configurações do grupo Configurações de gráfico:

Configurações do grupo Configurações de gráfico

O timeframe e a escala usados também podem ser personalizados. Isso é feito separadamente para a guia All, lembretes, bem como separadamente para algumas guias de autofiltragem.

Timeframe para as guias All é configurado no grupo personalizado Exibição de informações adicionais:

Configurações do grupo Exibição de informações adicionais

Por padrão, para todos os botões de instrumentos na guia All, é usado o timeframe 1 dia. Por exemplo, vamos alterá-lo para 15 minutos:

Gráfico do instrumento com período de 15 minutos

Fizemos isso para ver mais algumas linhas no gráfico que o utilitário pode exibir, já que essas linhas são exibidas apenas em períodos de menos de 1 dia.

A linha vertical vermelha mostra o início da sessão atual na barra e torna fácil determinar visualmente se o instrumento está subindo ou descendo hoje.

Uma linha horizontal quebrada indica níveis arredondados. Ou seja, preços que terminam em .00 e .50 para cotações de dois dígitos. Ou, como no nosso exemplo, em 0.x1000 ou 0.xx500 para os de 4 e 5 dígitos.

Mas de volta às configurações, as guias do filtro automático também possuem suas próprias configurações. Os globais estão localizados no grupo Guias adicionais. Também, para algumas guias, existem grupos separados com configurações:

Configurações da guia filtro automático

Os últimos grupos de configurações: Abrir um gráfico em uma nova janela e Dados externos.

Grupos de configurações Abrir gráfico em uma nova janela e Dados externos

Configurações de grupo Abrir gráfico em uma nova janela afetam o período e a escala dos gráficos que são abertos ao pressionar o botão New windows.

Em suma, isso é tudo. Mais detalhadamente toda a funcionalidade do utilitário é discutida em artigos anteriores desta série.


Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/5614

Arquivos anexados |
finder.zip (8456.89 KB)
_finder.ex5 (354.46 KB)
_finder.mq5 (260.34 KB)
_finder.ex4 (230.82 KB)
_finder.mq4 (260.34 KB)
Visualização do histórico de negociação multimoeda em relatórios em HTML e CSV Visualização do histórico de negociação multimoeda em relatórios em HTML e CSV

Como é sabido, desde seu lançamento, o MetaTrader 5 vem oferecendo testes multimoedas. Essa função é procurada pela maioria dos traders, mas, infelizmente, não é tão universal quanto gostaríamos. O artigo apresenta vários programas para traçar gráficos usando objetos gráficos baseados no histórico de negociação a partir de relatórios nos formatos HTML e CSV. A negociação de vários instrumentos pode ser analisada em paralelo em várias sub-janelas, ou numa só janela usando a comutação dinâmica realizada pelo usuário.

Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte III). Coleção de ordens e posições de mercado, busca e ordenação Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte III). Coleção de ordens e posições de mercado, busca e ordenação

Na primeira parte, começamos a criar uma grande biblioteca multi-plataforma, simplificando o desenvolvimento de programas para as plataformas MetaTrader 5 e MetaTrader 4. Além disso, nós implementamos a coleção do histórico de ordens e negócios. Nosso próximo passo é criar uma classe para uma seleção conveniente e a ordenação de ordens, negócios e posições nas listas de coleção. Nós vamos implementar o objeto da biblioteca base chamada Engine e adicionar uma coleção de ordens e posições de mercado para a biblioteca.

Biblioteca para o desenvolvimento fácil e rápido de programas para a MetaTrader (parte IV): eventos de negociação Biblioteca para o desenvolvimento fácil e rápido de programas para a MetaTrader (parte IV): eventos de negociação

Nos artigos anteriores, nós começamos a criar uma grande biblioteca multi-plataforma, simplificando o desenvolvimento de programas para as plataformas MetaTrader 5 e MetaTrader 4. Nós já temos as coleções do histórico de ordens e negócios, ordens e posições de mercado, bem como a classe para a seleção conveniente e ordenação das ordens. Nesta parte, nós continuaremos com o desenvolvimento do objeto base e ensinaremos a Biblioteca Engine a monitorar os eventos de negociação na conta.

Estudo de técnicas de análise de velas (parte IV): Atualizações e adições ao Pattern Analyzer Estudo de técnicas de análise de velas (parte IV): Atualizações e adições ao Pattern Analyzer

O artigo apresenta uma nova versão do aplicativo Pattern Analyzer. Esta versão fornece correções de bugs e novos recursos, bem como a interface de usuário revisada. Os comentários e sugestões do artigo anterior foram levados em conta no desenvolvimento da nova versão. A aplicação resultante é descrita neste artigo.