English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Caminhe em novos trilhos: Personalize indicadores no MQL5

Caminhe em novos trilhos: Personalize indicadores no MQL5

MetaTrader 5Exemplos | 4 dezembro 2013, 12:35
4 234 1
TheXpert
TheXpert

Introdução

Finalmente temos a oportunidade de testar o novo terminal de troca - MetaTrader 5. Sem dúvida, ele é digno de atenção e tem muitos recursos novos se comparado com o seu antecessor. As vantagens importantes desta plataforma entre outras são:

  • Linguagem essencialmente modificada, permitindo agora usar a programação orientada ao objeto, ainda permitindo usar as muitas vantagens da programação estrutural.
  • A velocidade de execução de código, que agora é muito mais rápida que no MetaTrader 4.
  • Aumento essencial de possibilidades para a exibição das informações necessárias.

Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado neste um contexto, como vantagens adicionais para os desenvolvedores.

Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação comparando com o MQL4.

Não há nada complicado neste artigo, além disso, tudo que for considerado aqui pode ser verificado diretamente no terminal usando os arquivos anexados.

Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles acharão algo novo aqui.

A estrutura geral

A estrutura geral do indicador comparada com o MQL4 não mudou.

Assim como antes, existem três funções - para inicialização, para processamento de dados e para a desinicialização do indicador.

Assim como antes, muitos parâmetros do indicador podem ser definidos pela palavra chave (#property). A maioria deles são projetados especificamente para os indicadores. As propriedades e os parâmetros de entrada, assim como antes, são definidos em um contexto global.

Como exemplo, vamos considerar a implementação da coloração personalizada para o indicador RSI. Aqui está a versão cortada, a completa pode ser encontrada no arquivo Color_RSI.mq5.

Vamos considerar as partes do código.

//--- grupo de propriedades
#property copyright "TheXpert"
#property link      "theforexpert@gmail.com"
#property version   "1.00"
//--- a descrição do indicador não pode exceder 511 símbolos no total
//--- incluíndo símbolos de novas linhas
#property description "      "
#property description "Demonstração de criação de indicador"
#property description "pelo exemplo do colorimento do RSI"

As propriedades especificadas acima são exibidas no painel de informação do indicador (a aba "Common" das propriedades). Ela se parece:

//--- propriedades do indicador
#property indicator_separate_window // o indicador será mostrado em uma subjanela
#property indicator_buffers 2       // número de buffers usados
#property indicator_plots   1       // número de buffers mostrados
//--- plot 1
#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // usar 2 cores
#property indicator_type1  DRAW_COLOR_LINE               // e como a cor será mostrada

Estas são as propriedades do indicador. A outra descrição das propriedades pode ser encontrada na ajuda.

//---- buffers
double Values[];                 // buffer de valores
double ValuesPainting[];         // buffer de cores
//--- indicator input parameters
input string             _1           = "Parâmetros do RSI";
input int                RSIPeriod    = 5;
input int                SmoothPeriod = 5;
input ENUM_APPLIED_PRICE AppliedPrice = PRICE_CLOSE;
input string             _2           = "Definições de cor";
input color              Down         = clrDarkSalmon;
input color              Up           = clrDeepSkyBlue;
//--- variable for storing the indicator handle
int RSIHandle;

Aqui estão os parâmetros de entrada do indicador e variáveis globais (não confunda com as variáveis globais do terminal do cliente). Os parâmetros de entrada do indicador são especificados com o identificador de entrada.

Agora é possível ajustar a enumeração do parâmetro de entrada, às vezes, é útil para evitar a seleção de parâmetros incorretos.

Por exemplo, o parâmetro AppliedPrice será exibido em um menu suspenso com os valores válidos possíveis.

Assim todas as enumerações, incluindo as definidas pelo usuário, serão exibidas no mesmo menu suspenso. Por exemplo, o seguinte parâmetro

//...
enum DayOfWeek
{
    Segunda,
    Terça,
    Quarta,
    Quinta,
    Sexta,
    Sábado,
    Domingo
};

input DayOfWeek Dia;

//...

será exibido como segue:

int OnInit()
  {
//--- vinculação dos buffers do indicador
//--- Values serve como buffer visível
   SetIndexBuffer(0,Values,INDICATOR_DATA);
//--- ValuesPainting serve como buffer para guardar as cores
   SetIndexBuffer(1,ValuesPainting,INDICATOR_COLOR_INDEX);
//--- Define o início do buffer Values para se desenhar
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,RSIPeriod);
//--- Define o nome do indicador
   IndicatorSetString(INDICATOR_SHORTNAME,"Color RSI("+string(RSIPeriod)+")");
//--- Define um valor vazio para o gráfico
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//--- Define as cores do buffer
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Down);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Up);
//--- receber os manipuladores do indicador
   RSIHandle=iRSI(NULL,0,RSIPeriod,AppliedPrice);
