
Indicadores Personalizados (Parte 1): Um Guia Introdutório Passo a Passo para Desenvolver Indicadores Personalizados Simples em MQL5
Introdução
A representação visual da informação de mercado é o alicerce da negociação. Sem essa modelagem visual dos dados e preços de mercado, a negociação não seria tão viável ou eficaz. Desde os primeiros dias de gráficos até as ferramentas sofisticadas de análise técnica disponíveis hoje, os traders confiam em pistas visuais para tomar decisões informadas nos mercados financeiros.
Os indicadores MQL5 servem como ferramentas poderosas para melhorar esse processo de análise visual. Aproveitando cálculos matemáticos e algoritmos, os indicadores MQL5 ajudam os traders a identificar oportunidades de lucro ao ler o comportamento do mercado estatisticamente. Esses indicadores podem ser aplicados diretamente aos gráficos de preços, fornecendo aos traders insights valiosos sobre a dinâmica do mercado.
Nesta série de artigos, exploraremos como os indicadores MQL5 são criados, personalizados e utilizados para melhorar as estratégias de negociação no MetaTrader 5. Desde a lógica básica do indicador até opções avançadas de personalização, cobriremos os princípios fundamentais e avançaremos gradualmente para os conceitos mais complexos de desenvolvimento de indicadores conforme progredimos com a série de artigos. O principal objetivo desta série de artigos é capacitá-lo a criar seus próprios indicadores personalizados MQL5 adaptados às suas preferências e metas de negociação.
O que é um Indicador?
Um indicador é uma ferramenta ou instrumento usado para analisar dados de preços passados e prever movimentos futuros de preços. Os indicadores concentram-se principalmente na análise de dados de mercado, em vez de executar negociações. Eles não podem abrir, modificar ou fechar posições e ordens. Eles fornecem apenas insights e não executam negociações.
Em essência, os indicadores são cálculos matemáticos ou algoritmos aplicados aos dados históricos de preços para gerar representações visuais do comportamento do mercado, atualizando seu status em tempo real conforme os dados são atualizados.
Essas representações visuais podem assumir várias formas, incluindo gráficos de linha, velas, histogramas, setas ou sobreposições nos gráficos de preços. Os indicadores ajudam os traders a interpretar a dinâmica do mercado, destacando tendências, identificando possíveis reversões ou sinalizando condições de sobrecompra ou sobrevenda.
Os indicadores podem ser classificados em diferentes categorias com base em sua funcionalidade, como indicadores de seguimento de tendência, indicadores de momento, indicadores de volatilidade e indicadores de volume.
Tipos de Indicadores no MQL5
Existem dois tipos de indicadores no MQL5: indicadores técnicos e indicadores personalizados.
1. Indicadores Técnicos
Esses são os indicadores padrão que vêm pré-carregados com o MetaTrader 5. Eles incluem uma ampla gama de indicadores técnicos que os traders podem acessar e carregar em seus gráficos do MetaTrader 5 para analisar o mercado. Esses indicadores incluem ferramentas populares, como osciladores, indicadores de seguimento de tendência e indicadores baseados em volume.
O código-fonte desses indicadores padrão não está prontamente disponível para visualização ou modificação, pois eles são incorporados na plataforma MetaTrader 5. A única maneira de acessá-los a partir do seu código MQL5 é usando as funções de indicadores técnicos predefinidas do MQL5. Essa funcionalidade nos permite atualizar ou personalizar esses indicadores padrão usando MQL5 para criar novos indicadores personalizados avançados e ferramentas de negociação. Eu demonstrarei como você pode estender a funcionalidade dos indicadores técnicos quando desenvolvermos um indicador personalizado baseado em velas suavizadas e multicoloridas à medida que avançamos com o artigo.
Exemplos de indicadores técnicos padrão do MetaTrader 5 incluem:
- iMA (Média Móvel Simples): Calcula a média móvel simples de uma série de preços especificada.
- iRSI (Índice de Força Relativa): Mede a magnitude das recentes mudanças de preço para avaliar condições de sobrecompra ou sobrevenda.
- iMACD (Convergência/Divergência de Médias Móveis): Identifica a direção da tendência e possíveis reversões ao analisar a convergência e divergência de duas médias móveis.
2. Indicadores Personalizados
Como o nome sugere, os indicadores personalizados são ferramentas de análise técnica que você pode construir por conta própria para analisar os mercados financeiros. Eles diferem dos indicadores embutidos porque permitem cálculos e visualizações mais específicos com base nas suas necessidades de negociação.
Como programador MQL5, você pode criar indicadores com base em qualquer dado disponível de qualquer fonte que você escolher. Você também pode importar um indicador personalizado já criado ou estender e modificar os indicadores técnicos MQL5 predefinidos para construir um indicador personalizado mais sofisticado e avançado, como faremos.
Benefícios dos Indicadores Personalizados
Aqui estão algumas propriedades e benefícios dos indicadores personalizados:
Flexibilidade Inigualável em Cálculos:- Você pode projetar indicadores personalizados para utilizar qualquer fórmula de indicador técnico ou estratégia de negociação que imaginar.
- Com o MQL5, você pode explorar uma ampla gama de cálculos de indicadores personalizados e modelos matemáticos adaptados às suas necessidades específicas.
- Você pode personalizar como os resultados do indicador aparecem no gráfico.
- O MQL5 oferece a opção de usar estilos de linha, velas, setas, objetos multicoloridos e muitos elementos gráficos adicionais para criar visualizações claras e informativas alinhadas ao seu estilo de negociação.
- O MQL5 oferece mais do que apenas criar indicadores do zero.
- Você pode aproveitar fontes de dados externas além dos dados de preço típicos para criar uma variedade de indicadores de análise técnica ou fundamental.
- Importe indicadores personalizados pré-construídos criados por outros programadores de MQL5 para melhorar ou estender sua funcionalidade.
- Estenda e modifique os indicadores embutidos para criar indicadores personalizados sofisticados, adaptados às suas necessidades exclusivas de negociação.
Combinando essas capacidades, o MQL5 permite que você construa indicadores personalizados que não apenas são adaptados às suas necessidades de análise técnica, mas também podem incorporar dados e cálculos além dos indicadores tradicionais baseados em preços.
Exemplos de Indicadores Personalizados Gratuitos no Terminal MetaTrader 5 O terminal MetaTrader 5 também fornece uma seleção de indicadores de exemplo que você pode acessar para usar ou estudar e compreender melhor o desenvolvimento de indicadores no MQL5. O código-fonte dos indicadores de exemplo gratuitos do MetaTrader 5 está prontamente disponível e é um recurso valioso para programadores de MQL5 que desejam aprender e experimentar a criação de indicadores. Os indicadores de exemplo do MQL5 estão armazenados nas pastas MQL5\Indicators\Examples e MQL5\Indicators\Free Indicators dentro do diretório de instalação do MetaTrader 5.
Ao examinar e modificar os indicadores de exemplo, você pode obter insights sobre técnicas de programação MQL5, lógica de indicadores e melhores práticas. Essa abordagem prática promove o aprendizado e capacita você a desenvolver indicadores personalizados adaptados aos seus objetivos específicos de negociação.
Blocos de Construção Básicos de Indicadores Personalizados em MQL5
Antes de estudar o desenvolvimento de indicadores personalizados no MQL5, é essencial entender a estrutura básica de um indicador MQL5. Ao se familiarizar com os principais componentes e funções de um indicador, você estará mais bem equipado para criar, modificar e utilizar indicadores de forma eficaz no MetaTrader 5.
Arquivo de Indicador Personalizado (.mq5)
Um indicador MQL5 é normalmente armazenado em um arquivo com a extensão ".mq5". Este arquivo contém o código-fonte escrito na linguagem de programação MQL5, definindo a lógica e o comportamento do indicador. Todos os indicadores são armazenados na pasta MQL5\Indicators dentro do diretório de instalação do MetaTrader 5.
Use o painel Navigator encontrado tanto no terminal de negociação MetaTrader 5 quanto no MetaEditor para acessar a pasta de Indicadores. Você também pode acessar a pasta de Indicadores através da pasta "MQL5" usando os seguintes dois métodos:
Como Acessar Arquivos de Indicadores Através do Terminal de Negociação MetaTrader 5:.
- Clique em "Arquivo" no menu superior.
- Selecione "Abrir Pasta de Dados" ou use o atalho de teclado (Ctrl + Shift + D).
- Navegue até a pasta "MQL5/Indicators".
Como Acessar Arquivos de Indicadores Através do MetaEditor:
- O painel Navigator do MetaEditor está localizado no lado esquerdo da janela do MetaEditor por padrão e fornece acesso direto à pasta MQL5.
- Se o painel Navigator estiver desativado, você pode ativá-lo usando o atalho de teclado (Ctrl + D) ou localizando e clicando na opção de menu Exibir no topo da janela do MetaEditor 5. A partir daí, selecione a opção que diz Navegador. Escolher essa opção habilitará o painel de navegação que lhe dá acesso à pasta MQL5.
Exemplo 1: O Indicador Personalizado de Histograma de Média Móvel Linear (LinearMovingAverageHistogram.mq5) Vamos criar um indicador personalizado para obter uma compreensão visual dos diferentes componentes de código necessários para construir um indicador personalizado. Nomearemos nosso primeiro indicador personalizado para esta demonstração prática como 'LinearMovingAverageHistogram'. Ele plotará uma média móvel ponderada linear como um histograma e uma linha representando o preço atual em uma janela separada abaixo do gráfico de preços.
Vamos começar criando um novo arquivo de indicador personalizado com o MQL5 Wizard.
Como Criar um Novo Arquivo de Indicador Personalizado com o MQL5 Wizard
Passo 1: Abra o IDE MetaEditor e inicie o 'MQL Wizard' usando o botão do item de menu 'Novo'.
Passo 2: Selecione a opção 'Indicador Personalizado' e clique em 'Próximo.'
Passo 3: Na seção 'Propriedades Gerais', preencha a pasta e o nome do seu novo indicador personalizado "Indicators\Article\LinearMovingAverageHistogram" e prossiga clicando em 'Próximo.'
Passo 4: Na seção 'Manipuladores de Eventos', selecione a segunda opção 'OnCalculate(...,preços)', deixe as caixas de seleção OnTimer e OnChartEvent desmarcadas e clique em 'Próximo' para continuar.
Passo 5: Na seção 'Propriedades de Desenho', selecione ou habilite a caixa de seleção 'Indicador em janela separada'. Desmarque ou desabilite as caixas de seleção 'Mínimo' e 'Máximo' e deixe a caixa de texto 'Plots' vazia. Clique em 'Finalizar' para gerar o novo arquivo de indicador personalizado MQL5.
Na pasta ‘MQL5/Indicators’, você encontrará uma nova subpasta chamada ‘Article.’ Essa subpasta contém o arquivo do indicador personalizado recém-criado, ‘LinearMovingAverageHistogram.mq5.’ Como parte das demonstrações práticas, estaremos codificando vários indicadores personalizados ao longo deste artigo. Para manter a organização adequada, salvaremos todos os arquivos de indicadores nesta nova pasta ‘Articles’.
Agora temos um novo arquivo de indicador personalizado MQL5 com apenas as funções obrigatórias (OnInit e OnCalculate). Lembre-se de salvar o novo arquivo antes de continuar. Aqui está como o código do nosso novo indicador personalizado gerado se parece:
//+------------------------------------------------------------------+ //| LinearMovingAverageHistogram.mq5 | //| Copyright 2024, Wanateki Solutions Ltd. | //| https://www.wanateki.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Wanateki Solutions Ltd." #property link "https://www.wanateki.com" #property version "1.00" #property indicator_separate_window //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Componentes Básicos de um Arquivo de Indicador Personalizado (.mq5). O arquivo de indicador consiste em várias seções. Vamos analisar como as diferentes partes do código do indicador funcionam:
Seção de Cabeçalho. A seção de cabeçalho do indicador é composta por três partes: os comentários do cabeçalho, as diretivas de propriedade, os arquivos externos incluídos e as definições de variáveis globais.
Abaixo está um detalhamento do que está incluído na seção de cabeçalho do nosso indicador:
1. Comentários do Cabeçalho: Esta é a primeira seção do código do nosso indicador. Ela contém informações comentadas sobre o indicador, como o nome do arquivo, informações de direitos autorais e um link para o site do autor. Esses comentários não afetam a funcionalidade do código do indicador de forma alguma.
//+------------------------------------------------------------------+ //| LinearMovingAverageHistogram.mq5 | //| Copyright 2024, Wanateki Solutions Ltd. | //| https://www.wanateki.com | //+------------------------------------------------------------------+2. Diretivas de Propriedade: As diretivas de propriedade fornecem informações adicionais sobre o indicador. Elas incluem os direitos autorais, um link associado ao indicador ou ao autor, a versão atual do indicador e instruções específicas sobre como exibir o indicador. A diretiva de propriedade mais importante é "#property indicator_separate_window", que instrui a plataforma a exibir o indicador em uma janela separada.
#property copyright "Copyright 2024, Wanateki Solutions Ltd." #property link "https://www.wanateki.com" #property version "1.00" #property indicator_separate_windowAs diretrizes de propriedade copyright, link, author, e description são visíveis na aba "Common" da pequena subjanela de configuração do indicador que aparece quando você carrega o indicador no gráfico.

