English Русский 中文 Español Deutsch 日本語
Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 1)

Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 1)

MetaTrader 4Exemplos | 22 fevereiro 2016, 14:40
9 897 0
Antoniuk Oleg
Antoniuk Oleg


Introdução

Este é o quarto artigo da série "Linguagem MQL4 para Iniciantes". Hoje aprenderemos a escrever indicadores personalizados. Iremos nos familiarizar com a classificação das características indicadoras, veremos como essas características influenciam o indicador, aprenderemos sobre novas funções e otimização, e, finalmente, escreveremos nossos próprios indicadores. Além disso, no final do artigo você vai encontrará dicas sobre o estilo de programação. Se este é o primeiro artigo "para iniciantes" que você está lendo, talvez seja melhor você ler os anteriores. Além disso, certifique-se que você tenha entendido corretamente o material anterior pois este artigo não explica o básico.


Tipos de Indicadores

Agora vou mostrar-lhe os tipos existentes de indicadores. Certamente você já viu um monte deles, mas agora eu gostaria de chamar sua atenção para as características e parâmetros dos indicadores, portanto, vamos fazer uma pequena classificação de características e parâmetros. Isto irá ajudá-lo a escrever indicadores personalizados. O primeiro indicador:

Este é o indicador Média Móvel, MA, um indicador técnico amplamente utilizado. Preste atenção aos seguintes fatos importantes:

  • o indicador é desenhado na janela do gráfico
  • o indicador mostra apenas um valor
  • a faixa dos valores do indicador é ilimitada e depende dos preços correntes
  • a linha é desenhada com uma certa cor, largura e estilo (linha sólida)

Agora vamos ver um outro indicador:

Faixa Percentual de Williams, (%R). Preste atenção aos seguintes fatos importantes:

  • o indicador é desenhado em uma subjanela separada
  • como no caso anterior, o indicador mostra apenas um valor
  • a faixa dos valores do indicador é estritamente limitada
  • a linha desenhada possui outro estilo, cor e largura.

Assim, existem as seguintes propriedades do indicador:

  • o indicador é desenhado em uma janela do gráfico ou em uma subjanela separada. Agora, vamos tentar entender, porque a Média Móvel é desenhada no gráfico, e a Faixa Percentual de Williams, %R é desenhada em uma janela separada. A diferença está na faixa dos valores exibidos. Note que o segundo indicador apresenta valores na faixa de 0 a -100. Agora imagine que mostramos esses valores em uma janela do gráfico. O que aconteceria? Você não iria ver esta linha porque o preço tem uma faixa muito mais estreita. No nosso caso, é a partir de 0,6805 a 0,7495. Mas isto não é tudo. Na verdade, os preços são números positivos e o nosso valor é negativo. Os indicadores são desenhados em uma subjanela separada se seus valores estiverem fora da faixa de preço do gráfico ativo. E se o intervalo a faixa for quase a mesma (por exemplo, diferentes tipos de médias móveis), um indicador é desenhado em uma janela do gráfico. Futuramente, defina este parâmetro indicador de acordo com esta simples lógica. Aqui está uma imagem:
  • um indicador de que é desenhado em uma subjanela separada pode ser limitado a uma faixa rigorosa. Isso significa que o terminal define uma escala fixa para mostrar valores do indicador; e mesmo que os valores excedam a faixa, você não irá vê-los. Se você desativar este parâmetro, o terminal irá automaticamente alterar a escala para que ela possua todos os valores de um indicador. Veja a imagem:

  • um indicador pode mostrar seus valores utilizando diferentes cores, estilos e largura. Você já viu isto muitas vezes ao configurar o desenho de indicadores no terminal. Aqui está uma restrição: se você usar uma largura de linha maior que 1, você pode usar apenas um estilo - linha sólida.

Mais um indicador:



Como você pode ver, o indicador Volumes é desenhado na forma de um histograma. Então, há muitos tipos de exibição dos valores do indicador. Aqui está um exemplo de outro tipo:



O indicador Fractais é desenhado na forma de símbolosespeciais. Agora, veja o indicador a seguir:



Este é o indicador Alligator. Observe que o indicador desenha simultaneamente três valores (linhas de balanço). Como isso funciona? Na verdade, qualquer indicador (há algumas exceções, mas vamos falar sobre eles mais tarde) usa buffers de dados ao exibir valores.

Buffer de dados é quase uma matriz simples. A sua peculiaridade está no fato de que esta matriz é parcialmente controlada pelo terminal. O terminal muda a matriz de modo que no recebimento de cada nova barra ocorra uma mudança. Isto é feito com a finalidade de que cada elemento da matriz corresponda a uma determinada barra. O número máximo de buffers de dados mostrados em um indicador é 8. Pode parecer estranho agora, mas em breve você vai entender que não poderia ser de outra forma. Basta lembrar que há um buffer de dados separado para cada linha no Alligator. Cada buffer de dados tem seus próprios parâmetros de acordo com qual terminal os desenha. No nosso caso, existem 3 buffers que podem ser descritos da seguinte forma:

  1. O primeiro buffer é desenhado por uma linha verde sólida com largura 3.
  2. O segundo buffer é desenhado por uma linha tracejada de cor vermelha e largura 1.
  3. O terceiro buffer é desenhado por uma linha azul sólida com largura 2.

Não é necessário para um indicador desenhar um buffer. Ele pode ser usado para os cálculos intermediários. É por isso que o número de buffers pode ser maior do que você vê. Mas a propriedade mais importante do buffer de dados é que cada elemento de buffer deve corresponder a uma certa barra de um gráfico. Lembre-se disto. Logo você verá como isso funciona em um código.

Agora vamos tirar uma conclusão da nossa pequena excursão. Qualquer indicador possui os seguintes parâmetros:

  • um ou mais buffers de dados (embora não necessariamente) para mostrar os seus valores ou para cálculos intermediários. Cada buffer, por sua vez, possui seus próprios parâmetros que definem como ele será desenhado e se ele será desenhado. Por exemplo: desenhar o valor sob a forma de um histograma, símbolo ou linha; qual cor e estilo;
  • Onde o indicador deve ser desenhado ( em uma janela do gráfico ou em uma subjanela separada);
  • Se o indicador é desenhado em uma subjanela, devemos limitar a faixa ou automatizar o dimensionamento.

Certifique-se de entender claramente todos estes parâmetros. Agora vamos usar um Wizard para criar um indicador personalizado.


Criação do indicador personalizado

Inicie o MetaEditor, selecione Arquivo->Novo:



Depois, vemos uma janela Expert Advisor Wizard, selecione Indicador Personalizado, clique Próximo:



Preencha os campos Nome, Autor e Link. Tudo aqui é como de costume, mas agora você pode adicionar parâmetros. O que é isso?

Parâmetros são variáveis comuns que podem ser definidas pelo usuário. O importante é que estas variáveis podem ser utilizadas em um código indicador. A aplicação de parâmetros é óbvia - você permite que os usuários configurem alguns aspectos da operação do indicador. Pode ser qualquer coisa que você desejar. Por exemplo, o calendário para utilização, modo de operação, número de barras para uma média etc.

Como exemplo, vamos tentar adicionar um parâmetro que irá mostrar o número de barras processadas para o cálculo dos valores do indicador. Onde isto pode ser usado? Imagine que o seu indicador sobrecarrega seu processador por causa de muitos cálculos. E muitas vezes você muda o calendário do gráfico e visualiza apenas as últimos 100-200 barras. Então você não precisa de outros cálculos que desperdiçam tempo. Este parâmetro irá ajudá-lo em tal situação. Claro, não haverá nada difícil em nosso indicador que possa desperdiçar os recursos do computador. Esta é apenas uma variante do uso dos parâmetros dos indicadores.

Para adicionar um parâmetro clique Add (1). Depois disso, você pode mudar o nome da variável (2). No nosso caso, substituímos por barsToProcess. Você também pode alterar o valor inicial (3), ou seja, o valor padrão. Altere-o para 100. Além disso, você pode alterar o tipo de variável, mas no nosso caso, não precisamos mudar nada porque o tipo int se adapta perfeitamente aos nossos propósitos. Depois que todas as mudanças necessárias forem feitas, clique Próximo:



Está quase pronto. Agora indique como o indicador deve ser desenhado: em uma janela separada ou em uma janela do gráfico. Você também pode limitar a faixa. Verifique o Indicador em uma janela separada. Abaixo está um campo vazio Índices (buffers de dados). Aqui você pode adicionar o número necessário de buffers de dados (no máximo 8). Além disso, você sempre pode adicionar ou excluir um buffer depois, alterando o código. Clique Add para adicionar o buffer. Agora você pode alterar a maneira como o buffer será desenhado: linha, histograma, seção, seta. Nós não iremos mudar nada, então nosso tipo será Linha. Ajuste a cor e clique OK.

Finalmente, seu primeiro indicador está pronto! Bem, ele não desenha nada, mas é um código! O arquivo com o código fonte está na pasta com os indicadores: MetaTrader4\experts\indicadores.


Vamos analisar cada linha

Agora vamos ver o que o Meta Editor criou:

//+------------------------------------------------------------------+
//|                                             myFirstIndicator.mq4 |
//|                                                     Antonuk Oleg |
//|                                                   banderass@i.ua |
//+------------------------------------------------------------------+

Como de costume, o título consiste em uma linha de comentários que inclui as informações que você escreveu anteriormente. Próximo:

#property copyright "Antonuk Oleg"

Você ainda lembra do pré-processador diretivo #define do segundo artigo? Nós o usamos para declarar constantes. Então, aqui está mais uma diretiva usada para denotar propriedades específicas de um indicador. No nosso caso, é usado para indicar autoria. Por favor, observe que começa com o sinal especial #, em seguida, vai para propriedade da palavra-chave (sem espaço). Em seguida, vem uma propriedade concreta que queremos definir, no nosso caso são os direitos autorais, e o valor desta propriedade. No nosso caso, é uma linha com seu nome. Usando a diretiva #property você pode configurar muitos aspectos específicos do indicador. Você verá isto agora. Todas estas propriedades serão configuradas por padrão. Vamos continuar:

#property link      "banderass@i.ua"

Esta diretiva mostra como contatar o autor. Você pode perguntar onde estão essas informações (nome e informações de contato do autor) pois elas não são mostradas em lugar algum. Mas estão incluídas no arquivo executável. E se você ver o arquivo executável como um texto comum, você verá esta informação:

Próximo:

#property indicator_separate_window

Esta diretiva mostra que o indicador deve ser desenhado em uma subjanela separada. Como você pode ver, não há parâmetros adicionais tão distintos como da diretiva anterior.

#property indicator_buffers 1

Esta diretiva indica quantos buffers de dados serão utilizados pelo indicador. Você deve ter notado que as diretivas são, de alguma forma, semelhantes às funções mais comuns: elas também aceitam alguns parâmetros e fazem algo em resposta. Mas há uma diferença importante: elas são executadas em primeira instância (antes da compilação).

#property indicator_color1 DarkOrchid

Indique a cor padrão para o primeiro buffer. Observe que a numeração do buffer inicia de ume não a partir de zero. Tente lembrar-se para que você não confunda no futuro. A cor é indicada através de um de muitos nomes predeterminados. Você pode ver as palavras-chave para todas as cores disponíveis na ajuda: Referência MQL4 -> Padrões Constantes -> Cores-Web. Da mesma forma você pode indicar a cor para outros buffers, basta alterar o número de buffer.

extern int       barsToProcess=100;

Este é nosso parâmetro do indicador. Nós o configuramos no Wizard. Observe que a única diferença de uma variável comum é a palavra-chave externa antes do tipo de variável. Assim que o parâmetro se parecerá para um usuário no indicador start:



Próximo:

double ExtMapBuffer1[];

Esta é uma matriz usual. Mas a dimensionalidade não é indicada e a inicialização não é realizada. Esta matriz, mais tarde, será configurada como um buffer de dados.

Em seguida, declaramos e descrevemos as funções. Diferente de um script usual, cada indicador tem 3 funções e não 1:

  • init() - esta função é chamada pelo terminal apenas uma vez quando inicializamos o indicador. Sua finalidade é preparar o indicador para a operação, configurar os buffers de dados, verificar os parâmetros (escritos por um usuário) e outras ações preparatórias. Esta função não é obrigatória. Se você não executar um código nela, você pode excluí-la.
  • deinit() - Esta função também é chamada apenas uma vez quando você exclui um indicador de um gráfico. Você deve preparar o indicador para o término de seu funcionamento. Por exemplo, feche os arquivos abertos, apague objetos gráficos a partir do arquivo (não se preocupe, você aprenderá como fazê-lo). Esta função também não é obrigatória.
  • start() - diferente dos scripts, nos indicadores esta função é chamada em cada crédito. Isto é, quando novas citações aparecem a partir do par de moedas para o gráfico que você tiver anexado o indicador, esta função é chamada. Além disso, esta função é chamada no início do indicador, ou seja, após a função init().

Vamos ver o que acontece em cada função:

int init()
{
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer1);
 
   return(0);
}

Aqui vemos a chamada de duas funções importantes para a configuração de um buffer de dados:

SetIndexStyle(0,DRAW_LINE);

Esta função define como desenharo buffer de dados. O primeiro parâmetro indica, para qual buffer a mudança deve ser aplicada. Por favor, observe que nesta função (e funções semelhantes) a numeração do buffer começa do zero e não a partir do número um como nas diretivas. Este é um momento importante, tenha cuidado. O segundo parâmetro indica, como desenhar o buffer escolhido. No nosso caso, usamos a constante DRAW_LINEque mostra que o buffer será desenhado como uma linha. Claro, existem outras constantes, mas vamos falar sobre elas mais tarde.

SetIndexBuffer(0,ExtMapBuffer1);

Esta função "liga" uma matriz em um número de buffer. Isto é, mostra que o buffer com o número indicado utilizará a matriz indicada para o armazenamento de dados. Assim, alterando os elementos dessa matriz você mudará o valor do buffer. Na verdade, uma matriz é um buffer de dados. O primeiro argumento é o nome da matriz que deve ser vinculada.

return(0);

Final da função, retornar zero - a inicialização foi bem sucedida.

int deinit()
{
//----
   
//----
   return(0);
}

A função de deinicialização está vazia por padrão.

int start()
{
   int counted_bars=IndicatorCounted();
//----
   
//----
   return(0);
}