//--- Definir a seqüência de indexação do buffer
   ArraySetAsSeries(Values,true);
   ArraySetAsSeries(ValuesPainting,true);
//--- execução bem sucedida
   return(0);
  }

Onlnit é o indicador da função de inicialização. Aqui configuramos os buffers do indicador e suas propriedades e definimos as variáveis do indicador que não podem ser definidas nas propriedades ou devem ser ajustadas dinamicamente. Há também uma inicialização dos dados iniciais, incluindo a atribuição dos identificadores que são necessários para os indicadores.

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[])
  {
//--- número de barras para o cálculo
   int toCount=(int)MathMin(rates_total,rates_total-prev_calculated+1);
//--- tentar copiar os dados do indicador iRSI
   if(CopyBuffer(RSIHandle,0,0,toCount,Values)==-1)
     {
      Print("Erro na cópia de dados, №",GetLastError());
      //--- retorna o comando para recalcular os valores do indicador
      return(0);
     }
//--- colorindo. Sim, agora tornou-se fácil
   for(int i=toCount-2;i>=0;--i)
     {
      //--- colorindo a primeira linha
      if(Values[i+1]!=EMPTY_VALUE && Values[i]>Values[i+1])
         ValuesPainting[i]=1;
      else
         ValuesPainting[i]=0;
     }
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }

OnCalculate é a função para o cálculo de dados. Esta função pode ser de dois tipos. Aqui está a forma padrão. Os detalhes se encontram abaixo.

Função:

//--- este uso da função não é obrigatório
/*
void OnDeinit()
{

}
*/

OnDeinit é a função de desinicialização do indicador. É necessário liberar os recursos com frequência, por exemplo, identificadores de arquivos. Para outros casos esta função não é necessária.

Dois conceitos de indicadores

O primeiro é padrão, o mesmo que estamos acostumados no MQL4 mas com uma forma levemente modificada. a função OnCalculate é usada em vez da função Start.

A forma padrão se parece como segue:

int OnCalculate(const int rates_total,      // Tamanho do Array
                const int prev_calculated,  // barras calculadas depois da última chamada
                const datetime& time[],     // Tempo para o gráfico atual...
                const double& open[],
                const double& high[],       
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
   return rates_total;
}

Para reduzir a quantidade de dados destinados a cópia de dados, os dados da tabela são passados diretamente como dispostos aos parâmetros da função. Além disso, o número de barras disponíveis é passado como primeiro parâmetro da função, o número de barras processadas depois da última chamada ou 0 (zero) passa como segundo parâmetro.

O valor 0 (zero) pode ser passado pela primeira chamada do indicador, assim como quando carregando dados novos ou perdidos. Este parâmetro é um substituto (alternativo ou equivalente - depende de você) para o IndicatorCounted(), que é inconveniente para muitos desenvolvedores.

O segundo conceito é a substituição e a expansão do i<…>OnArray - como funções do MQL4. Há um indicador desse tipo nos exemplos de terminal - Custom Moving Average. Estes tipos de indicadores são indicados para o processamento de dados dependente da escolha do usuário, incluindo os indicadores personalizados.

A função para o processamento de dados para os indicadores de tal tipo se parecem com isto:

int OnCalculate (const int rates_total,      // tamanho da série price[] 
                 const int prev_calculated,  // barras calculadas depois da última chamada
                 const int begin,            // onde os dados fictícios começam
                 const double& price[]       // array para cálculos
                 )
  {
   return rates_total;
  }

O último parâmetro da função são os dados selecionados pelo usuário para o processamento. Se você quer aplicar um indicador com vários buffers, o buffer do primeiro indicador será passado para o processamento de dados.

Os Dados do primeiro indicador significam que o indicador será aplicado primeiramente ao indicador anexado à janela selecionada da tabela.

Os Dados do indicador anterior significam que aquele indicador será aplicado ao último indicador anexado à janela selecionada da tabela.

Estes indicadores podem ser usados para reunir o stack inteiro. Por exemplo, usando do indicador Custom Moving Average é possível conseguir a suavização tripla impondo o primeiro indicador aos dados necessários, o segundo ao primeiro e o terceiro ao segundo.

Existem muitos indicadores padrão que implementam este conceito em particular. Então, quando você vê o prompt para o parâmetro da função applied_price_or_handle:

ele indica que o indicador está implementado de uma maneira que pode ser calculado nos dados de usuário - os identificadores destes dados devem ser passados como parâmetro applied_price_or_handle.

Usando da mesma maneira é possível organizar o processamento de dados diretamente no código do indicador:

  {
   //...
   RSIHandle = iRSI(NULL, 0, RSIPeriod, AppliedPrice);
   SmoothHandle = iMA(NULL, 0, SmoothPeriod, 0, MODE_EMA, RSIHandle);
   //...
  }

Há outra aplicação nova deste conceito - a habilidade de escrever indicadores de serviço universais. Um exemplo de tal indicador está anexado no arquivo Direction_Brush.mq5.

Os resultados são apresentados no gráfico superior. A coloração de direção neste caso está separada com uma entidade independente e implementada no outro indicador.

Certamente, a sua universalidade é limitada, já que eles são aplicáveis somente para o buffer zero do indicador. No entanto, eu acho que os indicadores deste tipo podem ser úteis.

Por outro lado, quando você escreve um indicador personalizado, você deve levar isto em conta, pois a informação principal processada no buffer zero permitirá evitar a implementação de uma máquina multifuncional em um indicador. Muitas das outras ações podem ser executadas e feitas nos indicadores de serviços externos. Tudo o que você terá que fazer é anexar indicadores de serviço com a funcionalidade requerida a sua customização.

O alcance da aplicação não é tão estreito como pode ser visto à primeira vista:

  • características de coloração do indicador (topos, instruções, níveis, segmentos, etc.), incluindo a visualização de tom;
  • sinais diferentes em condições diferentes;
  • coleção e exibição de estatísticas - por exemplo, a distribuição de dados;
  • construção de indicadores universais que podem ser calculados para um buffer - por exemplo, mover as médias, ziguezague.

Os recursos mencionados acima não são a lista completa de implementação de conceito. Eu acho que muitas outras implementações efetivas serão descobertas mais tarde.

O Acesso dos dados

Os princípios de acesso dos dados mudaram do MQL5. Agora o trabalho ocorre diretamente nos bancos de dados e como resultado, a velocidade de cálculo aumentou significativamente. Agora não é necessário criar um banco de dados e chamar a função iCustom para cada valor. Em vez disso, é possível conseguir a contagem de dados necessária chamando uma função e então usar diretamente os dados demandados copiados em um banco de dados local especificado.

A cópia dos dados é implementada usando a função de sistema CopyBuffer. Você pode achar a descrição de função na ajuda.

A contagem de dados máxima para copiar para o indicador e bancos de dados estáticos (com um tamanho pré-definido) é determinada pelo tamanho do banco de dados. O tamanho do banco de dados dinâmico pode ser modificado se o número de dados copiados exceder o seu tamanho.

Além disso, existem funções especiais para o acesso dos dados de histórico:

Função Descrição
CopyBuffer Recebe dados de um buffer específico de um certo indicador na quantidade necessária.
CopyRates Recebe dados de histórico da estrutura MqlRates de um período símbolo especificado em quantidades especificadas no banco de dados rates_array.
CopyTime A função recebe dados de histórico do time_array da abertura da barra para o par de período símbolo especificado na quantidade especificada.
CopyOpen A função entra nos dados de histórico do open_array da barra de preços de abertura para o par de período símbolo selecionado na quantidade especificada.
CopyHigh A função entra nos dados de histórico do high_array da barra de preços máximos para o par de período símbolo selecionado na quantidade especificada.
CopyLow A função entra nos dados de histórico do low_array da barra de preços mínimos para o par de período símbolo selecionado na quantidade especificada.
CopyClose A função entra nos dados de histórico do close_array da barra de preços de fechamento para o par de período símbolo selecionado na quantidade especificada.
CopyTickVolume A função entra nos dados de histórico do volume_array dos volumes de tick para o par de período símbolo selecionado na quantidade especificada.
CopyRealVolume A função entra nos dados de histórico do volume_array dos volumes de negociação para o par de período símbolo selecionado na quantidade especificada.
CopySpread A função entra nos dados de histórico do spread_array dos valores de Spread para o par de período símbolo selecionado na quantidade especificada.

Detalhes podem ser encontrados na ajuda.

Esses dados são transmitidos em somente uma forma do indicador, para o outro eles devem ter os próprios.

Devido ao fato do tipo do banco de dados de histórico não ser necessariamente duplo, é recomendado usar somente buffers de não indicador dinâmico para a sua gravação.

Há também mais um detalhe não documentado - se a contagem dos dados copiados for igual a 0 (zero), a função CopyBuffer irá gerar um erro com código nº4003, então a contagem de dados para a cópia não deve ser menor que 1 (um) elemento.

Os Buffers do indicador

A contagem de buffers não é limitada

Agora você não deve pensar em como acomodar a informação corretamente, como executar os cálculos intermediários com eficiência, trabalhando na criação do indicador do cluster.

Mas não devemos esquecer que a gravação dos buffers requer memória. Então, se você especificar uma profundidade de histórico do terminal de aproximadamente 1.000.000 de barras e anexar o indicador de cluster "thick" para o gráfico de minuto, não se surpreenda quando o terminal consumir Gb de memória.

A essência do buffer também sofreu algumas alterações. A quantidade de buffers usados é especificada nas propriedades de entrada.

#property indicator_buffers 2       // buffers usados

Este valor deve corresponder à contagem total de buffers.

O número de buffers exibidos é definido pela propriedade:

#property indicator_plots 1         // buffers mostrados

Aqui estão alguns detalhes. A maioria dos estilos de desenho precisam somente de um buffer INDICATOR_DATA para o desenho. Entretanto, existem alguns estilos que necessitam vários buffers de indicador para o desenho.

Como os exemplos dos seguintes estilos de desenhos:

  • DRAW_HISTOGRAM2 - requer dois buffers do indicador (HistogramSample.mq5)

  • DRAW_FILLING - requer dois buffers de indicador (CrossMa.mq5)

  • DRAW_CANDLES - requer quatro buffers do indicador (CandleSample.mq5)

  • DRAW_BARS - requer quatro buffers do indicador (BarsSample.mq5)

Todos os tipos acima, exceto o estilo DRAW_FILLING (ele não pode ser colorido), têm análogos coloridos.