3. Variáveis Globais: Todas as variáveis globais são colocadas abaixo das diretrizes de propriedade. Nosso código do indicador atualmente não contém variáveis globais, pois não as especificamos ao gerar o arquivo com o MQL5 Wizard. Definiremos todas as nossas variáveis globais e de entrada de usuário abaixo das diretrizes #property à medida que avançarmos neste artigo.
Funções Padrão de Indicador Personalizado do MQL5 Abaixo da seção de cabeçalho, você encontrará diferentes funções. Todos os indicadores devem conter as funções padrão do MQL5 OnInit e OnCalculate. Funções criadas pelo usuário são opcionais, mas recomendadas para uma organização adequada do código. Aqui está um resumo das diferentes funções no código do nosso indicador: 1. Função de Inicialização do Indicador (OnInit()): A função OnInit() é chamada quando o indicador é inicializado. Ela normalmente realiza tarefas de configuração, como mapear buffers de indicadores e inicializar quaisquer variáveis globais. Eu o apresentarei aos buffers de indicadores à medida que aprofundarmos no artigo. Quando a função é executada com sucesso, ela retorna INIT_SUCCEEDED e, quando a inicialização falha, ela retorna INIT_FAILED.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- return(INIT_SUCCEEDED); }2. Função de Iteração do Indicador (OnCalculate()): A função OnCalculate() no MQL5 é o centro nervoso principal de todos os cálculos de indicadores personalizados. Ela é chamada sempre que há uma alteração nos dados de preços, solicitando que o indicador atualize seus valores. Existem duas versões principais de OnCalculate(), que explicarei mais adiante no artigo.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- //--- return value of prev_calculated for next call return(rates_total); }3. Função de Desinicialização do Indicador (OnDeinit()): A função OnDeinit() não foi adicionada ao nosso código, mas é uma função muito importante. Ela é chamada quando o indicador está sendo encerrado e é responsável por executar os procedimentos de desinicialização. Normalmente, ela realiza todas as tarefas de limpeza, como liberar quaisquer manipuladores de indicadores técnicos.
//+------------------------------------------------------------------+ //| Indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //-- deinitialization code } //+------------------------------------------------------------------+
Quando compilamos nosso código indicador, encontramos 1 aviso: "nenhum gráfico de indicador definido para o indicador".
Este aviso significa que nosso indicador personalizado não possui uma definição crucial de como seus dados devem ser exibidos no gráfico. Como esperado, nosso código indicador atual serve como um mero esqueleto sem nenhum componente funcional. Para corrigir isso, vamos nos aprofundar e escrever os segmentos de código essenciais que darão vida ao nosso indicador.
Diretivas da Propriedade de Descrição Vamos começar escrevendo uma breve descrição do indicador personalizado na seção de cabeçalho do indicador:
#property description "A custom indicator to demonstrate a linear weighted moving average." #property description "A histogram and line are drawn in a separate window to indicate " #property description "the moving average direction."Diretivas da Propriedade de Buffers e Gráficos Todos os indicadores personalizados têm diferentes propriedades que estão sempre posicionadas no início do arquivo, conforme expliquei anteriormente. Algumas são opcionais, mas as três seguintes são sempre obrigatórias:
- indicator_separate_window ou indicator_chart_window: Usado para especificar se um indicador será plotado em uma janela separada ou diretamente na janela do gráfico.
- indicator_buffers: Especifica o número de buffers do indicador usados pelo indicador personalizado.
- indicator_plots: Especifica o número de gráficos usados pelo indicador personalizado.
Para atender a este requisito, vamos definir os buffers do indicador e as propriedades dos gráficos. Sob a propriedade 'indicator_separate_window', colocamos o código responsável por especificar os buffers e gráficos do indicador. Os buffers e gráficos de indicadores são usados para exibir os dados do indicador nos gráficos. Usamos a diretiva de propriedade para definir o número de buffers que estarão disponíveis no código para calcular o indicador. Este número é um inteiro de 1 a 512. Como esta é uma diretiva de pré-processador, ainda não existem variáveis na etapa de pré-processamento do código-fonte e é por isso que devemos especificar um dígito (de 1 a 512) como valor.
Precisamos de dois buffers de indicador e dois gráficos para armazenar e plotar os dados do nosso novo indicador personalizado. Um buffer de indicador para o histograma e outro para a linha que exibirá o preço atual do símbolo. Seguido por um gráfico para o histograma e outro gráfico para a linha de preço.
//--- indicator buffers and plots #property indicator_buffers 2 #property indicator_plots 2
Diretivas da Propriedade de Rótulo, Tipo e Estilo
Em seguida, devemos especificar outros detalhes como o rótulo do indicador, tipo, cor, estilo e largura do histograma e da linha de preço.
//--- plots1 details for the ma histogram #property indicator_label1 "MA_Histogram" #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plots2 details for the price line #property indicator_label2 "Current_Price_Line" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGoldenrod #property indicator_style2 STYLE_SOLID #property indicator_width2 2
Variáveis Globais de Entrada do Usuário
A seguir, especificamos as variáveis de entrada do usuário do indicador personalizado (período da média móvel e deslocamento) que serão usadas para armazenar diferentes parâmetros do indicador.
//--- input parameters for the moving averages input int _maPeriod = 50; // MA Period input int _maShift = 0; // MA Shift
Declaração de Arrays Dinâmicos do Buffer do Indicador no Escopo Global
Em seguida, declaramos o buffer do indicador para o histograma da média móvel e a linha de preço. Os buffers de indicadores estão entre os pilares básicos dos indicadores personalizados e são responsáveis por armazenar os dados do indicador em arrays dinâmicos. Você deve começar declarando um array dinâmico e, em seguida, registrá-lo como um buffer de indicador usando uma função especial do MQL5 'SetIndexBuffer' para convertê-lo em um array gerenciado pelo terminal. Após fazer isso, o terminal será responsável por alocar memória para o array e fornecer acesso público a ele como um novo array acessível por séries temporais, no qual outros indicadores podem ser calculados.
Primeiro, declararemos os buffers do histograma e da linha como arrays dinâmicos e, depois, na função OnInit(), usaremos a função especial 'SetIndexBuffer' do MQL5 para registrá-los e convertê-los em arrays acessíveis por séries temporais gerenciadas pelo terminal.
//--- indicator buffer double maHistogramBuffer[], priceLineBuffer[];
Função de Inicialização do Indicador Personalizado - GetInit()
Em seguida, vamos criar uma função personalizada que será responsável por inicializar nosso indicador personalizado. Comece criando uma função em branco do tipo void, o que significa que ela não retorna dados. Nomeie a função 'GetInit()'. Coloque a função especial 'SetIndexBuffer(...)', que será responsável por converter os arrays dinâmicos dos buffers de indicador que declaramos anteriormente 'maHistogramBuffer' e 'priceLineBuffer' em arrays acessíveis por séries temporais gerenciadas pelo terminal.
//+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ void GetInit() { //--- set the indicator buffer mapping SetIndexBuffer(0, maHistogramBuffer, INDICATOR_DATA); SetIndexBuffer(1, priceLineBuffer, INDICATOR_DATA); } //+------------------------------------------------------------------+Em seguida, definimos a precisão do indicador para coincidir com o valor de dígitos do símbolo.
//--- set the indicators accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1);Depois, definimos a primeira barra a partir de onde o índice começará a ser desenhado.
//--- set the first bar from where the index will be drawn PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, _maPeriod); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 0);Configure o deslocamento do indicador de média móvel para o valor especificado pelo usuário para o handle da média móvel e use um valor zero para a linha de preço. Isso será usado ao plotar ou desenhar o indicador.
//--- set the indicator shifts when drawing PlotIndexSetInteger(0, PLOT_SHIFT, _maShift); PlotIndexSetInteger(1, PLOT_SHIFT, 0);Em seguida, definimos o nome que será mostrado na Janela de Dados MT5 para os valores do indicador a partir do buffer de dados do indicador. Usamos um controle de switch para definir o nome curto do indicador para a janela de dados.
//--- set the name to be displayed in the MT5 DataWindow IndicatorSetString(INDICATOR_SHORTNAME, "LWMA_Histo" + "(" + string(_maPeriod) + ")");Para finalizar a função de inicialização do indicador, definiremos o histograma de desenho como um valor vazio.
//--- set the drawing histogram and line to an empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
Função Personalizada para Calcular a Média Móvel Ponderada Linear - GetLWMA()
Em seguida, precisamos criar uma função personalizada chamada 'GetLWMA(..)', que será responsável por calcular a média móvel ponderada linear. A função será do tipo void, pois não queremos que ela retorne dados. Ela aceitará quatro argumentos como parâmetros de função (rates_total, prev_calculated, begin, &price).
//+------------------------------------------------------------------+ //| Function to calculate the linear weighted moving average | //+------------------------------------------------------------------+ void GetLWMA(int rates_total, int prev_calculated, int begin, const double &price[]) { int weight = 0; int x, l, start; double sum = 0.0, lsum = 0.0; //--- first calculation or number of bars was changed if(prev_calculated <= _maPeriod + begin + 2) { start = _maPeriod + begin; //--- set empty value for first start bars for(x=0; x < start; x++) { maHistogramBuffer[x] = 0.0; priceLineBuffer[x] = price[x]; } } else start = prev_calculated - 1; for(x = start - _maPeriod, l = 1; x < start; x++, l++) { sum += price[x] * l; lsum += price[x]; weight += l; } maHistogramBuffer[start-1] = sum/weight; priceLineBuffer[x] = price[x]; //--- main loop for(x=start; x<rates_total && !IsStopped(); x++) { sum = sum - lsum + price[x] * _maPeriod; lsum = lsum - price[x - _maPeriod] + price[x]; maHistogramBuffer[x] = sum / weight; priceLineBuffer[x] = price[x]; } }
Função Principal de Iteração do Indicador - OnCalculate()
A função de iteração do indicador personalizado 'OnCalculate(..)' é o coração do nosso indicador personalizado e é responsável por atualizar e plotar nosso indicador quando há um novo tick ou mudança de preço, e todos os cálculos necessários se originam aqui. Atualmente, estamos usando a forma abreviada da função OnCalculate():
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { return(rates_total); }Esta função aceita quatro parâmetros de entrada ou argumentos:
- rates_total: Este parâmetro contém o valor do número total de elementos do array price[]. Ele é passado como um parâmetro de entrada para calcular os valores do indicador, como fizemos anteriormente com a função 'GetLWMA(..)'.
- prev_calculated: Este parâmetro armazena o resultado da execução de 'OnCalculate(..)' na chamada anterior. Ele desempenha um papel fundamental no algoritmo de cálculo dos valores do indicador e garante que não façamos cálculos para todo o período do histórico em cada chamada da função 'OnCalculate(..)' ou quando ocorre uma nova mudança de preço.
- begin: Este parâmetro armazena o número do valor inicial do array de preços, que não contém dados para o cálculo. No nosso indicador personalizado, este valor é o "_maPeriod" e simplesmente informa à função 'OnCalculate(...)' para interromper todos os cálculos até que todas as barras alcancem o valor armazenado em "_maPeriod", garantindo que haja barras suficientes para os cálculos do indicador.
- price: Este parâmetro armazena o preço aplicado usado para calcular os dados do indicador. Ele é especificado pelo usuário ao carregar o indicador personalizado no gráfico. Os usuários têm a opção de selecionar open, close, high, low, preço médio (HL / 2), preço típico (HLC / 3), fechamento ponderado (HLCC / 4), ou valores de dados de indicadores previamente carregados.