Agora vem a função mais importante - o código principal está localizado aqui. Atenção: a variável counted_bars é declarada de antemão e inicializada pela função IndicatorCounted(). Esta variável é geralmente utilizada para a otimização e aceleração da operação do indicador, isto será analisado mais tarde. E agora vamos desenhar algo na janela do indicador.



Finalização do Indicador

Vamos decidir o que deve ser exibido. O que o indicador irá nos mostrar? Algo simples. Primeiro, vamos desenhar números aleatórios. Por que não? Isso garante 50% dos sinais de lucro.

Vamos escrever na nossa função init() um código para a inicialização do gerador de números aleatórios:

int init()
{
 
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer1);
 
   // initialization of the generator of random numbers
   MathSrand(TimeLocal());
 
   return(0);
}

A inicialização está pronto, agora vem a função start():

int start()
{
   int counted_bars=IndicatorCounted();
 
   for(int i=0;i<Bars;i++)
   {
      ExtMapBuffer1[i]=MathRand()%1001;
   }
   
   return(0);
}

Compilar - F7. Inicie o terminal, encontre o painel de Navegação, selecione a seção Indicadores Personalizados e clique duas vezes no nome do nosso indicador:

O indicador será anexado ao gráfico ativo:

Você vê, tudo funciona. Agora vamos ver o que o código faz:

for(int i=0;i<Bars;i++)

Nós usamos o ciclo para passar por todos os elementos do buffer de dados. Como uma determinada barra corresponde a cada elemento do buffer, usamos o ciclo a partir da barra de zero (o último disponível) e terminamos com o primeiro disponível, que é em sucessão de um a menos do que as barras variáveis (porque contamos as barras a partir de zero).

{
   ExtMapBuffer1[i]=MathRand()%1001;
}

Em cada iteração um contador é incrementado, e passamos da última barra disponível para a primeira ao mesmo tempo atribuindo a cada elemento de buffer (que corresponde a uma determinada barra) um número aleatório de 0 a 1000. Se for difícil de entender como um determinado elemento corresponde a um certa barra, tente mudar o ciclo da seguinte maneira e veja o resultado no terminal:

for(int i=0;i<Bars;i++)
{
   ExtMapBuffer1[i]=i;
}

Agora o indicador exibirá o número de cada barra, veja:



Você vê, o número de barras aumenta da última barra para o primeira. Espero que agora você entenda a correspondência dos elementos de buffer de barras no gráfico.

Agora vamos voltar para o código do indicador "aleatório". Se você o utilizou pelo menos alguns minutos, você verá que cada crédito do indicador desenha um gráfico absolutamente diferente. Isto é, cada crédito faz recálculos do que foi calculado anteriormente. Isto é inconveniente para nós porque não podemos ver o que aconteceu um crédito atrás. Mas isso não importa porque ninguém vai usar tal indicador - estamos simplesmente aprendendo a escrevê-lo. Há mais uma coisa. Imagine, seu indicador faz um monte de cálculos complexos e o cálculo de uma barra requer grandes recursos do processador. Nesse caso, se um novo preço aparece, seu indicador calculará o valor de cada barra disponível, mesmo que isso tenha sido feito anteriormente. Isto está claro? Em vez de calcular apenas uma vez, ele irá calcular de novo e de novo. A eliminação destes problemas relacionados com o desperdício irracional de recursos é chamada de otimização.

Como podemos resolver este problema? Geralmente, isto é feito da seguinte forma: Primeiro, um indicador é calculado em todos os castiçais disponíveis, e só então, quando as cotações forem recebidas, ele vai recalcular o valor apenas do último castiçal. Isso é razoável - não há ações desnecessárias. Agora, vamos otimizar a função start(), isto vai funcionar da seguinte forma:

int start()
{
   int counted_bars=IndicatorCounted(),
       limit;
 
   if(counted_bars>0)
      counted_bars--;
   
   limit=Bars-counted_bars;
  
   for(int i=0;i<limit;i++)
   {
      ExtMapBuffer1[i]=MathRand()%1001;
   }
   
   return(0);
}

Vamos analisar cada linha:

int counted_bars=IndicatorCounted(),

Nós declaramos a variável counted_bars que irá armazenar o número de barras calculado por um indicador. Na verdade, a função IndicatorCounted() retorna o número de barras inalteradas após a chamada anterior da função start(). Então, se for a primeira chamada da função start(), IndicatorBars() irão retornar 0porque todas as barras são novas para nós. Se não for a primeira chamada, a mudança é apenas na última barra, então as IndicatorBars() irão retornar um número igual as Barras-1.

limit;

Aqui está mais uma variável que vai ser utilizada como um limitador, ou seja, ajudará que o ciclo seja completado mais rapidamente, omitindo castiçais já calculados.

  if(counted_bars>0)
      counted_bars--;

Como já foi dito, se o IndicatorCounted() retorna 0, a função start() é chamado pela primeira vez e todas as barras são "novas" para nós (o indicador não foi calculado para elas). Mas se não for a primeira chamada do start(), o valor igual a Barras-1 será devolvido. Portanto, esta condição rastreia tal situação. Depois disso, diminuímos 1 das variáveis counted_bars. Apenas a última barra pode ser alterada, então por que fazemos isso? O fato é que existem algumas situações em que o último crédito da barra anterior permanece não processado porque quando o último crédito veio, o penúltimo crédito foi processado. E o indicador personalizado não foi chamado e não foi calculado. É por isso que diminuímos 1 das variáveis counted_bars para eliminar esta situação.

limit=Bars-counted_bars;

Aqui vamos atribuir ao limite da variável (o limitador) o número das últimos barras que precisam ser recalculadas. Enquanto a variável counted_bars armazena o número de castiçais já calculados, nós simplesmente encontramos a diferença entre as Barras (o número total de barras disponíveis) e counted_bars para definir quantos castiçais devem ser calculados.

for(int i=0;i<limit;i++)
{
   ExtMapBuffer1[i]=MathRand()%1001;
}

O ciclo quase não sofreu alteração. Apenas mudamos a condição de implementação. Agora, o ciclo irá será executado enquanto o contador for menor que o limite.

Agora a otimização está concluída. Se você observar a versão atualizada do indicador, você verá que quando um novo crédito for recebido, apenas o valor só das últimas barras sofrem alterações. Tente usar esta otimização constantemente, mesmo que seu indicador não calcule nada difícil. Isto é chique.

Você se lembra de um parâmetro do indicador barsToProcess que nós adicionamos no Wizard? Agora é a hora de utilizá-lo. Nós simplesmente precisamos adicionar um par de linhas antes do ciclo:

int start()
{
   int counted_bars=IndicatorCounted(),
       limit;
 
   if(counted_bars>0)
      counted_bars--;
   
   limit=Bars-counted_bars;
   
   if(limit>barsToProcess)
      limit=barsToProcess;
  
   for(int i=0;i<limit;i++)
   {
      ExtMapBuffer1[i]=MathRand()%1001;
   }
   
   return(0);
}

Como podemos ver, é tudo muito simples. Verificamos se o limite é maior que as barsToProcess. Se sim, diminua o limitador através da atribuição. Como resultado, se estabelecermos barsToProcess=100, você vai ver uma imagem parecida com esta:

Como você pode ver, apenas o número de barras ajustadas por nós é calculado.

Nosso indicador está quase pronto. Mas nós não temos sinais claros para entrar no mercado. Sendo assim, precisamos adicionar mais certeza. Para este propósito nós usaremos os níveis.

OsNíveis são linhas horizontais desenhadas pelo indicador utilizando um certo estilo, cor e largura. Devemos observar que o número máximo de níveis em uma barra é 8. Além disso, você pode definir os níveis usando diretivas ou funções. Se você desejar definir os níveis por padrão, é preferível utilizar a primeira variante. Para alteração dinâmica dos níveis durante o funcionamento do indicador utilize as funções. Por isso, vamos definir dois níveis: o primeiro sobre o ponto 800, o segundo - 200. Para este efeito, vamos adicionar várias diretivas no início do código indicador:

//+------------------------------------------------------------------+
//|                                             myFirstIndicator.mq4 |
//|                                                     Antonuk Oleg |
//|                                                   banderass@i.ua |
//+------------------------------------------------------------------+
#property copyright "Antonuk Oleg"
#property link      "banderass@i.ua"
 
#property indicator_level1 800.0
#property indicator_level2 200.0
#property indicator_levelcolor LimeGreen
#property indicator_levelwidth 2
#property indicator_levelstyle 0
 
#property indicator_separate_window

Vamos analisar as novas diretivas:

#property indicator_level1 800.0

Esta diretiva mostra que o nível 1 deve ser colocado no ponto 800,0. Preste atenção que a numeração do buffer inicia com 1, como nas diretivas de configuração do buffer. Para configurar outro nível, basta alterar o número do nível no final de uma diretiva:

#property indicator_level2 200.0

Há uma limitação importante na configuração da forma exterior dos níveis. Você não pode configurar cada nível individualmente. Todas as configurações são aplicadas absolutamente à todos os níveis. Se você precisar configurar cada nível individualmente, você deve usar objetos (e não usar níveis de maneira alguma) que serão descritos no próximo artigo.

#property indicator_levelcolor LimeGreen

Esta diretiva define a corque será usada para desenhar todos os níveis.

#property indicator_levelwidth 2

Esta diretiva define a largura para desenhar as linhas de todos os níveis. Você pode definir a largura de 1 a 5. Não se esqueça que se a largura for superior a 1, os níveis serão desenhados em uma linha sólida. Se você precisar de um outro estilo de desenho de níveis, utilize apenas a largura 1.

#property indicator_levelstyle STYLE_SOLID

Esta diretiva define o estilo das linhas desenhadas. Existem as seguintes constantes predefinidas:

  • STYLE_SOLID - linha sólida
  • STYLE_DASH - linha tracejada
  • STYLE_DOT - linha pontilhada
  • STYLE_DASHDOT - linha pontilhada-tracejada
  • STYLE_DASHDOTDOT - linha pontilhada-tracejada com pontos duplos


