English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
MQL5: Crie o seu próprio indicador

MQL5: Crie o seu próprio indicador

MetaTrader 5Exemplos | 4 dezembro 2013, 12:36
17 615 4
MetaQuotes
MetaQuotes

Introdução

O que é um indicador? É um conjunto de valores calculados que deseja-se que sejam exibidos em uma tela de forma conveniente. Os conjuntos de valores são representados em programas como séries. Deste modo, a criação de um indicador significa escrever um algorítimo que manuseia algumas séries (séries de preço) e registra os resultados do manuseamento para outras séries (valores de indicador).

Apesar do fato de que há muitos indicadores prontos, os quais já tornaram-se clássicos, a necessidade de criar os próprios indicadores de alguém sempre existirá. Tais indicadores que criamos utilizando nossos próprios algorítimos chamam-se indicadores personalizados. Neste artigo, discutiremos como criar um indicador personalizado simples.

Os indicadores são diferentes

Um indicador pode ser apresentado como linhas ou áreas coloridas ou pode ser exibido como etiquetas especiais para a posição de entrada. Estes tipos também podem ser combinados, o que fornece ainda mais tipos de indicadores. Consideraremos a criação de um indicador no exemplo bem conhecido True Strength Index desenvolvido por William Blau.

True Strength Index

O indicador TSI é baseado no ímpeto duplamente suavizado de identificar tendências, bem como áreas sobre-vendidas/sobre-compradas. A explicação matemática disto pode ser encontrada em Momentum, Direction, and Divergence por William Blau. Aqui incluímos apenas sua fórmula de cálculo.

TSI(CLOSE,r,s) =100*EMA(EMA(mtm,r),s) / EMA(EMA(|mtm|,r),s)

na qual:

  • mtm = CLOSEatual – CLOSprev, série de valores que denotam a diferença entre os preços de fechamento da barra atual e aquele da barra anterior;
  • EMA(mtm,r) = suavização exponencial de valores mtm com a extensão do período igual a r;
  • EMA(EMA(mtm,r),s) = suavização exponencial de valores EMA (mtm,r) com o período s;
  • |mtm| = valores mtm absolutos;
  • r = 25,
  • s = 13.

A partir desta fórmula, podemos extrair três parâmetros que influenciam o cálculo do indicador. Estes são os períodos r e s, assim como os tipos de preços usados para os cálculos. Em nosso caso, utilizamos o preços de FECHAMENTO.

Assistente do MQL5

Vamos exibir o TSI como uma linha azul - aqui precisamos inicializar o assistente do MQL5. No primeiro estágio, devemos indicar o tipo de um programa que queremos criar - indicador personalizado. Em um segundo estágio, vamos definir o nome do programa, os parâmetros r e s e os seus valores.

Assistente do MQL5: Definindo o nome e o parâmetro do indicador

Depois disso, vamos definir que o indicador deverá ser exibido em uma janela separada como uma linha azul e ajustar a etiqueta to TSI para esta linha.

Assistente do MQL5: ajustando o tipo de indicador

Todos os dados iniciais foram inseridos, então pressionamos Done (concluído) e obtemos um esboço de nosso indicador.

//+------------------------------------------------------------------+
//|                                          True Strength Index.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- mapeamento de buffers do indicador
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }
//+------------------------------------------------------------------+

O assistente do MQL5 cria o cabeçalho do indicador, no qual ele escreve as propriedades do indicador, a saber:

  • o indicador é exibido em uma janela separada;
  • o número de buffers do indicador, indicator_buffers=1;
  • número de tramas, indicator_plots= 1;
  • o nome da trama nº 1, indicator_label1="TSI";
  • estilo da primeira trama - linha, indicator_type1=DESENHAR_LINHA;
  • a cor da trama nº 1, indicator_color1=Azul;
  • estilo de uma linha, indicator_style1=ESTILO_SÓLIDO;
  • largura da linha para a trama 1, indicator_width1=1.

Todas as preparações estão prontas, agora podemos refinar e melhorar o nossos código.

OnCalculate()

A função OnCalculate() é o manipulador do evento Calcular, que aparece quando é necessário calcular novamente os valores do indicador e desenhá-lo novamente no quadro. Este é o evento de um novo recebimento de seleção, atualização de histórico de símbolo, etc. Por isso o código principal de todos os cálculos dos valores do indicador devem estar localizados exatamente nesta função.

É claro, cálculos auxiliares podem ser implementados em outras funções separadas, mas essas funções adicionais devem ser usadas no manipulador OnCalculate.

Por padrão, o assistente do MQL5 cria a segunda forma do OnCalculate(), o qual fornece acesso a todos os tipos de series temporais:

  • Preços aberto, alto, baixo e de fechamento;
  • volumes (real e/ou assinalados);
  • distribuição;
  • tempo de abertura do período.

Mas em nosso caso, precisamos apenas de um array de dados, por isso, vamos alterar a primeira forma de chamar o OnCalculate().

int OnCalculate (const int rates_total,      // size of the price[] array
                 const int prev_calculated,  // número de barras disponíveis na chamada anterior
                 const int begin,            // de onde os dados do price[] começa
                 const double& price[])      // array em que o indicador será calculado
  {
//---
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }  

Isto nos possibilitará aplicar mais adiante o indicador não apenas aos dados de preço, mas também criar um indicador com base em valores de outros indicadores.

Especificando o tipo de dados para o cálculo do indicador personalizado

Se selecionarmos Close na aba de parâmetros (é oferecido por padrão), em seguida o price[] passado ao OnCalculate() conterá os preços de fechamento. Se selecionarmos, por exemplo, Preço Típico, o price[] conterá os preços de (Alto+Baixo+Fechamento)/3 para cada período.

O parâmetro rates_total denota o tamanho da série price[]; será útil para organizar os cálculos em um ciclo. A indexação dos elementos no price[] inicia a partir de zero e é direcionado do passado para o futuro. Por exemplo, o elemento price[0] contém o valor mais antigo, enquanto o price[rates_total-1] contém o elemento da série mais atual.

Organizando buffers de indicador auxiliar

Apenas uma linha será mostrada em um quadro, ou seja, os dados de uma série de indicadores. Mas antes disso, precisamos organizar os cálculos intermediários. Os dados intermediários são armazenados em séries de indicadores que são marcados pelo atributo CÁLCULO DE_INDICADORES . A partir da fórmula vemos que precisamos de séries adicionais:

  1. para valores mtm - série MTMBuffer[];
  2. para valores |mtm| - série AbsMTMBuffer[];
  3. para EMA(mtm,r) - série EMA_MTMBuffer[];
  4. para EMA(EMA(mtm,r),s) - série EMA2_MTMBuffer[];
  5. para EMA(|mtm|,r) - série EMA_AbsMTMBuffer[];
  6. para EMA(EMA(|mtm|,r),s) - série EMA2_AbsMTMBuffer[].

No total precisamos acrescentar 6 séries a mais de tipo duplo em nível global e vincular estas séries com os buffers do indicador na função OnInit(). Não esqueça de indicar o novo número de buffers do indicador; a propriedade do indicator_buffers deve ser igual a 7 (havia 1 e foram adicionados 6 buffers a mais).

#property indicator_buffers 7

Agora o código do indicador se parece com isto:

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_plots   1
//---- plot TSI
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      r=25;
input int      s=13;
//--- indicator buffers
double         TSIBuffer[];
double         MTMBuffer[];
double         AbsMTMBuffer[];
double         EMA_MTMBuffer[];
double         EMA2_MTMBuffer[];
double         EMA_AbsMTMBuffer[];
double         EMA2_AbsMTMBuffer[];
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- mapeamento de buffers do indicador
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,    // size of the price[] array;
                 const int prev_calculated,// número de barras disponíveis;
                                           // na chamada anterior;
                 const int begin,          // de onde os dados  
                                           // do price[] começa;
                 const double& price[])    // array em que o indicador será calculado;
  {
//---
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }

Cálculos intermediários

É muito fácil organizar os cálculos dos valores dos buffers MTMBuffer[] e AbsMTMBuffer[]. No loop, um por um passam por valores a partir do price[1] até o price[rates_total-1] e escrevem a diferença dentro de uma série e o valor absoluto da diferença dentro de um segundo.

//--- calcula os valores de mtm e |mtm|
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

O próximo estágio é o cálculo da média exponencial destas séries. Existem duas maneiras de fazer isto. Na primeira, escrevemos o algoritmo inteiro tentando não cometer erros. No segundo caso, utilizamos funções prontas que já estão depuradas e intencionadas exatamente para estes propósitos.

No MQL5 não há funções integradas para calcular médias móveis dos valores de séries, mas há uma biblioteca pronta de funções (MovingAverages.mqh). O caminho completo para ela é terminal_directory/MQL5/Include/MovingAverages.mqh, no qual o terminal_directory é o lugar no qual o terminal MetaTrader 5 está instalado. A biblioteca está em um arquivo include; ele contém funções para calcular médias móveis em séries que utilizam um dos quatro métodos clássicos:

  • média simples;
  • média exponencial;
  • média suavizada;
  • média ponderada linear.

De modo a utilizar estas funções, em qualquer programa MQL5, acrescente o seguinte no cabeçalho do código:

#include 

Precisamos da função ExponentialMAOnBuffer(), a qual calcula a média móvel suavizada na série de valores e registra os valores da média dentro de outra série.

A função de suavizar uma série

No total, o arquivo include MovingAverages.mqh contém oito funções que podem ser divididas em dois grupos de funções do mesmo tipo, cada uma contendo 4 delas. O primeiro grupo contém funções que recebem uma série e simplesmente retornam um valor de uma média móvel em uma posição especificada:

  • SimpleMA() - para calcular o valor de uma média simples;
  • ExponentialMA() - para calcular o valor de uma média exponencial;
  • SmoothedMA() - para calcular o valor de uma média suavizada;
  • LinearWeightedMA() - para calcular o valor de uma média ponderada linear.

Estas funções são destinada a obter o valor de uma média uma vez para uma série e não estão otimizadas para chamadas múltiplas. Caso necessite utilizar uma função a partir deste grupo em um loop (para calcular valores de uma média e ainda escrever cada valor calculado dentro de uma série), será necessário organizar um algoritmo otimizado.

O segundo grupo de funções é destinado a preencher a série recipiente com valores de uma série móvel com base na série de valores iniciais:

  • SimpleMAOnBuffer() - preenche o buffer[] com valores de uma média simples a partir da série price[];
  • ExponentialMAOnBuffer() - preenche o buffer[] com valores de uma média exponencial a partir da série price[];
  • SmoothedMAOnBuffer() - preenche o buffer[] com valores de uma média suavizada a partir da série price[];
  • LinearWeightedMAOnBuffer() - preenche o buffer[] com valores de uma média ponderada linear a partir da série price[];

Todas as funções especificadas, exceto para buffer[], price[] e o período período de média, obtém 3 ou mais parâmetros, a finalidade dos quais é análoga aos parâmetros da função OnCalculate() - rates_total, prev_calculated e begin. As funções deste grupo processam corretamente séries passadas de price[] e buffer[], levando em consideração a direção de indexação (marcadorAS_SERIES ).

O parâmetro begin indica o índice de uma série de origem, a partir da qual os dados significantes começam, ou seja, dados que precisam ser manipulados. Para a série MTMBuffer[] os dados reais começam com o índice 1, pois o MTMBuffer[1]=price[1]-price[0]. O valor de MTMBuffer[0] é indefinido, por isso begin=1.

//--- primeiro cálculo
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // índice, a partir do qual os dados estão disponíveis para suavizar 
                         r,  // período da média exponencial
                         MTMBuffer,       // buffer para calcular a média
                         EMA_MTMBuffer);  // buffer para colocar a média calculada
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