Aqui está o código para nossa função 'OnCalculate(...)':
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- check if we have enough bars to do the calculations if(rates_total < _maPeriod - 1 + begin) return(0); //--- first calculation or number of bars was changed if(prev_calculated == 0) { ArrayInitialize(maHistogramBuffer, 0); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, _maPeriod - 1 + begin); } //--- calculate the linear weighted moving average and plot it on the chart GetLWMA(rates_total, prev_calculated, begin, price); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+Agora temos todos os diferentes segmentos de código do nosso novo indicador personalizado. Certifique-se de que o arquivo 'LinearMovingAverageHistogram' tenha a aparência e todos os componentes do código abaixo:
#property version "1.00" #property indicator_separate_window //--- indicator buffers and plots #property indicator_buffers 2 #property indicator_plots 2 //--- plots1 details for the ma histogram #property indicator_label1 "MA_Histogram" #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plots2 details for the price line #property indicator_label2 "Current_Price_Line" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGoldenrod #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //--- input parameters for the moving averages input int _maPeriod = 50; // MA Period input int _maShift = 0; // MA Shift //--- indicator buffer double maHistogramBuffer[], priceLineBuffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- call the custom initialization function GetInit(); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- check if we have enough bars to do the calculations if(rates_total < _maPeriod - 1 + begin) return(0); //--- first calculation or number of bars was changed if(prev_calculated == 0) { ArrayInitialize(maHistogramBuffer, 0); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, _maPeriod - 1 + begin); } //--- calculate the linear weighted moving average and plot it on the chart GetLWMA(rates_total, prev_calculated, begin, price); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ void GetInit() { //--- set the indicator buffer mapping SetIndexBuffer(0, maHistogramBuffer, INDICATOR_DATA); SetIndexBuffer(1, priceLineBuffer, INDICATOR_DATA); //--- set the indicators accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1); //--- set the first bar from where the index will be drawn PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, _maPeriod); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 0); //--- set the indicator shifts when drawing PlotIndexSetInteger(0, PLOT_SHIFT, _maShift); PlotIndexSetInteger(1, PLOT_SHIFT, 0); //--- set the name to be displayed in the MT5 DataWindow IndicatorSetString(INDICATOR_SHORTNAME, "LWMA_Histo" + "(" + string(_maPeriod) + ")"); //--- set the drawing histogram and line to an empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Function to calculate the linear weighted moving average | //+------------------------------------------------------------------+ void GetLWMA(int rates_total, int prev_calculated, int begin, const double &price[]) { int weight = 0; int x, l, start; double sum = 0.0, lsum = 0.0; //--- first calculation or number of bars was changed if(prev_calculated <= _maPeriod + begin + 2) { start = _maPeriod + begin; //--- set empty value for first start bars for(x=0; x < start; x++) { maHistogramBuffer[x] = 0.0; priceLineBuffer[x] = price[x]; } } else start = prev_calculated - 1; for(x = start - _maPeriod, l = 1; x < start; x++, l++) { sum += price[x] * l; lsum += price[x]; weight += l; } maHistogramBuffer[start-1] = sum/weight; priceLineBuffer[x] = price[x]; //--- main loop for(x=start; x<rates_total && !IsStopped(); x++) { sum = sum - lsum + price[x] * _maPeriod; lsum = lsum - price[x - _maPeriod] + price[x]; maHistogramBuffer[x] = sum / weight; priceLineBuffer[x] = price[x]; } }Quando você salvar e compilar o indicador personalizado, notará que agora ele não contém avisos ou erros. Abra seu terminal de negociação MetaTrader 5 para carregá-lo e testá-lo em seus gráficos.
Mais Exemplos Práticos
Agora que você está familiarizado com os blocos de construção básicos dos indicadores personalizados, devemos criar alguns indicadores personalizados simples para nos ajudar a solidificar esse conhecimento. Seguiremos todos os passos que definimos anteriormente e implementaremos todas as bases dos indicadores personalizados nos exemplos abaixo.
Exemplo 2: O Monitor de Spread Indicador Personalizado - (SpreadMonitor.mq5)
Vamos continuar com nossa abordagem prática e criar outro indicador personalizado simples que usa dados de spread para exibir um histograma multicolorido em uma janela separada. Este indicador será útil para símbolos que utilizam spread flutuante e facilitará o monitoramento de como o spread flutua ou dispara ao longo do tempo de maneira visual e fácil de analisar. Use o Assistente MQL como fizemos anteriormente para criar um novo arquivo de indicador personalizado com o nome 'SpreadMonitor.mq5'. Lembre-se de salvá-lo na pasta 'Article' para manter uma estrutura de arquivos organizada.
Neste exemplo, demonstrarei como criar um indicador multicolorido. Quando o spread atual for maior que o spread anterior, o histograma mudará para a cor vermelha para indicar um aumento no spread, e quando o spread atual for menor que o spread anterior, o histograma mudará para a cor azul para indicar que o spread está diminuindo. Esta função do indicador personalizado será melhor observada em símbolos com spread flutuante, e uma rápida olhada no indicador, quando carregado em um gráfico, facilita a identificação de períodos em que o spread está disparando rapidamente.
Depois de gerar o novo arquivo de indicador personalizado 'SpreadMonitor.mq5' com o Assistente MQL, adicione o seguinte código.
Comece especificando onde o indicador será exibido:
//--- indicator window settings #property indicator_separate_window
Especifique o número de buffers e gráficos do indicador:
//--- indicator buffers and plots #property indicator_buffers 2 #property indicator_plots 1
Defina o tipo de indicador, estilo e especifique as diferentes cores:
//--- indicator type and style settings #property indicator_type1 DRAW_COLOR_HISTOGRAM #property indicator_color1 clrDarkBlue, clrTomato #property indicator_style1 0 #property indicator_width1 1 #property indicator_minimum 0.0
Declare os arrays dinâmicos que serão usados como buffers do indicador no escopo global:
//--- indicator buffers double spreadDataBuffer[]; double histoColorsBuffer[];
Crie a função personalizada que será responsável por inicializar nosso indicador:
//+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ void GetInit(){ } //+------------------------------------------------------------------+
Dentro da nossa nova função de inicialização de indicador 'GetInit()'. Registre e mapeie os buffers do indicador:
//--- set and register the indicator buffers mapping SetIndexBuffer(0, spreadDataBuffer, INDICATOR_DATA); SetIndexBuffer(1, histoColorsBuffer, INDICATOR_COLOR_INDEX);
Defina o nome que aparecerá na Janela de Dados do MetaTrader 5 e como rótulo da subjanela do indicador:
//--- name for mt5 datawindow and the indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME,"Spread Histogram");
Defina os dígitos do indicador para precisão:
//--- set the indicators accuracy digits IndicatorSetInteger(INDICATOR_DIGITS, 0);
O próximo passo será criar uma função personalizada para calcular o spread. Vamos nomear a função 'GetSpreadData()' e especificar que ela deve conter três parâmetros ou argumentos. A função será do tipo void, já que não precisamos que ela retorne nenhum dado:
//+------------------------------------------------------------------+ //| Custom function for calculating the spread | //+------------------------------------------------------------------+ void GetSpreadData(const int position, const int rates_total, const int& spreadData[]) { spreadDataBuffer[0] = (double)spreadData[0]; histoColorsBuffer[0] = 0.0; //--- for(int x = position; x < rates_total && !IsStopped(); x++) { double currentSpread = (double)spreadData[x]; double previousSpread = (double)spreadData[x - 1]; //--- calculate and save the spread spreadDataBuffer[x] = currentSpread; if(currentSpread > previousSpread) { histoColorsBuffer[x] = 1.0; //-- set the histogram to clrTomato } else { histoColorsBuffer[x] = 0.0; //-- set the histogram to clrDarkBlue } } //--- } //+------------------------------------------------------------------+
O indicador personalizado não pode funcionar com a função OnCalculate() vazia. Neste exemplo, usaremos a versão longa de OnCalculate(), que utiliza especificamente dez parâmetros para armazenar e processar os dados do indicador personalizado.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- check if we have enough data start calculating if(rates_total < 2) //--- don't do any calculations, exit and reload function return(0); //--- we have new data, starting the calculations int position = prev_calculated - 1; //--- update the position variable if(position < 1) { spreadDataBuffer[0] = 0; position = 1; } //--- calculate and get the tick volume GetSpreadData(position, rates_total, spread); //--- Exit function and return new prev_calculated value return(rates_total); }
O indicador personalizado SpreadMonitor está quase completo, vamos unir todos os diferentes segmentos de código e salvar o arquivo antes de compilá-lo e carregá-lo em um gráfico do MetaTrader 5.
//--- indicator window settings #property indicator_separate_window //--- indicator buffers and plots #property indicator_buffers 2 #property indicator_plots 1 //--- indicator type and style settings #property indicator_type1 DRAW_COLOR_HISTOGRAM #property indicator_color1 clrDarkBlue, clrTomato #property indicator_style1 0 #property indicator_width1 1 #property indicator_minimum 0.0 //--- indicator buffers double spreadDataBuffer[]; double histoColorsBuffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- initialize the indicator GetInit(); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- check if we have enough data start calculating if(rates_total < 2) //--- don't do any calculations, exit and reload function return(0); //--- we have new data, starting the calculations int position = prev_calculated - 1; //--- update the position variable if(position < 1) { spreadDataBuffer[0] = 0; position = 1; } //--- calculate and get the tick volume GetSpreadData(position, rates_total, spread); //--- Exit function and return new prev_calculated value return(rates_total); } //+------------------------------------------------------------------+ //| Custom function for calculating the spread | //+------------------------------------------------------------------+ void GetSpreadData(const int position, const int rates_total, const int& spreadData[]) { spreadDataBuffer[0] = (double)spreadData[0]; histoColorsBuffer[0] = 0.0; //--- for(int x = position; x < rates_total && !IsStopped(); x++) { double currentSpread = (double)spreadData[x]; double previousSpread = (double)spreadData[x - 1]; //--- calculate and save the spread spreadDataBuffer[x] = currentSpread; if(currentSpread > previousSpread) { histoColorsBuffer[x] = 1.0; //-- set the histogram to clrTomato } else { histoColorsBuffer[x] = 0.0; //-- set the histogram to clrDarkBlue } } //--- } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ void GetInit() { //--- set and register the indicator buffers mapping SetIndexBuffer(0, spreadDataBuffer, INDICATOR_DATA); SetIndexBuffer(1, histoColorsBuffer, INDICATOR_COLOR_INDEX); //--- name for mt5 datawindow and the indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME,"Spread Histogram"); //--- set the indicators accuracy digits IndicatorSetInteger(INDICATOR_DIGITS, 0); } //+------------------------------------------------------------------+
Aqui está o SpreadMonitor indicador personalizado carregado em um gráfico de cinco minutos do GBPJPY no MetaTrader 5.
Exemplo 3: Indicador Personalizado de Velas Suavizadas Multi-Coloridas - (SmoothedCandlesticks.mq5)
Como os indicadores são principalmente representações visuais de estratégias de negociação, indicadores multicoloridos são preferíveis aos que exibem dados visuais em uma única cor. Indicadores multicoloridos facilitam para os traders identificar rapidamente os sinais de negociação gerados pelo indicador, o que ajuda a otimizar a eficiência e a facilidade de uso do indicador.
Ter a capacidade de criar indicadores multicoloridos é uma habilidade muito útil para qualquer desenvolvedor de MQL5, e neste exemplo, demonstrarei como você pode criar um indicador personalizado de velas suavizadas multicoloridas. Eliminar o ruído do mercado sempre foi uma prioridade para os traders, e este indicador simples realiza isso ao usar os cálculos das médias móveis suavizadas para criar velas multicoloridas que mudam de cor de acordo com o sinal das médias móveis. Isso cria um gráfico organizado, fácil de interpretar, e elimina a necessidade de usar a ferramenta de mira do gráfico para detectar se ocorreu um cruzamento de média móvel.
As velas ficam verdes quando os preços de abertura, alta, baixa e fechamento estão acima da média móvel suavizada e ficam vermelhas quando os preços de abertura, alta, baixa e fechamento estão abaixo da média móvel suavizada. Se a média móvel suavizada tocar qualquer parte do corpo da vela, ou seja, se estiver entre os preços alto e baixo da vela, a vela ficará cinza escuro para mostrar que não há sinal de entrada sendo gerado pelo indicador suavizado.
Este exemplo também demonstrará como usar os indicadores padrão do MQL5 por meio das funções predefinidas de indicadores técnicos do MQL5 que discutimos anteriormente. Use o Assistente MQL5 para criar um novo arquivo de indicador personalizado e nomeie-o 'SmoothedCandlesticks.mq5'. Lembre-se de salvá-lo na pasta 'Article' junto com os outros arquivos de indicadores personalizados que criamos anteriormente.
Especificando as Diretivas #Property do Indicador
Comece especificando onde o indicador será exibido, seja na janela do gráfico ou em uma janela separada abaixo do gráfico de preços. O indicador funcionará em todos os cenários, e você pode alternar entre exibi-lo em uma janela separada e na janela do gráfico para testar sua aparência visual.
//--- specify where to display the indicator #property indicator_separate_window //#property indicator_chart_window
Especificando os buffers do indicador. Neste indicador, usaremos seis buffers de indicadores para plotar e exibir nossos dados. Teremos quatro buffers de indicadores para os preços de abertura, fechamento, alta e baixa das velas. Um buffer de indicador para a linha da média móvel suavizada e outro buffer de indicador para armazenar as cores das velas. Isso totaliza seis buffers de indicadores.
//--- indicator buffers #property indicator_buffers 6
Precisamos de dois gráficos de indicadores para o desenho do nosso indicador. Um gráfico para desenhar as velas e outro gráfico para a linha da média móvel suavizada. Isso totaliza dois gráficos de indicadores.
//--- indicator plots #property indicator_plots 2
Especifique os detalhes do gráfico para as velas suavizadas. Isso inclui valores para o tipo, cor e rótulo. O rótulo é exibido na janela de dados junto com os dados correspondentes, como o preço. Nosso indicador usa velas multicoloridas e precisamos fornecer um total de três cores que mudarão dependendo do sinal de negociação atual, como expliquei anteriormente. O usuário terá a opção de alterar as cores especificadas antes de carregar o indicador no gráfico, no painel de indicadores.
//--- plots1 details for the smoothed candles #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrDodgerBlue, clrTomato, clrDarkGray #property indicator_label1 "Smoothed Candle Open;Smoothed Candle High;Smoothed Candle Low;Smoothed Candle Close;"
Repita o passo anterior e especifique os detalhes do segundo gráfico para a linha da média móvel suavizada. Especificaremos apenas uma cor para a linha suavizada, pois não é uma linha multicolorida.
//--- plots2 details for the smoothing line #property indicator_label2 "Smoothing Line" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGoldenrod #property indicator_style2 STYLE_SOLID #property indicator_width2 2
Variáveis de Entrada do Usuário no Escopo Global
Declare as variáveis de entrada do usuário para capturar e salvar o período da média móvel suavizada e o preço aplicado para os cálculos.
//--- user input parameters for the moving averages input int _maPeriod = 50; // Period input ENUM_APPLIED_PRICE _maAppliedPrice = PRICE_CLOSE; // Applied Price
Variáveis de Indicador, Buffers e Handle de Indicadores Técnicos no Escopo Global
Aqui, vamos declarar arrays dinâmicos para armazenar nossos buffers de indicadores. Anteriormente, usamos a diretiva #property para alocar seis buffers de indicadores. Vamos começar declarando cinco buffers de indicadores para a abertura, fechamento, alta, baixa e armazenamento das velas. O buffer restante para a linha suavizada será declarado abaixo, pois usaremos a função técnica padrão do MQL5 iMA para gerenciar este buffer.
//--- indicator buffers double openBuffer[]; double highBuffer[]; double lowBuffer[]; double closeBuffer[]; double candleColorBuffer[];
Em seguida, declaramos o buffer para a linha suavizada e um handle para acessar a função do indicador técnico iMA. Usar a função de indicador técnico padrão do MQL5 já criada nos poupa tempo e é mais eficiente, pois todos os cálculos de suavização das velas serão realizados de forma eficiente com menos código.
//Moving average dynamic array (buffer) and variables double iMA_Buffer[]; int maHandle; //stores the handle of the iMA indicator
Aqui, declaramos e inicializamos nossa última variável global 'barsCalculated' com o valor zero. Esta variável inteira é usada para armazenar o número de barras calculadas a partir da média móvel suavizada iMA. Vamos usá-la na função OnCalculate().
//--- integer to store the number of values in the moving average indicator int barsCalculated = 0;
Função Personalizada Para a Inicialização do Indicador - GetInit()
Agora que terminamos a seção de cabeçalho do nosso indicador personalizado, vamos criar uma função personalizada para realizar todas as tarefas de inicialização. Vamos nomear a função 'GetInit()' e especificar que ela deve retornar um valor booleano para indicar se a inicialização do indicador foi bem-sucedida. Se a inicialização falhar, o indicador deve terminar e fechar.
Na função de inicialização, realizaremos algumas tarefas importantes, como configurar e registrar os buffers do indicador, salvar o nome curto do indicador e criar o handle da iMA para a linha de suavização, entre outras tarefas básicas de inicialização.
//+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ bool GetInit() { //--- set the indicator buffer mapping by assigning the indicator buffer array SetIndexBuffer(0, openBuffer, INDICATOR_DATA); SetIndexBuffer(1, highBuffer, INDICATOR_DATA); SetIndexBuffer(2, lowBuffer, INDICATOR_DATA); SetIndexBuffer(3, closeBuffer, INDICATOR_DATA); SetIndexBuffer(4, candleColorBuffer, INDICATOR_COLOR_INDEX); //--- buffer for iMA SetIndexBuffer(5, iMA_Buffer, INDICATOR_DATA); //--- set the price display precision to digits similar to the symbol prices IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- set the symbol, timeframe, period and smoothing applied price of the indicator as the short name string indicatorShortName = StringFormat("SmoothedCandles(%s, Period %d, %s)", _Symbol, _maPeriod, EnumToString(_maAppliedPrice)); IndicatorSetString(INDICATOR_SHORTNAME, indicatorShortName); //IndicatorSetString(INDICATOR_SHORTNAME, "Smoothed Candlesticks"); //--- set line drawing to an empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); //--- create the maHandle of the smoothing indicator maHandle = iMA(_Symbol, PERIOD_CURRENT, _maPeriod, 0, MODE_SMMA, _maAppliedPrice); //--- check if the maHandle is created or it failed if(maHandle == INVALID_HANDLE) { //--- creating the handle failed, output the error code ResetLastError(); PrintFormat("Failed to create maHandle of the iMA for symbol %s, error code %d", _Symbol, GetLastError()); //--- we terminate the program and exit the init function return(false); } return(true); // return true, initialization of the indicator ok } //+------------------------------------------------------------------+
Depois de criar a função 'GetInit()', chame-a na função padrão 'OnInit()' do indicador para que ela execute sua tarefa prevista.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- call the custom initialization function if(!GetInit()) { return(INIT_FAILED); //-- if initialization failed terminate the app } //--- return(INIT_SUCCEEDED); }
Função Principal de Iteração do Indicador - OnCalculate()
A próxima tarefa será codificar a função padrão 'OnCalculate(....)' para realizar todos os cálculos do indicador. Neste exemplo, utilizaremos a versão longa desta função padrão, que possui um total de dez parâmetros. Esta versão de 'OnCalculate(...)' baseia-se em cálculos da série temporal do período atual. Aqui estão os parâmetros que ela contém:
- rates_total: Armazena o número total de barras no gráfico quando o indicador é iniciado e é atualizado para refletir o estado atual do total de barras disponíveis à medida que novas barras ou dados são carregados.
- prev_calculated: Salva o número de barras já processadas na chamada anterior. Isso nos ajuda a saber quais dados já calculamos ou processamos, para que não precisemos calcular todas as barras em cada chamada da função OnCalculate(...) ou quando novas barras chegam. OnCalculate(..) retorna uma versão atualizada desta variável em cada chamada.
- time, open, high, low, close, tick_volume, volume, e spread: É fácil dizer o que esses arrays contêm, já que seus nomes representam os dados das barras que eles armazenam e salvam. Nosso indicador personalizado dependerá dos dados desses arrays, e ele demonstrará como utilizá-los, especialmente para um indicador baseado em velas, como o nosso.
Adicione o corpo da função OnCalculate(...) ao nosso código, pois ele contém todos os cálculos relevantes para a plotagem das velas multicoloridas suavizadas e da linha de suavização.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- declare a int to save the number of values copied from the iMA indicator int iMA_valuesToCopy; //--- find the number of values already calculated in the indicator int iMA_calculated = BarsCalculated(maHandle); if(iMA_calculated <= 0) { PrintFormat("BarsCalculated() for iMA handle returned %d, error code %d", iMA_calculated, GetLastError()); return(0); } int start; //--- check if it's the indicators first call of OnCalculate() or we have some new uncalculated data if(prev_calculated == 0) { //--- set all the buffers to the first index lowBuffer[0] = low[0]; highBuffer[0] = high[0]; openBuffer[0] = open[0]; closeBuffer[0] = close[0]; start = 1; if(iMA_calculated > rates_total) iMA_valuesToCopy = rates_total; else //--- copy the calculated bars which are less than the indicator buffers data iMA_valuesToCopy = iMA_calculated; } else start = prev_calculated - 1; iMA_valuesToCopy = (rates_total - prev_calculated) + 1; //--- fill the iMA_Buffer array with values of the Moving Average indicator //--- reset error code ResetLastError(); //--- copy a part of iMA_Buffer array with data in the zero index of the the indicator buffer if(CopyBuffer(maHandle, 0, 0, iMA_valuesToCopy, iMA_Buffer) < 0) { //--- if the copying fails, print the error code PrintFormat("Failed to copy data from the iMA indicator, error code %d", GetLastError()); //--- exit the function with zero result to specify that the indicator calculations were not executed return(0); } //--- iterate through the main calculations loop and execute all the calculations for(int x = start; x < rates_total && !IsStopped(); x++) { //--- save all the candle array prices in new non-array variables for quick access double candleOpen = open[x]; double candleClose = close[x]; double candleHigh = high[x]; double candleLow = low[x]; lowBuffer[x] = candleLow; highBuffer[x] = candleHigh; openBuffer[x] = candleOpen; closeBuffer[x] = candleClose; //--- scan for the different trends signals and set the required candle color candleColorBuffer[x] = 2.0; // set color clrDarkGray - default (signal for no established trend) if(candleOpen > iMA_Buffer[x] && candleClose > iMA_Buffer[x] && candleHigh > iMA_Buffer[x] && candleLow > iMA_Buffer[x]) candleColorBuffer[x]=0.0; // set color clrDodgerBlue - signal for a long/buy trend if(candleOpen < iMA_Buffer[x] && candleClose < iMA_Buffer[x] && candleHigh < iMA_Buffer[x] && candleLow < iMA_Buffer[x]) candleColorBuffer[x]=1.0; // set color clrTomato - signal for a short/sell trend } //--- return the rates_total which includes the prev_calculated value for the next call return(rates_total); }
Função de Desinicialização do Indicador - OnDeinit()
A última função é a função padrão 'OnDeinit()' para desinicializar todas as variáveis e arrays que precisam ser liberados. Todos os arrays de buffers são gerenciados automaticamente e não precisam ser liberados ou desinicializados, exceto pelo handle da iMA. Para garantir que nosso indicador libere todos os recursos não utilizados ao ser encerrado, usaremos a função 'IndicatorRelease()' do MQL5 para liberar quaisquer recursos sendo consumidos pela variável 'maHandle'.
//+------------------------------------------------------------------+ //| Indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(maHandle != INVALID_HANDLE) { IndicatorRelease(maHandle);//-- clean up and release the iMA handle } } //+------------------------------------------------------------------+
Nosso indicador agora está quase completo, aqui estão os segmentos de código combinados. Certifique-se de que seu código tenha todos os diferentes segmentos nesta ordem.
//--- specify where to display the indicator #property indicator_separate_window //#property indicator_chart_window //--- indicator buffers #property indicator_buffers 6 //--- indicator plots #property indicator_plots 2 //--- plots1 details for the smoothed candles #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrDodgerBlue, clrTomato, clrDarkGray #property indicator_label1 "Smoothed Candle Open;Smoothed Candle High;Smoothed Candle Low;Smoothed Candle Close;" //--- plots2 details for the smoothing line #property indicator_label2 "Smoothing Line" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGoldenrod #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //--- user input parameters for the moving averages input int _maPeriod = 50; // Period input ENUM_APPLIED_PRICE _maAppliedPrice = PRICE_CLOSE; // Applied Price //--- indicator buffers double openBuffer[]; double highBuffer[]; double lowBuffer[]; double closeBuffer[]; double candleColorBuffer[]; //Moving average dynamic array (buffer) and variables double iMA_Buffer[]; int maHandle; //stores the handle of the iMA indicator //--- integer to store the number of values in the moving average indicator int barsCalculated = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- call the custom initialization function if(!GetInit()) { return(INIT_FAILED); //-- if initialization failed terminate the app } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- declare a int to save the number of values copied from the iMA indicator int iMA_valuesToCopy; //--- find the number of values already calculated in the indicator int iMA_calculated = BarsCalculated(maHandle); if(iMA_calculated <= 0) { PrintFormat("BarsCalculated() for iMA handle returned %d, error code %d", iMA_calculated, GetLastError()); return(0); } int start; //--- check if it's the indicators first call of OnCalculate() or we have some new uncalculated data if(prev_calculated == 0) { //--- set all the buffers to the first index lowBuffer[0] = low[0]; highBuffer[0] = high[0]; openBuffer[0] = open[0]; closeBuffer[0] = close[0]; start = 1; if(iMA_calculated > rates_total) iMA_valuesToCopy = rates_total; else //--- copy the calculated bars which are less than the indicator buffers data iMA_valuesToCopy = iMA_calculated; } else start = prev_calculated - 1; iMA_valuesToCopy = (rates_total - prev_calculated) + 1; //--- fill the iMA_Buffer array with values of the Moving Average indicator //--- reset error code ResetLastError(); //--- copy a part of iMA_Buffer array with data in the zero index of the the indicator buffer if(CopyBuffer(maHandle, 0, 0, iMA_valuesToCopy, iMA_Buffer) < 0) { //--- if the copying fails, print the error code PrintFormat("Failed to copy data from the iMA indicator, error code %d", GetLastError()); //--- exit the function with zero result to specify that the indicator calculations were not executed return(0); } //--- iterate through the main calculations loop and execute all the calculations for(int x = start; x < rates_total && !IsStopped(); x++) { //--- save all the candle array prices in new non-array variables for quick access double candleOpen = open[x]; double candleClose = close[x]; double candleHigh = high[x]; double candleLow = low[x]; lowBuffer[x] = candleLow; highBuffer[x] = candleHigh; openBuffer[x] = candleOpen; closeBuffer[x] = candleClose; //--- scan for the different trends signals and set the required candle color candleColorBuffer[x] = 2.0; // set color clrDarkGray - default (signal for no established trend) if(candleOpen > iMA_Buffer[x] && candleClose > iMA_Buffer[x] && candleHigh > iMA_Buffer[x] && candleLow > iMA_Buffer[x]) candleColorBuffer[x]=0.0; // set color clrDodgerBlue - signal for a long/buy trend if(candleOpen < iMA_Buffer[x] && candleClose < iMA_Buffer[x] && candleHigh < iMA_Buffer[x] && candleLow < iMA_Buffer[x]) candleColorBuffer[x]=1.0; // set color clrTomato - signal for a short/sell trend } //--- return the rates_total which includes the prev_calculated value for the next call return(rates_total); } //+------------------------------------------------------------------+ //| Indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(maHandle != INVALID_HANDLE) { IndicatorRelease(maHandle);//-- clean up and release the iMA handle } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| User custom function for custom indicator initialization | //+------------------------------------------------------------------+ bool GetInit() { //--- set the indicator buffer mapping by assigning the indicator buffer array SetIndexBuffer(0, openBuffer, INDICATOR_DATA); SetIndexBuffer(1, highBuffer, INDICATOR_DATA); SetIndexBuffer(2, lowBuffer, INDICATOR_DATA); SetIndexBuffer(3, closeBuffer, INDICATOR_DATA); SetIndexBuffer(4, candleColorBuffer, INDICATOR_COLOR_INDEX); //--- buffer for iMA SetIndexBuffer(5, iMA_Buffer, INDICATOR_DATA); //--- set the price display precision to digits similar to the symbol prices IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- set the symbol, timeframe, period and smoothing applied price of the indicator as the short name string indicatorShortName = StringFormat("SmoothedCandles(%s, Period %d, %s)", _Symbol, _maPeriod, EnumToString(_maAppliedPrice)); IndicatorSetString(INDICATOR_SHORTNAME, indicatorShortName); //IndicatorSetString(INDICATOR_SHORTNAME, "Smoothed Candlesticks"); //--- set line drawing to an empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); //--- create the maHandle of the smoothing indicator maHandle = iMA(_Symbol, PERIOD_CURRENT, _maPeriod, 0, MODE_SMMA, _maAppliedPrice); //--- check if the maHandle is created or it failed if(maHandle == INVALID_HANDLE) { //--- creating the handle failed, output the error code ResetLastError(); PrintFormat("Failed to create maHandle of the iMA for symbol %s, error code %d", _Symbol, GetLastError()); //--- we terminate the program and exit the init function return(false); } return(true); // return true, initialization of the indicator ok } //+------------------------------------------------------------------+
Salve e compile o código do indicador, e ele será compilado sem erros ou avisos. Carregue-o no MetaTrader 5 e teste como ele se comporta usando diferentes parâmetros de entrada do usuário.
Conclusão
Neste artigo, você aprendeu o que são indicadores, os vários tipos de indicadores encontrados na plataforma MetaTrader 5, os diferentes componentes e blocos de construção dos indicadores personalizados, e adquiriu experiência prática desenvolvendo alguns indicadores personalizados com MQL5 desde o início.
Desenvolver indicadores personalizados com MQL5 é um tópico complexo que não pode ser totalmente esgotado em um único artigo, por isso continuaremos cobrindo áreas mais avançadas em artigos futuros. Com o conhecimento que você adquiriu neste guia de artigo, você agora é capaz de desenvolver seus próprios indicadores personalizados simples. Eu desafio você a continuar praticando suas habilidades de programação e desejo-lhe tudo de melhor em sua jornada de codificação.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14481





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso