English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Série de preço médio para cálculos intermediários sem utilizar buffers adicionais

Série de preço médio para cálculos intermediários sem utilizar buffers adicionais

MetaTrader 5Indicadores | 7 fevereiro 2014, 08:55
5 928 0
Nikolay Kositsin
Nikolay Kositsin

Introdução

No meu artigo "Os princípios do cálculo econômico de indicadores" fiz testes razoavelmente convincentes que provam o fato de que nem toda chamada única de um indicador personalizado ou técnico é o melhor meio de realização de cálculos intermediários em um indicador desenvolvido.

A velocidade de execução final pode parecer bem menor em comparação com a que poderíamos ter se tivéssemos colocado o código para cálculos intermediários diretamente em nosso indicador.

Este tipo de abordagem para escrever um código poderia ser bastante atrativo, se fosse simples o bastante. Na realidade, ele parece ser uma séria complicação de um código com a descrição de buffers adicionais usados para armazenar resultados de cálculo intermediários.

Apesar da variedade de cálculos intermediários, o mais necessário neles são os diferentes algorítimos de média. Na maioria dos casos, para eles, podemos usar funções de personalização universais e simples que simplificam significativamente a tarefa de escrever tal código. O processo de criação destas funções e o trabalho com eles serão descritos neste artigo.


1. A ideia geral de funções de média que trabalham com uma barra

A abordagem clássica para calcular a média em uma barra atual consiste em um buffer indicador intermediário, o qual preenchemos com as informações necessárias, e depois selecionamos uma gama de valores anteriores, o que é igual ao período de média e calculamos o valor médio.

O procedimento de processamento desta seleção parece com o seguinte:

SmoothVar(bar) = Function(Var(bar - (n-1)), Var(bar - (n-2)), ......... Var(bar))

onde:

  • SmoothVar(bar) — parâmetro médio;
  • bar — número de uma barra, para o qual o cálculo é realizado;
  • Var(bar - (n-1)) — parâmetros de média com uma troca em (n-1) barras;
  • n — número de barras para média.

Tal abordagem de média, em nosso caso, leva ao aparecimento de dois ciclos de cálculo. No primeiro ciclo, os dados são calculados e colocados em um buffer intermediário. No segundo ciclo, a média usando outro ciclo de busca adicional de células do buffer indicador é realizada com base na fórmula sugerida acima. Este cálculo parecerá muito mais fácil, se acumularmos a seleção de dados intermediários dentro da função em si. Neste caso, a função de média parecerá com o seguinte:

SmoothVar(bar) = Function(Var(bar), bar)

Um novo valor Var(bar) é escrito para a seleção de valores dentro da função em uma barra atual, e os valores de Var(bar - n) que se tornam desnecessários são excluídos da seleção. Com esta abordagem, um código de média parece bastante trivial e não requer buffers indicador adicionais. Dentro da função, o array armazena a quantia exata necessária de dados requeridos para o cálculo de uma barra, não todos os dados do histórico.

Neste caso, há também apenas um ciclo de cálculo de dados. Deve ser observado que para chamar esta função de média em uma barra atual, você deve chamá-la em todas as barras anteriores primeiro!


2. A média clássica como exemplo de implementação de uma função que trabalha com uma barra

Tais funções de média devem conter variáveis que não devem perder seus valores entre as chamadas destas funções. Além disso, a média de tipo único com diferentes parâmetros pode ser usada em um código por muitas vezes; então, para evitar um conflito de utilização dos recursos da memória compartilhada, devemos implementar estas funções como classes; e foi isso que eu fiz.

Os algoritmos de média clássica são descritos na classe CMoving_Average:

class CMoving_Average : public CMovSeriesTools
  {
public:  
   double    MASeries  (uint begin,               // Index of start of reliable bars
                       uint prev_calculated,      // Amount of history in bars at a previous tick
                       uint rates_total,          // Amount of history in bars at a current tick
                       int Length,               // Period of averaging
                       ENUM_MA_METHOD MA_Method, // Method of averaging (MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA)
                       double series,              // Value of price series calculated for the bar with the 'bar' number
                       uint bar,                   // Bar index
                       bool set                  // Direction of indexing of arrays.
                      );

   double    SMASeries (uint begin,          // Index of start of reliable bars
                       uint prev_calculated,// Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       int Length,            // Period of averaging
                       double series,         // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    EMASeries (uint begin,            // Index of start of reliable bars
                       uint prev_calculated, // Amount of history in bars at a previous tick
                       uint rates_total,     // Amount of history in bars at a current tick
                       double Length,         // Period of averaging
                       double series,        // Value of price series calculated for the bar with the 'bar' number
                       uint bar,              // Bar index
                       bool set              // Direction of indexing of arrays.
                      );
                        
   double    SMMASeries(uint begin,              // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,     // Amount of history in bars at a current tick
                         int Length,            // Period of averaging
                         double series,         // Value of price series calculated for the bar with the 'bar' number
                         uint bar,              // Bar index
                         bool set              // Direction of indexing of arrays.
                      );

   double    LWMASeries(uint begin,               // Index of start of reliable bars
                         uint prev_calculated, // Amount of history in bars at a previous tick
                         uint rates_total,      // Amount of history in bars at a current tick
                         int Length,             // Period of averaging
                         double series,          // Value of price series calculated the bar with the 'bar' number
                         uint bar,               // Bar index
                         bool set               // Direction of indexing of arrays.
                        );

protected:
   double            m_SeriesArray[];
   int               m_Size_, m_count, m_weight;
   double            m_Moving, m_MOVING, m_Pr;
   double            m_sum, m_SUM, m_lsum, m_LSUM;
  };

Esta classe é derivada da classe base CMoviSeriesTools que contém os métodos de funções protegidas e uma verificação pela exatidão do período das médias móveis.

A classe base contém um código universal adicional que é usado em todas as classes que sugiro, e não há sentido em copiá-la muitas vezes para as classes derivadas. Em tarefas aplicadas de uso de média, os membros da classe protegida não são usados na forma explícita, então, vamos suspender sua visão geral por hora.

A classe CMoving_Average consiste em cinco funções de tipo único de média, seus nomes falam por si, e elas não precisam ser descritas em detalhes.

A primeira função MASeries() é uma coleção integral de quatro outras funções que permitem selecionar um algorítimo de média usando o parâmetro MA_Method. O código de algoritmos de média é otimizado para o máximo desempenho, e este é o motivo pelo qual os parâmetros principais das funções (Comprimento, série, barra) são suplementados com o começo de parâmetros adicionais, prev_calculated, rates_total e set, em que o propósito é absolutamente idêntico às variáveis do indicador com os mesmos nomes.

O parâmetro 'set' define uma marcação de indexação dos elementos de uma série de preço 'series' nas funções de média para serem iguais aos arrays das variáveis.

Devemos considerar que todas as funções de média desta classe têm o parâmetro Lenght (Comprimento) fixo e não pode ser alterado quando o código do programa está sendo executado. A função EMASeries() da classe CMoving_Average tem este parâmetro de tipo duplo!

Agora que já nos familiarizamos com a classe CMoving_Average, podemos começar a usá-la em indicadores. Para isso, usar a diretiva #include adiciona os conteúdos do arquivo MASeries_CIs.mqh em escopo global para o código do indicador que você desenvolve:

#include <MASeries_Cls.mqh> 

E, então, você pode determinar o número necessário de procedimentos de média no código do indicador e, depois, na parte OnCalculate() (antes do operador de loop e colchetes) declare as variáveis estáticas da classe CMoving_Average de acordo com o número necessário de procedimentos de média. Deve haver uma variável separada para a classe e uma célula separada no array da classe para cada procedimento de média.

//---- declaration of variables of the class CMoving_Average из файла MASeries_Cls.mqh
static CMoving_Average MA1, MA2, MA3, MA4;

As variáveis da classe na função OnCalculate() são declaradas como estáticas porque seus valores devem ser mantidos entre as chamadas desta função. Agora podemos começar a trabalhar com a média em si. Como exemplo, mostrarei quatro procedimentos consecutivos de média de séries de preço - SMA/EMA/SMMA/LWMA (o indicador MAx4.ma5):