Ao se fazer uma média, o valor do período deve ser levado em consideração, pois na série de saída os valores calculados são preenchidos com um pequeno atraso, que é maior em períodos de média maiores. Por exemplo, se o período=10, os valores da série resultante começarão com início+período-1=início+10-1. Em chamadas adicionais de buffer[], deve ser levado em consideração, e deve-se iniciar o manuseamento com o índice início+período-1.

Desta forma, é possível obter a segunda média exponencial a partir das séries de MTMBuffer[] e AbsMTMBuffer:

//--- calcula a segunda média móvel
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);

O valor de begin agora é igual a R, porque begin = 1 + r-1 (r é o período da média exponencial primária, tratamento começa com o índice 1). Nas matrizes EMA2_MTMBuffer[] e EMA2_AbsMTMBuffer[], os valores são calculados a partir do índice r + s-1, porque nós começamos a lidar com matrizes de entrada com o índice r, e o período para a segunda média exponencial é igual a s.

Todos os pré-cálculos estão prontos, agora podemos calcular os valores do buffer do indicador, TSIBuffer[], que serão plotados no gráfico.

//--- agora calcular os valores do indicador
   para(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
Compile o código pressionando a tecla F5 e inicie-a no terminal MetaTrader 5. Funciona!

A primeira versão do True Strength Index

Ainda restam algumas perguntas.

Otimizando cálculos

Na verdade, não é suficiente apenas escrever um indicador que funcione. Se olharmos detalhadamente para a implementação atual do OnCalculate(), veremos que não está otimizado.

int OnCalculate (const int rates_total,    // tamanho da série price[];
                 const int prev_calculated,// número de barras disponíveis;
                 // na chamada anterior;
                 const int begin,// e onde os dados 
                 // do price[] começa;
                 const double &price[]) // array em que o indicador será calculado;
  {
//--- calcula os valores de mtm e |mtm|
   MTMBuffer[0]=0.0;
   AbsMTMBuffer[0]=0.0;
   for(int i=1;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }
//--- calcula a primeira média móvel
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,  // índice, a partir do qual os dados estão disponíveis para suavizar 
                         r,  // período da média exponencial
                         MTMBuffer,       // // buffer para calcular a média
                         EMA_MTMBuffer);  // buffer para colocar a média calculada
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         1,r,AbsMTMBuffer,EMA_AbsMTMBuffer);

//--- calcula a segunda média móvel
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_MTMBuffer,EMA2_MTMBuffer);
   ExponentialMAOnBuffer(rates_total,prev_calculated,
                         r,s,EMA_AbsMTMBuffer,EMA2_AbsMTMBuffer);
//--- calcula o valor do indicador
   for(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }

No início de cada função, calculamos valores das séries de MTMBuffer[] e AbsMTMBuffer[]. Neste caso, se o tamanho do price[] for igual a centenas de milhares ou até mesmo milhões, os cálculos repetidos desnecessários podem ocupar todos os recursos da CPU, não importa o quanto ela seja potente.

Para organizar cálculos otimizados, utilizamos o parâmetro de entrada prev_calculated, que é igual ao valor retornado pelo OnCalculate() na chamada anterior. Na primeira chamada de cada função, o valor do prev_calculated é sempre igual a 0. Neste caso, calculamos todos os valores no buffer do indicador. Na próxima chamada não teremos que calcular o buffer inteiro - apenas o último valor será calculado. Vamos escrevê-lo desta forma:

//--- se este é o primeiro cálculo 
   if(prev_calculated==0)
     {
      //--- coloque zero no inicio
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }
//--- calcula os valores de mtm e |mtm|
   int start;
   if(prev_calculated==0) start=1;  // comece a preencher MTMBuffer[] e AbsMTMBuffer[] do índice 1 
   else start=prev_calculated-1;    // define o início igual ao último índice nas matrizes 
   for(int i=start;i<rates_total;i++)
     {
      MTMBuffer[i]=price[i]-price[i-1];
      AbsMTMBuffer[i]=fabs(MTMBuffer[i]);
     }