Todos os buffers do indicador são agora divididos em 3 tipos:

  • Buffers INDICADOR_DATA - em que os dados são exibidos no gráfico. Estes buffers são destinados ao desenho e para o trabalho com o iCustom. Eles devem ser registrados primeiro. No caso de seu pedido casual (errado), o código será compilado com sucesso e ele será desenhado quando aplicado a um gráfico, entretanto, provavelmente incorretamente.

  • INDICATOR_COLOR_INDEX - buffers para o armazenamento de cores. Eles são necessários para o armazenamento de indexadores de buffers de cor do tipo INDICATOR_DATA, tendo um dos tipos de cores especiais (#property indicator_typeN). Tal buffer (nós o denominamos buffer de cor) deve ser registrado logo depois do buffer principal, que o usa.

  • INDICATOR_CALCULATIONS - buffers de tal tipo são adequados para a gravação de resultados de cálculos auxiliares. Eles não são exibidos no gráfico.

int OnInit()
{
   // ...
   SetIndexBuffer(0, V2, INDICATOR_DATA);
   SetIndexBuffer(1, V2C,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, V4, INDICATOR_DATA);
   SetIndexBuffer(3, V4C,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4, V1, INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, V3, INDICATOR_CALCULATIONS);

   // ...
   return 0;
}

Existem também alguns recursos relativos à indicadores via iCustom.

  • Buffers para desenho (aqueles que são exibidos no gráfico) estão disponíveis para leitura. O número do buffer (índice) deve combinar com aquele para o qual o buffer está registrado.
  • Os buffers para um armazenamento de cores pode estar disponível para a leitura, mas nem sempre. Por exemplo, no código acima o buffer V2C pode ler e obter os valores necessários, mas o buffer V4C não está disponível.
  • Os buffers para cálculos intermediários não estão disponíveis da maneira que estavam no MQL4. Se você quiser ter acesso assegurado para o buffer de dados externo, declare-o como INDICATOR_DATA.

No caso do pedido ao buffer inacessível, o erro 4806 ("Os dados requeridos não foram encontrados") será gerado.

Vamos considerar os buffers de cores em detalhe.

No MQL4, para cada cor era necessário criar um buffer separado, mas agora usando os estilos de cores, você pode especificar até 63 cores para um buffer. Em alguns casos, ele permitirá otimizar o número de buffers usado e então economizar o uso da memória. Ele também abre novas possibilidades para os indicadores de escrita, em particular, o uso de visualização de tom.

Além disso, esta inovação, em alguns casos, simplifica muito a lógica da aplicação de várias cores em comparação com o MQL4. O exemplo mais óbvio - separação de tendências por cores. No MQL4 para o caso de muita economia (nos casos corretos) de implementação ele requeria três (3) buffers e programação não trivial.

Agora é mais fácil que nunca. Aqui estão as amostras de códigos, a implementação completa pode ser encontrada no arquivo Color_RSI.mq5.

#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // usar 2 cores
#property indicator_type1  DRAW_COLOR_LINE               //e o tipo especial de visualização das cores
//---- buffers
double Values[];                 // buffer de valores
double ValuesPainting[];         // buffer dos índices de cores
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- vinculação dos buffers do indicador
//--- Values serve como buffer visível
   SetIndexBuffer(0,Values,INDICATOR_DATA);
//--- ValuesPainting serve como buffer para guardar as cores
   SetIndexBuffer(1,ValuesPainting,INDICATOR_COLOR_INDEX);
//...
   return(0);
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate(/*...*/)
  {
//--- número de barras para o cálculo
   int toCount=(int)MathMin(rates_total,rates_total-prev_calculated+1);
//--- tentar copiar os dados do indicador iRSI
   if(CopyBuffer(RSIHandle,0,0,toCount,Values)==-1)
     {
      Print("Erro na cópia de dados, №",GetLastError());
      //--- retorna o comando para recalcular os valores do indicador
      return(0);
     }
//--- colorindo. Sim, agora tornou-se fácil
   for(int i=toCount-2;i>=0;--i)
     {
      //--- colorindo a primeira linha
      if(Values[i+1]!=EMPTY_VALUE && Values[i]>Values[i+1])
         ValuesPainting[i]=1;
      else
         ValuesPainting[i]=0;
     }
//--- retorna o valor de prev_calculated para o próximo uso
   return(rates_total);
  }

Alguns códigos mais e nós conseguimos o seguinte:

Você deve notar alguns dos detalhes quando estiver usando os tipos de cores para desenho.

Para os buffers de cores, quando estiver usando um esquema de definição de cores dinâmico, a contagem de cores máxima é limitada pela contagem de cores definida na propriedade indicator_colorN. Por exemplo

#property indicator_color1 clrDarkSalmon, clrDeepSkyBlue // usar 2 cores

o esquema de cores do buffer conterá no máximo duas cores, mesmo que você ajuste um número maior de cores dinamicamente (usando o PlotIndexSetInteger).

Então, o número de cores requerido deve ser escrito em uma linha - linha de definição de propriedade. Então elas podem ser modificadas dinamicamente. A cor mais curta que eu encontrei - "Red". Entretanto, você pode sempre fazer o seguinte:

Em vez de

#property indicator_color1  clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, clrRed, //…

você pode escrever:

#define C clrRed
#property indicator_color1  C, C, C, C, C, C, C, C, C, C, C, C, C, C, //…

O número máximo de cores para um buffer é 63. Quando o número de cores for maior que o máximo (definido pela propriedade indicator_colorN) o buffer não será exibido.

Aqui está um exemplo de visualização de tom, usando o número máximo de cores:

Em geral, as oportunidades de desenho aumentaram significativamente, e isso é ótimo.

Banco de dados

Durante a referência direta ao banco de dados por índices é necessário referir se ao tipo de ordem de dados - propriedade AsSeries. Ela não pode ser definida para alguns tipos de bancos de dados.

Esta etiqueta não pode ser ajustada para os bancos de dados multi-dimensionais e estáticos. Para os tipos de bancos de dados, que passam pela função OnCalculate é possível ajustar tal etiqueta.

A cópia dos dados usando a função CopyBuffer não depende da propriedade AsSeries, mas a sua implementação é diferente para buffers diferentes.

Para os buffers do indicador é necessário copiar a profundidade total do histórico disponível. Ela deve ser lembrada.

Para bancos de dados dinâmicos e estáticos (com tamanho pré-definido) a cópia dos dados é executada do presente para o passado.

A função CopyBuffer modifica o tamanho dos buffers para buffers dinâmicos (exceto do indicador) para o tamanho necessário.

Não é recomendado usar os bancos de dados estáticos para a cópia de dados.

Em geral, eu o aconselho a sempre verificar como copiar os dados e como endereçá-los. A maneira mais simples e segura é:

  • ajustar a propriedade AsSeries para todos os buffers usados para o armazenamento de dados de histórico.
  • levar em conta as estruturas do buffer para os buffers diferentes.
  • verificar sempre o valor da variável _LastError (código de último erro).

Além disso, eu recomento com veemência estudar a ajuda para a função CopyBuffer e para todas as funções conectadas com a propriedade AsSeries.

IndicatorCounted

Agora os debates sobre a necessidade da função IndicatorCounted sucumbirá ao esquecimento, pois esse valor é definido diretamente por nós como valor de retorno da chamada da função anterior.

int OnCalculate(const int rates_total,      // Tamanho do array
                const int prev_calculated,  // barras calculadas depois da última chamada
                //...)
  {
   return rates_total;
  }

Com mais frequência é suficiente retornar o valor rates_total que contém a contagem de barras da chamada de função atual.

Entretanto, se os dados de preços foram modificados desde a última chamada OnCalculate() (por exemplo, dados de histórico foram carregados ou as lacunas de dados de histórico foram preenchidas), então o valor do parâmetro de entrada prev_calculated

será ajustado para 0 (zero) pelo terminal do cliente.

Também, se a função OnCalculate retornar zero, então os valores do indicador não são exibidos no DataWindow do terminal do cliente. Então, se você quiser ver o indicador e executar o seu recalculo total durante o processo de carregamento do histórico ou depois de uma falha de conexão, retorne 1 em vez de 0.

Outro recurso útil que foi adicionado é determinar quantas barras foram calculadas para o indicador. É de mais utilidade para Expert Advisors que executam cálculos em dados extensos. A função é BarsCalculated, seus detalhes podem ser encontrados na ajuda.

Esta função tem outra aplicação útil. Se o indicador não foi carregado, o seu carregamento pode levar algum tempo - o tempo entre a criação do identificador de indicador e o seu uso para os cálculos.

Este tempo é necessário para a inicialização e o seu pré-cálculo inicial. Ele depende da velocidade de cálculo e detalhes do indicador.

Durante este tempo, a chamada para a função CopyBuffer gera o erro 4806 - "Os dados requeridos não foram encontrados".

A função BarsCalculated pode ser usada paradeterminar a disponibilidade dos dados do indicador para a cópia:

//--- número de barras para o cálculo
   int toCount=rates_total-(int)MathMax(prev_calculated-1,0);
//--- tentar copiar os dados do indicador iWPR
   int copied=CopyBuffer(WPRHandle,0,0,toCount,Values);
   int err=GetLastError();
//--- checar o resultado da cópia
   if(copied==-1)
     {
      //--- se o número do erro é 4806, os dados simplesmente não foram carregados ainda
      if(err==4806)
        {
         //--- esperar até os dados serem carregados
         for(int i=0;i<1000;++i)
            if(BarsCalculated(WPRHandle)>0)
               break;
         //--- tentar copiar os dados do indicador iWPR de novo
         copied=CopyBuffer(WPRHandle,0,0,rates_total,Values);
         err=GetLastError();
        }
     }
//--- checar o resultado da cópia
   if(copied==-1)
     {
      Print("Erro ao tentar pegar os valores de WPR, último erro é ",err," barras ",rates_total);
      return(0);
     }
//...

Índice

Em conclusão, eu gostaria de dizer que apenas alguns dos detalhes foram considerados neste artigo. Mas eu espero que os aspectos básicos esteja apresentados aqui.

Seria ótimo se este artigo fosse uma referência útil sobre o assunto, onde você pudesse sempre consultar e encontrar informações sobre os detalhes.

Se você encontrou algum erro neste artigo, ou descobriu algo importante, por favor me informe e eu tentarei corrigir e melhorar o artigo assim que possível.

Eu estou planejando esboçar as modificações recentes, além disso, espero que algumas das informações úteis apareçam nos comentários.

Esta é a razão para lê-los com cuidado.

Apêndice

  • Color.mqh - incluir o arquivo, copiar este arquivo para a pasta MQL5/Include. Este arquivo é necessário para o indicador Toned_WPR.
  • Color.mqh - biblioteca, copiar este arquivo para a pasta MQL5/Libraries. Este arquivo é necessário para o indicador Toned_WPR.

Todos os demais arquivos são indicadores

Agradecimentos

Novamente, eu gostaria de agradecer o Sr. Victor Rustamov (granit77) pela leitura do manuscrito, discussões úteis e conselhos proveitosos.

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

Arquivos anexados |
color.mqh (2.04 KB)
barssample.mq5 (4.7 KB)
candlesample.mq5 (4.71 KB)
color.mq5 (8.48 KB)
color_rsi.mq5 (11.32 KB)
crossma.mq5 (5.08 KB)
toned_wpr.mq5 (9.65 KB)
Últimos Comentários | Ir para discussão (1)
[Excluído] | 23 dez 2013 em 12:08
Attached source code files and source code insets in HTML code are now completely translated into Portuguese for your convenience.
MQL5: Crie o seu próprio indicador MQL5: Crie o seu próprio indicador
O que é um indicador? É um conjunto de valores calculados que deseja-se que sejam exibidos em uma tela de forma conveniente. Os conjuntos de valores são representados em programas como arrays. Deste modo, a criação de um indicador significa escrever um algorítimo que manuseia algumas séries (séries de preço) e registra os resultados do manuseamento para outras séries (valores de indicador). Descrevendo a criação do Force Index, o autor mostra como escrever indicadores no MQL5.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Aplicar um indicador a outro Aplicar um indicador a outro
Ao escrever um indicador que usa a forma curta da solicitação da função OnCalculate(), você pode deixar passar o fato de que um indicador pode ser calculado, não apenas pelos dados de preço, mas também pelos dados de algum outro indicador (não importando se for incorporado ou um personalizado). Você quer melhorar um indicador para sua aplicação correta a outros dados do indicador? Vamos analisar neste artigo todas as etapas necessárias para tal modificação.
Desenvolvendo um sistema de Replay (Parte 49): Complicando as coisas (I) Desenvolvendo um sistema de Replay (Parte 49): Complicando as coisas (I)
Aqui neste artigo iremos complicar um pouco as coisa. Fazendo uso do que foi visto nos artigos anteriores, iremos começar a liberar o arquivo de Template, para que o usuário possa fazer uso de um template pessoal. No entanto, irei fazer as mudanças aos poucos, visto que também irei modificar o indicador a fim de proporcionar um alivio ao MetaTrader 5.