//---- The main cycle of indicator calculation 
for(bar = first; bar < rates_total; bar++) 
 {
  //----+ Four calls of the function MASeries.  
  ma1_ = MA1.MASeries(start1, prev_calculated, rates_total, Length1, MODE_SMA,  price[bar], bar, false);
  ma2_ = MA2.MASeries(start2, prev_calculated, rates_total, Length2, MODE_EMA,  ma1_,       bar, false);
  ma3_ = MA3.MASeries(start3, prev_calculated, rates_total, Length3, MODE_SMMA, ma2_,       bar, false);
  ma4_ = MA4.MASeries(start4, prev_calculated, rates_total, Length4, MODE_LWMA, ma3_,       bar, false);
  //----       
  MAx4[bar] = ma4_ + dPriceShift;
 }

O resultado de cada média anterior (excluindo o último) é usado no próximo algoritmo de média, e o resultado final é passado para o buffer indicador.

Eu acho que a parte mais importante deste código é uma inicialização preliminar muito cuidadosa das variáveis de índices que mostram o começo de barras confiáveis. Nesta situação, parecerá com o seguinte:

//---- Initialization of variables of start of reliable information
start1 = 0 + begin;
start2 = Length1 + begin;
start3 = Length1 + begin; // the previous EMA averaging doesn't change the start of reliable information
start4 = Length1 + Length3 + begin;

Observe que, nesta situação, o algoritmo LWMA da média é o último e não afeta nada; mas se não fosse o último, então a troca do início da informação confiável seria igual a Length4+1, e não Length4!

Quero adicionar que se não for claro a partir do código anterior, em que o número da informação confiável começa, pegue um número grande e depois o diminua experimentalmente, se necessário.


3. Comparando o indicador criado utilizando classes com seus análogos que usam indicadores técnicos e personalizados

Seria muito interessante comparar o desempenho do indicador MAx4.mq5 criado com seu análogo idêntico (iMAx4.mq5) que usa o indicador técnico iMA().

Bem, assim que tivermos decidido realizar o teste, seria razoável testar outro indicador (MA3x1.mq5) similar ao MAx4.mq5, mas com a primeira média fazendo uso da chamada do indicador técnico iMA() e as outras três usando a classe CMoving_Average. E, assim que o conjunto padrão de indicadores do terminal do cliente incluiu o indicador Custom Moving Average.mq5, fiz outro indicador análogo em suas bases para propósitos de teste (cMAx4.mq5).

Para a próxima análise, preparei Expert Advisors para teste: MAx4_Test.mq5, iMAx4_Test.mq5, MAx3x1_Test.mq5 e cMAx4_Test.mq5 respectivamente. As condições de realização de tais testes foram descritas com detalhes no artigo "Os princípios do cálculo econômico de indicadores". Neste artigo, não descreverei os detalhes do teste, mas mostrarei os resultados finais da execução de todos os quatro Expert Advisors no Strategy Tester para os últimos 12 meses em EURUSD H4 com modelagem de cada tick e o valor dos parâmetros de entrada 'period' (período) de todos os EA's iguais a 500.

Fig.1 O resultado do teste dos indicadores

Os piores resultados em nossos testes são mostrados pelo indicador que chama indicadores personalizados; então, esta variável de escrita de código pode ser recomendada apenas para os mais preguiçosos! é claro que outro "líder" vem depois, mas um que se baseia em chamadas de indicadores técnicos tem resultados bem melhores, porém, são muito aquém do ideal.

O líder real dos testes é o indicador que é desenvolvido usando classes!

O híbrido, que usa classes e indicadores técnicos, fica em segundo lugar, mas não acontece sempre; se o tempo de teste de um indicador for crucial, então, é melhor verificar tais variáveis pessoalmente para cada situação.

Visão geral da implementação de classes de média

Algorítimo Nome da classe Nome do arquivo Troca ou início de barras confiáveis
após a aplicação de um algoritmo
Possibilidade de mudança
dinâmica do Comprimento do parâmetro
1 Média clássica CMoving_Average MASeries_Cls.mqh Length/0/Length/Length + 1 (SMA/EMA/SMMA/LWMA) não
2 Desvio Padrão CStdDeviation StdDevSeries_Cls.mqh Comprimento não
3 Suavização JMA CJJMA JJMASeries_Cls.mqh 30 sim
4 Suavização T3 CT3 T3Series_Cls.mqh 0 sim
5 Suavização ultralinear CJurX JurXSeries_Cls.mqh 0 sim
6 Suavização de Tushar Chande CCMO CMOSeries_Cls.mqh Comprimento + 1 não
7 Suavização de Kaufman CAMA AMASeries_Cls.mqh Comprimento + 3 não
8 Média parabólica CParMA ParMASeries_Cls.mqh Comprimento não
9 Velocidade de mudança CMomentum MomSeries_Cls.mqh Comprimento + 1 não
10 Velocidade de mudança normalizada CnMomentum nMomSeries_Cls.mqh Comprimento + 1 não
11 Taxa de mudança CROC ROCSeries_Cls.mqh Comprimento + 1 não

A classe descrita previamente CMoving_Average inclui cinco algoritmos de média.

A classe CCMO contém algoritmos de média e oscilador.

As outras classes incluem algoritmos únicos de média. A ideologia de uso de qualquer uma das classes sugeridas é absolutamente a mesma para o procedimento de uso da classe CMoving_Average descrita acima. O código de todos os algoritmos de média (exceto para a parabólica) é otimizado para a máxima velocidade de execução. O código da média parabólica não foi otimizado devido a complexidade deste processo. Os últimos três algoritmos não representam uma média. Eu os adicionei por causa de sua alta popularidade e compatibilidade com os trabalhos de analistas técnicos populares.

Para um fácil entendimento da informação, é melhor representar os algoritmos de média em aquivos .mqh separados; e para um uso prático, a melhor variável é tê-los em um único arquivo.

Para o uso em indicadores, todas as classes sugeridas são unidas em um único arquivo SmoothAlgorithms.mqh. Além disso, o arquivo é suplementado com as funções do arquivo iPriceSeries.mqh. Apenas a função PriceSeries() é usada nos exemplos deste artigo:

double PriceSeries
 (
  uint applied_price,  // Price constant
  uint   bar,          // Index of shift for a specified number of periods back or forward
                          // relatively to a current bar.
  const double& Open [],
  const double& Low  [],
  const double& High [],
  const double& Close[]
 )

Esta função é destinada ao trabalho com indicadores bases na utilização do segundo tipo de chamada da função OnCalculate().

A ideia principal da criação desta função é estender o conjunto de séries de tempo de preço da enumeração ENUM_APPLIED_PRICE com variáveis personalizadas. A função retorna o valor de uma série de tempo de preço por seu número que varia de 1 a 11.


4. Exemplos práticos de implementação de um código de programa utilizando as classes de média

Se for suficiente mostrar outro exemplo de utilização de outras classes, ter certeza que tudo foi feito da mesma forma que na média vezes quatro. Mostrarei uma variável de implementação da função OnCalculate() em um análogo do indicador CCI usando as classes CJJMA e CJurX (JCCX.mq5)

int OnCalculate(const int rates_total,       // amount of history in bars on a current tick
              const int prev_calculated,   // amount of history in bars on a previous tick
              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[]
             )
  {
//----+   
   //---- Checking whether there are enough bars for calculation
   if (rates_total < 0) return(0);
    
   //---- Declaration of variables  with floating point  
   double price_, jma, up_cci, dn_cci, up_jccx, dn_jccx, jccx;
   //----+ Declaration of integer variables
   int first, bar;
   
   //---- calculation of start number 'first' for the cycle of recalculation of bars
   if (prev_calculated == 0) // checking for the first start of calculation of indicator
        first = 0;           // starting number for calculation of all bars
   else first = prev_calculated - 1; // starting number for calculation of new bars
   
   //---- declaration of variables of the class CJurX from the file SmoothAlgorithms.mqh
   static CJurX Jur1, Jur2;
   //---- declaration of variables of the class CJMA from the file SmoothAlgorithms.mqh
   static CJJMA JMA;
   
   //---- Main cycle of calculation of the indicator
   for(bar = first; bar < rates_total; bar++)
    {
     //----+ Calling the PriceSeries function to get the input price price_
     price_ = PriceSeries(IPC, bar, open, low, high, close); 

     //----+ One call of the JJMASeries function to get JMA
     jma = JMA.JJMASeries(0, prev_calculated, rates_total, 0, JMAPhase, JMALength, price_, bar, false); 

     //----+ Determine the deviation of price from the value of JMA
     up_cci = price_ - jma;         
     dn_cci = MathAbs(up_cci);

     //----+ Two calls of the JurXSeries function.  
     up_jccx = Jur1.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, up_cci, bar, false);
     dn_jccx = Jur2.JurXSeries(30, prev_calculated, rates_total, 0, JurXLength, dn_cci, bar, false); 

     //---- Preventing zero divide in empty values
     if (dn_jccx == 0) jccx = EMPTY_VALUE;
     else
      {
       jccx = up_jccx / dn_jccx;
       
       //---- Limitation of the indicator from the top and from the bottom
       if (jccx > +1)jccx = +1;
       if (jccx < -1)jccx = -1;
      }

     //---- Loading the obtained value to the indicator buffer
     JCCX[bar] = jccx;
    }
//----+     
   return(rates_total);
  }

Fig.2 O indicador JCCX

Mas, desta vez, adicionei as classes adequadas de outro arquivo no escopo global no código do indicador.

#include <SmoothAlgorithms.mqh>

Agora, quero chamar sua atenção para outra coisa. A questão é que um grande número de indicadores pode ser representado como funções de uma barra, que é realmente confortável de trabalhar usando classes.

Por exemplo, pode ser interessante obter o canal Bollinger com base na média móvel Vidya de Tushar Chande. Neste caso, duas classes CCMO e CStdDeviation são usadas. Usando a primeira classe, obtemos o valor da média móvel VIDYA; e usando a segunda classe, calculamos o valor do desvio padrão da série de preço para a média móvel.

Na sequência, usamos este desvio para o cálculo do limite superior e inferior do canal:

//+------------------------------------------------------------------+
// Description of the classes CStdDeviation{}; and CCMO{};           | 
//+------------------------------------------------------------------+ 
#include <SmoothAlgorithms.mqh> 
//+==================================================================+
//|  The algorithm of getting the Bollinger channel from             |
//|  the moving average VIDYA                                        |
//+==================================================================+
class CVidyaBands
{
public:
  double VidyaBandsSeries(uint begin,                // number of the start of reliable calculation of bars
                         uint prev_calculated,      // amount of history on a previous tick in bars
                         uint rates_total,          // amount of history on a current tick in bars
                         int CMO_period,            // the period of averaging of the oscillator CMO
                         double EMA_period,         // the period of averaging of EMA
                         ENUM_MA_METHOD MA_Method, // the type of averaging
                         int BBLength,             // the period of averaging of the Bollinger channel
                         double deviation,          // Deviation
                         double series,             // Value of the price series calculated for a bar with the number 'bar'
                         uint bar,                  // Bar index
                         bool set,                  // Direction of indexing of arrays
                         double& DnMovSeries,       // Value of the lower border of the channel for a current bar
                         double& MovSeries,         // Value of the middle line of the channel for a current bar
                         double& UpMovSeries        // Value of the upper border of the channel for a current bar 
                        ) 
   {
//----+
    //----+ Calculation of the middle line    
    MovSeries = m_VIDYA.VIDYASeries(begin, prev_calculated, rates_total, 
                                    CMO_period, EMA_period, series, bar, set); 
    //----+ Calculation of the Bollinger channel
    double StdDev = m_STD.StdDevSeries(begin+CMO_period+1, prev_calculated, rates_total, 
                                      BBLength, deviation, series, MovSeries, bar, set);
    DnMovSeries = MovSeries - StdDev;
    UpMovSeries = MovSeries + StdDev;
//----+
    return(StdDev); 
   }