Os blocos de cálculo de EMA_MTMBuffer[], EMA_AbsMTMBuffer[], EMA2_MTMBuffer[] e EMA2_AbsMTMBuffer[] não requerem otimização de cálculos, pois o ExponentialMAOnBuffer() já está escrito da maneira otimizada. Precisamos otimizar apenas o cálculo dos valores da série TSIBuffer[]. Utilizamos o mesmo método que foi utilizado para o MTMBuffer[].

//--- calcula os valores do indicador
   if(prev_calculated==0) start=r+s-1; // define o início do índice nas matrizes
   for(int i=start;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);

A última observação para o procedimento de otimização: O OnCalculate() retorna o valor do rates_total. Isto significa que o número de elementos na série de entrada price[] é utilizada para o cálculo de indicadores.

O valor retornado pelo OnCalculate() é salvo na memória do terminal e na próxima chamada do OnCalculate() que é passado para a função como o valor do parâmetro de entrada prev_calculated.

Isto possibilita que sempre se saiba o tamanho da série de entrada na chamada anterior do OnCalculate() e iniciar o cálculo dos buffers do indicador a partir de um índice correto sem recálculos desnecessários.

Verificando os dados de entrada

Há mais uma coisa que precisamos fazer para que o OnCalculate() funcione perfeitamente. Vamos acrescentar a verificação da série de price[], na qual os valores do indicador são calculados. Se o tamanho da série (rates_total) for pequeno demais, nenhum cálculo será necessário - precisamos esperar até a próxima chamada do OnCalculate(), quando os dados não forem suficientes.

//--- se o tamanho de price[] é muito pequeno
  if(rates_total<r+s) return(0); // não calcula ou desenha alguma coisa
//--- se esta é a primeira chamada 
   if(prev_calculated==0)
     {
      //--- coloque zero no inicio
      MTMBuffer[0]=0.0;
      AbsMTMBuffer[0]=0.0;
     }

Já que o suavizamento exponencial é utilizado duas vezes sequencialmente para calcular o True Strength Index, o tamanho do price[] deve ser no mínimo igual ou maior do que a soma dos períodos r e s; do contrário, a execução é interrompida e o OnCalculate() retorna 0. O valor zero retornado significa que o indicador não será traçado no quadro, pois seus valores não são calculados.

Configurando a representação

No que diz respeito à exatidão dos cálculos, o indicador está pronto para uso. Mas se o chamarmos a partir de outro programa mql5, ele será constituído, por padrão, de preços de fechamento. Podemos especificar outro tipo de preço padrão - especificar um valor a partir da enumeração ENUM_APPLIED_PRICE na propriedade indicator_applied_price de um indicador.

Por exemplo, a fim de definir um preço típico ( (alto+baixo+fechamento)/3) para um preço, vamos escrever o seguinte:

#property indicator_applied_price PRICE_TYPICAL


Se estivermos planejando utilizar apenas seus valores utilizando as funções iCustom() ou IndicatorCreate() nenhum outro aperfeiçoamento é necessário. Mas se for usado de forma direta, ou seja, traçado no quadro, são recomendados ajustes adicionais:

  • número da barra, iniciando a partir do qual um indicador é traçado;
  • Etiquetas para valores em TSIBuffer[], os quais serão refletidos na DataWindow;
  • nome curto do indicador, mostrado em uma janela separada e no pop-up de ajuda ao apontar o cursor do mouse sobre a linha do indicador;
  • o número de dígitos depois do ponto decimal que é mostrado nos valores do indicador (isto não afeta a precisão).

Estes ajustes podem ser refinados no manipulador OnInit(), utilizando as funções a partir do grupo Custom Indicators . Acrescente novas linhas e salve o indicador como True_Strength_Index_ver2.mq5.

//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- mapeamento de buffers do indicador
   SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);