Terminamos o desenvolvimento do nosso indicador "aleatório". Agora vamos salvar o arquivo de origem com um nome mais apropriado - randomIndicator.mq4. Recompile o arquivo de origem mais uma vez. Este indicador também será usado na parte seguinte. A versão final deve ficar assim:



Função iCustom

Agora vamos tratar sobre uma função muito útil - iCustom. Ela é usada para obter valores de qualquer indicador personalizado. Lembre-se que para os indicadores integrados, usamos funções para trabalhar com indicadores técnicos descritos no artigo anterior (por exemplo: iADX(), iMACD etc.). Para todos os outros indicadores (indicadores personalizados) utilize a função iCustom. Esta função é universal e pode ser aplicada a qualquer indicador personalizado que atenda os seguintes requisitos:

  • o indicador está compilado e está sob a forma de um arquivo executável (*.ex4)
  • o indicador está na pasta MetaTrader 4\experts\indicadores

O protótipo da função possui a seguinte forma:

double iCustom( string symbol, int timeframe, string name, ..., int mode, int shift);

Parâmetros:

  • símbolo – define qual segurança financeira (par de moeda) deve ser utilizada para o cálculo de um indicador de valores personalizados. Use NULO (ou 0), se você precisar da segurança (gráfico) atual (ativa).
  • calendário – define em qual calendário (período de tempo) o indicador deve ser utilizado. Use 0 para o período atual ou uma das constantes (PERÍODO_M1, PERÍODO_M5, PERÍODO_M15, PERÍODO_M30, PERÍODO_H1, PERÍODO_H4, PERÍODO_D1, PERÍODO_W1, PERÍODO_MN1).
  • nome – o nome do arquivo executável do indicador personalizado. Apenas o nome deve ser indicado: não escreva a extensão (.ex4) ou o caminho para o arquivo (experts/indicadores/). Por exemplo, se o nome do arquivo executável do indicador personalizado for "RandomIndicator.ex4", você deve escrever "RandomIndicator". O registo aqui não é relevante. Isso significa que você pode escrever "RANDOMindicator e irá funcionar.
  • ... - Aqui você deve indicar todos os valores dos parâmetros dos indicadores personalizados. Por exemplo, no nosso indicador RandomIndicator há apenas um parâmetro - barsToProcess. Isto é, no nosso caso, escrevemos aqui 100 (ou qualquer outro valor adequado). Se o número de parâmetros for maior que um, eles serão indicados na mesma sucessão que eles são declarados no indicador personalizado, separados por vírgulas. Agora tentaremos escrever um indicador baseado nessa função e você entenderá melhor.
  • modo – o modo de operação de um indicador personalizado. Na verdade, o valor que você deseja obter,é o número do buffer de dados. A numeração começa a partir de zero (diferente das diretivas). Se o indicador personalizado tiver apenas um buffer de dados, este parâmetro deve ser igual a 0.
  • deslocamento – define para qual barra o indicador personalizado deve ser utilizado.

Exemplos de uso:

ExtMapBuffer[0]=iCustom(NULL,PERIOD_H1,"Momentum",14,0,0);
 
// assign to the first element of the array ExtMapBuffer the value of the custom 
// indicator Momentum on the last available bar. We use here the active 
// security on hour chart. The name of the executable file: Momentum. 
// This indicator has only one parameter - period. In our case the period 
// is equal to 14. This indicator has only one data buffer, so we use zero, 
// in order to get access to its values.
double signalLast=iCustom("EURUSD",PERIOD_D1,"MACD",12,26,9,1,0);
 
// declare a new variable signalLast and assign to it the value of the custom 
// indicator индикатора MACD on the last available bar. We use the pair EURUSD on 
// a daily chart. The name of the executable file: MACD. This indicator has 3 parameters: 
// period for quick average, period for slow average and period for a signal line. 
// This indicator also has 2 data buffers. The first one is with values of the main line. The second one 
// with values of a signal line. In our case we take the value of the signal line.

Indicador de sinal

Agora vamos escrever mais um indicador simples. Imagine a seguinte situação. Você escreveu um indicador bastante complexo com muitos buffers de dados. Muitos deles são exibidos em uma janela separada, outros são usados para cálculos intermediários. Você sabe exatamente os sinais de compra e venda. Mas a dificuldade é que é muito difícil de rastrear os sinais. Você precisa olhar constantemente em seu monitor, tentando encontrar linhas cruzadas, que são níveis acima ou abaixo delas. É por isso que você decide escrever mais um indicador que poderia fazer isto para você e só iria lhe mostrar os sinais de entrada. Por exemplo, estas poderiam ser setas indicando em que direção você deve abrir posições. Esta é apenas uma fantasia mostrando onde um indicador de sinal seria apropriado. A nossa situação é muito mais fácil, mas ainda é semelhante à primeira.

Vamos escrever um indicador de sinal com base no indicador anterior RandomIndicator. Primeiro, precisamos definir as condições de entrada - aqui precisaremos dos nossos níveis. As condições serão as seguintes:

  • se uma linha mover-se acima do nível superior (800,0), compre
  • se uma linha mover-se abaixo do nível superior (200,0), venda

Agora é a hora de escrever um novo indicador. Utilize o Expert Advisor Wizard para criar um novo indicador personalizado. Como no caso anterior, adicione um parâmetro adicional:

E a última etapa (Desenho de propriedades do programa do indicador Personalizado) deve ser a seguinte:



Primeiro adicione dois buffers de dados que serão usados para desenhar sinais de compra e venda na forma de setas. Altere o tipo de buffers de dados em Seta. Altere os códigos das cores e dos símbolos. Abaixo estão todos os códigos de símbolos disponíveis:

Nós não precisamos desenhar o indicador em uma janela separada porque nós estamos indo desenhar os sinais na janela do gráfico.

Nós usamos dois buffers de dados porque não podemos desenhar setas diferentes (símbolos) usando apenas um buffer. Cada buffer de dados apresentado na forma de um símbolo pode ser desenhado apenas por um símbolo. Agora vamos analisar com muita atenção o código de inicialização do indicador:

int init()
{
//---- indicators
   SetIndexStyle(0,DRAW_ARROW);
   SetIndexArrow(0,236);
   SetIndexBuffer(0,ExtMapBuffer1);
   SetIndexEmptyValue(0,0.0);
   SetIndexStyle(1,DRAW_ARROW);
   SetIndexArrow(1,238);
   SetIndexBuffer(1,ExtMapBuffer2);
   SetIndexEmptyValue(1,0.0);
//----
   return(0);
}

Preste atenção que agora a outra constante para o tipo de buffer de dado é utilizada - DRAW_ARROW:

SetIndexStyle(0,DRAW_ARROW);

Vemos também duas novas funções que são usadas para configurar o desenho do símbolo. SetIndexArrow é usada para definir o símbolo que representará um buffer. O primeiro argumento é o número de buffer, o segundo é o código de símbolo que irá representar o indicador:

SetIndexArrow(0,236);

SetIndexEmptyValue é utilizado para indicar um valor "vazio". Significa que indicam o valor em que não é preciso desenhar nada. No nosso caso isto é muito conveniente porque os sinais não são gerados em cada barra. Ele funciona da seguinte maneira: quando não precisamos desenhar uma matriz na barra atual, você atribui ao elemento correspondente do buffer de dados um valor de "vazio", no nosso caso, é 0. O primeiro argumento da função é o número do buffer de dados. O segundo é o valor "vazio":

SetIndexEmptyValue(0,0.0);

O código de inicialização restante define buffers análogos ao indicador "aleatório'' que analisamos anteriormente. Agora vamos terminar o código na função start():

int start()
{
   int counted_bars=IndicatorCounted(),
       limit;
 
   if(counted_bars>0)
      counted_bars--;
   
   limit=Bars-counted_bars;
   
   if(limit>barsToProcess)
      limit=barsToProcess;
  
   for(int i=0;i<limit;i++)
   {
      double randomValue=iCustom(NULL,0,"RandomIndicator",barsToProcess,0,i);
      
      if(randomValue>800.0)
         ExtMapBuffer1[i]=High[i]+5*Point;
      else
         ExtMapBuffer1[i]=0.0;
         
      if(randomValue<200.0)
         ExtMapBuffer2[i]=Low[i]-5*Point;         
      else
         ExtMapBuffer2[i]=0.0;         
   }
   
   return(0);
}

Todo o código até que o ciclo seja repetido desde o indicador "aleatório". Na verdade, este código é padrão em qualquer indicador e é repetido com pequenas alterações. Agora vamos analisar o ciclo em detalhes:

   for(int i=0;i<limit;i++)
   {
      double randomValue=iCustom(NULL,0,"RandomIndicator",barsToProcess,0,i);
      
      if(randomValue>800.0)
         ExtMapBuffer1[i]=High[i]+5*Point;
      else
         ExtMapBuffer1[i]=0.0;
         
      if(randomValue<200.0)
         ExtMapBuffer2[i]=Low[i]-5*Point;         
      else
         ExtMapBuffer2[i]=0.0;         
   }

Primeiramente, declaramos a variável randomValue (valor aleatório) e atribuímos o valor do nosso indicador "aleatório" na barra atual. Para isso, utilizamos a função iCustom:

double randomValue=iCustom(NULL,0,"RandomIndicator",barsToProcess,0,i);
 
// get the value of the "random" indicator on the i-th bar. Use the active chart on the current period. 
// The name of the executable file of indicator: RandomIndicator. Single parameter of "random" indicator
// is number of bars for calculation. In our indicator there is also analogous variable, that is why
// we use it. In "random" indicator only 1 data buffer, so we use 0, for getting
// access to its values.

Se o valor do indicador "aleatório" for maior que o nível superior (800), este é um sinal para comprar:

if(randomValue>800.0)
   ExtMapBuffer1[i]=High[i]+5*Point;

// if there is signal to buy, assign to current element of data buffer the highest
// value of the current bar. Besides add 5 points, so that the arrow were a little higher 
// than the current price. The predetermined variable Point is used to get automatically
// a multiplier for presenting points. Otherwise we would have to write something like
// this: ExtMapBuffer1[i]=High[i]+0.0005; 

De outro modo, se não houver nenhum sinal de Compra:

else
   ExtMapBuffer1[i]=0.0;
 
// if no Buy signal, assign to the current element of data
// buffer "empty" value, which is equal to 0.0.
// Now no symbol will be shown on this bar.

Se o valor do indicador "aleatório" for menor que o nível inferior (200), este é um sinal para Vender:

if(randomValue<200.0)
   ExtMapBuffer2[i]=Low[i]-5*Point;
 
// if it is signal to sell, assign to the current element of data buffer the lowest
// value of the current bar. Besides diminish the value by 5 points, so that the arrow were 
// a little lower than the current price.

De outro modo, se não houver nenhum sinal de Venda:

else
   ExtMapBuffer2[i]=0.0;
 
// if no Sell signal, assign to the current element of data
// buffer "empty" value. Now no symbol will be shown on this bar.

Isto era o ciclo. Compile o indicador e o inicie no terminal:





Sobre o estilo

Não, estas não são regras para combinar um terno e uma camisa com uma gravata, embora elas sejam sempre oportunas. Se você não escrever o código apenas para você mesmo, o estilo de programação é muito importante. Na verdade, cada desenvolvedor tem seu próprio estilo de programação. Cada um projeta ciclos de sua própria maneira, faz diferentes ajustes (ou não faz nenhum entalhe), declara variáveis etc Você deve encontrar o seu próprio estilo de programação que você sempre irá utilizar. Eu gostaria de dar-lhe várias recomendações que ajudarão você a tornar seu código fácil de ler e de compreender:

  • Não escreva muitos operações em uma linha separas de ponto e vírgula(;)
  • escreva os nomes das variáveis e das funções em Inglês
  • nos nomes de variáveis use letras maiúsculas como delimitadores
  • evite o uso abusivo de abreviaturas e reduções nos nomes de variáveis e funções
  • faça ajustes de um determinado comprimento para ter até mesmo blocos de código
  • em cada novo corpo (de um ciclo ou de uma condição) faça ajustes adicionais
  • faça o agrupamento de variáveis de um tipo
  • faça comentários apropriados para blocos de códigos grandes e difíceis
  • faça comentários apropriados para as funções escritas por você (atribuição, parâmetros)


Conclusão

Você aprendeu algo novo hoje. Você escreveu dois indicadores simples. Bem, eles são inúteis, mas eu não estou ensinando você a negociar com sucesso! Você já viu como os indicadores funcionam e quais parâmetros e propriedades eles possuem. Você aprendeu a definir buffers e a trabalhar com eles. Você se familiarizou com várias novas funções. A função iCustom é muito importante e continuará a ser usado mesmo em Expert Advisors. Se você encontrar alguma dificuldade, leia o artigo novamente e tente compreendê-lo. Se você ainda tem alguma dúvida, por favor, não hesite em usar os fóruns ou escrever comentários para o artigo.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/1500

Arquivos anexados |
Indicador Taichi - uma ideia simples de formalizar os valores do Ichimoku Kinko Hyo Indicador Taichi - uma ideia simples de formalizar os valores do Ichimoku Kinko Hyo
Dificuldades para interpretar os sinais Ichimoku? Este artigo apresenta alguns princípios de formalização de valores e sinais de Ichimoku Kinko Hyo. Para visualização de seu uso o autor escolheu o par de moedas EURUSD com base em suas próprias preferências. No entanto, o indicador pode ser usado em qualquer par de moedas.
Abordagem do objeto no MQL Abordagem do objeto no MQL
Este artigo vai ser interessante, em primeiro lugar, para programadores novatos e profissionais que trabalham no ambiente MQL. Também seria útil se este artigo fosse lido por desenvolvedores e ideólogos do ambiente MQL pois as questões aqui analisadas podem tornar-se projetos para uma futura implementação do MetaTrader e da MQL.
Exibição de um novo calendário Exibição de um novo calendário
Este artigo contém a descrição para escrever um indicador simples e conveniente exibindo em uma área de trabalho os principais eventos econômicos a partir de recursos externos da Internet.
Como implementar seus próprios critérios de otimização Como implementar seus próprios critérios de otimização
Neste artigo um exemplo de otimização com critérios de lucro/levantamento de crédito com resultados retornados em um arquivo é desenvolvido para um Expert Advisor Padrão - Média Móvel.