  protected:
    //---- declaration of variables of the classes CCMO and CStdDeviation
    CCMO           m_VIDYA;
    CStdDeviation  m_STD;
};

Então, temos uma classe simples e pequena!

Os últimos três parâmetros de entrada da função VidyaBandsSeries() passam os valores necessários do canal através de um link.

Gostaria de observar que, neste caso, você não pode declarar as variáveis das classes dentro da função VidyaBandsSeries() e torná-las estáticas, porque as variáveis estáticas em classes têm um significado bem diferente. Este é o motivo pelo qual esta declaração deve ser feita em escopo global da classe:

protected: 
  //---- declaration of variables of the classes CCMO and CStdDeviation 
  CCMO           m_VIDYA; 
  CStdDeviation  m_STD;

Em um canal Bollinger normal, o período da média da média móvel e o período da média do canal em si são sempre iguais.

Nesta classe, fiz estes parâmetros separados para lhe dar mais liberdade (EMA_period e BBLength). O indicador em si (VidyaBBands.mq5) feito com base nesta classe é tão simples em uso da classe CVidyaBands que não precisamos analisar seu código no artigo.

Tais classes das funções do indicador devem ser colocadas em um arquivo mqh separado. Coloquei tais funções no arquivo IndicatorsAlgorithms.mqh.

Fig.3 O indicador VidyaBBands


5. Comparando o desempenho de um indicador que usa classes com um que não usa

Primeiro de tudo, quero descobrir, como o uso de classes ao escrever um código de um indicador diminui seu desempenho?

Para este propósito, o código do indicador JJMA.mq5 foi escrito sem o uso de classes (JMA.mq5), depois, eu testei nas mesmas condições que durante o teste anterior. Os resultados finais dos teste não foram muito diferentes:

Fig.4 Os resultados do teste de indicadores JMA e JJMA

é claro que existe uma carga adicional no uso de classes, mas não é tão significante se comparando com as vantagens que elas fornecem.


6. Vantagens do uso de classes de média

Uma vantagem do uso destes algoritmos, que é realmente convincente, é que o posicionamento de chamadas de indicadores técnicos e personalizados leva a um grande aumento do desempenho do código desenvolvido descrito acima.

Outra vantagem prática de tais classes é uma grande conveniência de seu uso. Por exemplo, tudo que é descrito no popular livro de William Blau "Momentum, Direction and Divergence" parece ser um campo de teste real para este tipo de abordagem ao escrever indicadores. O código dos indicadores vem comprimido ao máximo, compreensível e geralmente consistindo em um único ciclo de recálculo de barras.

Você pode facilmente desenvolver qualquer indicador - um clássico ou técnico, usando os métodos alternativos de média. Uma variedade bastante ampla de algorítimos de média fornece grandes possibilidades para criar sistemas de negócio não tradicionais, geralmente com uma detecção precoce de tendências e um número menor de acionamento falso.


7. Algumas recomendações sobre o uso de algoritmos de média em um código de indicador específico

Uma única olhada rápida em qualquer indicador desenvolvido usando diferentes algoritmos de média descrito aqui é o suficiente para entender quão diferentes são esses algoritmos.

Fig. 5 As médias móveis que usam diferentes algoritmos de média

Então, seria razoável supor que nem todos os algoritmos sugeridos são igualmente bons em qualquer situação. Apesar de que possa ser difícil determinar um limite estrito de uso de um ou outro algoritmo, é possível fornecer a você algumas recomendações gerais do uso deles.

Por exemplo, os algoritmos de Tushar Chande e Kaufman são destinados a determinar situações de tendência e não são adequados para suavização adicional para o propósito de filtragem de ruído. Então, é melhor colocar suas séries de preço não processadas ou valores de indicador sem média para estes algoritmos. Aqui está o resultado do processamento de valores do indicador Momentum usando o algoritmo de Kaufman (o indicador 4c_Momentum_AMA.mq5)

Fig.6 O resultado do processamento de valores do indicador Momentum usando o algoritmo de Kaufman

Eu acho que os algoritmos de média clássica não precisam de nenhuma recomendação especial. A área de aplicação deles é bastante ampla. Em todo lugar, onde estes algoritmos são usados, você pode com sucesso usar os quatro algoritmos restantes (JMA, T3, ultralinear e parabólico). Aqui está um exemplo do indicador MACD onde EMA e SMA são substituídos com a média JMA (o indicador JMACD.mq5):

Fig.7 O gráfico MACD usando a média JMA

E aqui está o resultado de suavização do indicador calculado em vez de mudar seu algoritmo de média para uma melhor qualidade de determinação da tendência atual (o indicador JMomentum.mq5):

Fig.8 O resultado da suavização JMA do indicador Momentum

Não é surpresa que o comportamento dos mercados muda constantemente; por isso, seria ingenuidade pensar que você pode encontrar aquele único algoritmo ideal para uma determinada parte do mercado financeiro para hoje e sempre! Ah! Nada neste mundo dura para sempre. Apesar disso, para mim, por exemplo, neste mercado de mudanças eternas, geralmente uso os indicadores de tendências de prazo médio e rápido como JFATL.mq5 e J2JMA.mq5. Estou bastante satisfeito com as predições com base neles.

Outra coisa que quero acrescentar. Os algoritmos de média são reutilizáveis. Bons resultados podem ser obtidos ao aplicar médias repetidas em valores em que já foi feita a média. Na realidade, neste artigo, começo analisando o processo de esboço de indicador a partir disso (o indicador MAx4.mq5).


8. A ideia geral de composição de código dos algoritmos de média

E agora, no final do artigo, gostaria que você prestasse atenção ao mecanismo das funções de média em si.

Primeiramente, a maioria dos algoritmos de média inclui arrays dinâmicos de variáveis do tipo m_SeriesArray[] para armazenar os valores do parâmetro de entrada 'series'.

Assim que a informação relevante para o cálculo aparece, você deve alocar a memória para tal array para uma vez. Isso é feito usando a função SeriesArrayResize() da classe CMovSeriesTools.

//----+ Changing the size of the array of variables
if(bar==begin && !SeriesArrayResize(__FUNCTION__, Length, m_SeriesArray, m_Size_))
   return(EMPTY_VALUE);

Depois, em cada barra, você deve escrever o valor atual da série de preço 'series' para o valor mais antigo do array e memorizar o número de sua posição na variável m_count. Isso é feito usando a função Recount_ArrayZeroPos() da classe CMovSeriesTools.

//----+ transposition and initialization of cells of the array m_SeriesArray 
Recount_ArrayZeroPos(m_count, Length_, prev_calculated, series, bar, m_SeriesArray);

E agora, se precisarmos encontrar um elemento com uma troca relativa ao elemento atual, devemos usar a função Recount_ArrayNumber() da classe CMovSeriesTools:

for(iii=1; iii<=Length; iii++, rrr--)
   {
    kkk = Recount_ArrayNumber(m_count, Length_, iii);
    m_sum += m_SeriesArray[kkk] * rrr;
    m_lsum += m_SeriesArray[kkk];
    m_weight += iii;
   }

Geralmente, em tais situações, o elemento mais novo é escrito para a posição zero e os outros (exceto o mais velho) são sobrescritos preliminarmente para a próxima posição por vez; porém, não economiza recursos do computador, e quanto mais complexa a abordagem acima parece ser, mais racional!

Além dos algoritmos de média, os corpos destas funções contém as chamadas de funções usadas para determinação das posições de barra relativamente ao começo do cálculo das barras:

//----+ Checking the start of reliable calculation of bars
if(BarCheck1(begin, bar, set)) return(EMPTY_VALUE);

o momento em que há informações o suficiente para iniciar a inicialização das variáveis:

//----+ Initialization of zero
if(BarCheck2(begin, bar, set, Length))

e situações quando a última barra é fechada:

//----+ Saving values of the variables 
if(BarCheck4(rates_total, bar, set))

ou não fechada:

//----+ Restoring values of the variables
if(BarCheck5(rates_total, bar, set))

A primeira verificação determina uma situação quando não existem barras suficientes para a função de média, e retorna um resultado vazio. Uma vez que a segunda verificação é passada com sucesso e existem dados suficientes para o primeiro cálculo, a inicialização das variáveis é realizada para uma vez. Duas verificações finais são necessárias para o processamento correto múltiplo dos valores sobre a barra não fechada atual. Já descrevi no meu artigo dedicado a otimização de um código de programa.

E, agora, algumas palavras sobre a otimização do códio do programa de tais funções para um máximo desempenho. Por exemplo, o algoritmo SMA implica a média dos valores selecionados de um período de uma série de preço em cada barra. Estes valores são literalmente somados e divididos pelo período em cada barra.

Mas, a diferença entre a soma na barra anterior e a soma na barra atual é que a primeira é somada com o valor da série de preço com uma troca em um período relativamente ao período atual e o segundo - com o valor atual. Então, seria muito mais racional calcular tal soma apenas uma vez durante a inicialização das funções, e depois em cada barra adicionar apenas os novos valores das séries de preço a esta soma e diminuir os valores antigos dela. Exatamente isso é feito em tal função.


Conclusão

As implementações de algoritmos de média sugeridas no arquivo usando as classes são simples, tipo único e tipo universal, então você não terá problemas para estudá-las.

Os arquivos anexos ao artigo contém muitos exemplos para facilitar o entendimento desta abordagem para escrita de código de indicadores. No arquivo Include_en.zip, todas as classes estão distribuídas em arquivos. O arquivo Include_en.zip contém apenas dois arquivos que são suficientes para compilar todos os indicadores no arquivo Indicators.zip. Os Expert Advisors para teste estão no arquivo Experts.zip.

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

Arquivos anexados |
experts-en.zip (3.88 KB)
include__en.zip (40.84 KB)
include-en.zip (17.82 KB)
indicators_en.zip (90.93 KB)
Construindo um Analisador de Espectro Construindo um Analisador de Espectro
Este artigo é destinado a familiarizar seus leitores com uma possível variável de uso de objetos gráficos da linguagem MQL5. Ele analisa um indicador que implementa um painel de gerenciamento de um simples analisador de espectro usando objetos gráficos. O artigo é destinado para leitores familiarizados com o básico do MQL5.
Crie seu próprio Market Watch usando as classes da biblioteca padrão Crie seu próprio Market Watch usando as classes da biblioteca padrão
O novo terminal do cliente do MetaTrader 5 e a linguagem MQL5 fornece novas oportunidades para apresentar informações visuais para o negociante. Neste artigo, propomos um conjunto de classes extensível e universal, que lida com todo o trabalho de organização de exibição da informação de texto arbitrária no gráfico. é apresentado o exemplo do indicador Maket Watch.
Indicadores de William Blau e sistemas de comércio no MQL5. Parte 1: Indicadores Indicadores de William Blau e sistemas de comércio no MQL5. Parte 1: Indicadores
O artigo apresenta os indicadores descritos no livro de William Blau "Momentum, Direction, and Divergence". A abordagem de William Blau nos permite prontamente e precisamente aproximar as flutuações da curva de preço, para determinar a tendência de movimentos de preço e os pontos de virada e eliminar o ruído de preço. Entretanto, também somos capazes de detectar estados de excesso de compra ou venda do mercado e sinais indicando o fim da tendência e reverso do movimento de preço.
O exemplo simples da criação de um indicador utilizando a lógica Fuzzy O exemplo simples da criação de um indicador utilizando a lógica Fuzzy
O artigo dedica-se à aplicação prática do conceito da lógica fuzzy para análise de mercados financeiros. Propomos o exemplo dos sinais de geração de indicador com base em duas regras fuzzy baseadas no indicador Envelopes. O indicador desenvolvido usa diversos buffers de indicador: 7 buffers para cálculo, 5 buffers para a exibição dos gráficos e 2 buffers de cor.