//--- barra, começando pela qual o indicador é desenhado
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s-1);
   string shortname;
   StringConcatenate(shortname,"TSI(",r,",",s,")");
//--- define um rótulo para exibir em DataWindow
   PlotIndexSetString(0,PLOT_LABEL,shortname);   
//--- define um nome para mostrar em uma sub-janela ou pop-up
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- define a acurácia mostrada nos valores do indicador
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//---
   return(0);
  }

Se iniciarmos ambas versões do indicador e rolar o quadro até o início, veremos todas as diferenças.


A segunda versão do indicador True Strength Index parece melhor

Conclusão

Com base no exemplo de criar o indicador True Strength Index, podemos delinear os momentos básicos no processo de escrever qualquer indicador em MQL5:

  • Para criar o seu próprio indicador customizado, utilize o Assistente de MQL5 que o ajudará a executar as operações de rotina preliminares no ajuste do indicador. Selecione a variável necessária da função OnCalculate().
  • Se for necessário, acrescente mais séries para cálculos intermediários e as vincule com os buffers do indicador necessário utilizando a função SetIndexBuffer() . Indique o tipo do INDICATOR_CALCULATIONS para estes buffers.
  • Otimize os cálculos no OnCalculate(), pois esta função será chamada cada vez que os dados de preço mudarem. Utilize funções já depuradas para tornar a escrita do código mais fácil, e para melhor legibilidade.
  • Execute refinamentos visuais adicionais do indicador para tornar o programa fácil de usar, tanto para outros programas mql5 ou pelos usuários.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/10

Últimos Comentários | Ir para discussão (4)
[Excluído] | 23 dez 2013 em 12:12
Attached source code files and source code insets in HTML code are now completely translated into Portuguese for your convenience.
Léo Muniz
Léo Muniz | 5 jan 2017 em 05:23

No trecho final da função OnCalculate o comando de loop "for" foi traduzido do inglês e está escrito "para", como evidente abaixo. Sugiro consertar para evitar erros com principiantes em programação.  

//--- agora calcular os valores do indicador
   para(int i=r+s-1;i<rates_total;i++)
     {
      TSIBuffer[i]=100*EMA2_MTMBuffer[i]/EMA2_AbsMTMBuffer[i];
     }
Walter Wolseley Pessoa Batista De Lima
Léo Muniz:

No trecho final da função OnCalculate o comando de loop "for" foi traduzido do inglês e está escrito "para", como evidente abaixo. Sugiro consertar para evitar erros com principiantes em programação.  

Ótima observação, Leo =)

moysesnunes
moysesnunes | 14 ago 2021 em 20:56
Como "estudante básico" em criação de robôs, praticamente todos os artigos ou vídeos que assisti, seus autores apresentam a seguinte afirmação:_ Todo indicador possui um handle... 
Considerando  este excelente artigo, que já faz parte de meus textos para estudo, a afirmativa é verdadeira para quais situações? Como criar um handle para este indicador? 
Alguém pode me ajudar?!
Aplicar um indicador a outro Aplicar um indicador a outro
Ao escrever um indicador que usa a forma curta da solicitação da função OnCalculate(), você pode deixar passar o fato de que um indicador pode ser calculado, não apenas pelos dados de preço, mas também pelos dados de algum outro indicador (não importando se for incorporado ou um personalizado). Você quer melhorar um indicador para sua aplicação correta a outros dados do indicador? Vamos analisar neste artigo todas as etapas necessárias para tal modificação.
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Limitações e verificações em Expert Advisors Limitações e verificações em Expert Advisors
É permitido negociar este símbolo na segunda? Há dinheiro suficiente para abrir posição? Qual o tamanho da perda se o Stop Loss acionar? Como limitar o número de ordens pendentes? A operação de negócio foi executada na barra atual ou na anterior? Se um robô de negócio não puder realizar este tipo de verificações, então qualquer estratégia de negócio pode se tornar uma de perda. Este artigo mostra os exemplos de verificações que são úteis em qualquer Expert Advisor.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.