Tratamento de eventos no MQL5: mudando período MA rapidamente

31 dezembro 2013, 11:26
Sceptic Philozoff
0
1 134

Introdução

Este pequeno artigo é dedicado a um dos novos recursos do MQL5 da plataforma MetaTrader 5, desenvolvida pela MetaQuotes Software Corp. Possivelmente este artigo esteja um pouco atrasado (deveria ter sido emitido em setembro-outubro de 2009 - então seria oportuno), mas não havia artigos semelhantes sobre este tema. Além disso, naquela época, não existiam essas possibilidades de manipulação de eventos nos indicadores.

Imagine que temos um indicador de preços simples aplicado a um gráfico (neste caso é a média móvel, ou seja MA), e nós queremos mudar o seu período de suavização. Na plataforma MT4 nós tínhamos as seguintes opções:

  • No MetaEditor é possível editar o parâmetro de entrada de expert (externo), responsável pelo período MA, e depois compilar o arquivo fonte.
  • Sem alternar para o MetaEditor, exatamente na janela do terminal, você pode abrir a caixa de diálogo propriedades do indicador e editar o parâmetro de entrada correspondente.
  • Você pode abrir a biblioteca Win32 API, encontrar as funções de captura de mensagens, e em seguida, ajustar o código indicador de modo que ele responda a eventos do teclado.

Como sabemos, o desejo para o mínimo esforço é o maior motor de progresso. Agora, graças a uma nova plataforma MT5 que permite indicadores de manipulação e de eventos iniciados pelo usuário, podemos pular as possibilidades acima e alterar os parâmetros do indicador pressionando apenas uma única tecla. Este artigo aborda a implementação técnica desta solução do problema.

Atribuição de tarefas e problemas

O código-fonte indicador, usado em nossos experimentos, acompanha o Client Terminal. O arquivo de código-fonte inalterado (Custom Moving Average.mq5) está anexo no final deste artigo.

Por enquanto não vamos analisar o código-fonte e, especialmente, as mudanças em relação ao seu MQL4 original. Sim, em alguns lugares ele mudou de forma significativa, e isso nem sempre é óbvio. Explicações correspondentes, relativas à reestruturação da parte de base de cálculo, podem ser encontradas no fórum e na ajuda online.

No entanto, a parte principal do indicador no MQL4 permaneceu inalterada. Pelo menos 80% de todas as alterações no código, destinadas a resolver o nosso problema, foram feitas com base na ideia de funções computacionais do indicador como as "caixas pretas".

Um exemplo do que queremos alcançar é assim: suponha que nós aplicamos este indicador a um gráfico e, em um determinado momento, ele exibe um MA exponencial (EMA) com mudança zero e período de 10. Nosso objetivo é aumentar o período de suavização de MA simples (SMA) para 3 (até 13), e transferí-lo em 5 barras para a direita. A sequência de ação assumida é a seguinte:

  • Pressionando a tecla TAB algumas vezes para mudar o MA exibido a partir exponencial para simples (mudança do tipo MA).
  • Pressionando a tecla seta UP na parte principal do teclado três vezes para aumentar o período de MA simples por 3.
  • Pressionando a seta UP (8) no teclado numérico 5 vezes para compensar MA por 5 barras para a direita.

A primeira, e a solução mais óbvia, é introduzir a função OnChartEvent() no código do indicador e escrever o handler de evento de teclas. De acordo com a lista de mudanças no MetaTrader 4 Client Terminal builds 245 e 246 https://www.mql5.com/en/forum/53/page1/#comment_2655.

MetaTrader 5 Client Terminal builds 245 e 246

...

MQL5: Adicionado a possibilidade de manipulação de eventos por meio de indicadores personalizados, semelhante a por Expert Advisors.

Então, agora não temos problemas com a adição de novos handlers de eventos no indicador. Mas, para isso, nós ainda temos que modificar um pouco o seu código.

Primeiro, no MQL5 o status dos parâmetros externos do indicador mudou: você não pode modificá-lo no código. O único modo de mudar é através da caixa de diálogo Propriedades no Client Terminal. Em geral, na necessidade urgente de mudá-los, esta restrição é facilmente contornada: basta copiar os valores dos parâmetros externos em novas variáveis ​globais do indicador e todos os cálculos são feitos como se essas novas variáveis são realmente parâmetros externos do indicador. Por outro lado, neste caso, desaparece a viabilidade de parâmetros externos, cujos valores só podem confundir os usuários. Agora esses parâmetros são simplesmente inúteis.

Assim, não há parâmetros externos (entrada) no indicador. As variáveis ​que desempenham o papel de parâmetros externos, agora serão Terminal Global Variables (Variáveis globais terminais) ou TGV, para simplificar. Se você quiser ver a TGV, responsável pelos antigos parâmetros externos do indicador, você pode simplesmente pressionar a tecla F3 no terminal. Não consigo encontrar outra maneira simples de controlar os parâmetros do indicador.

Segundo (e isto é importante), em qualquer alteração nos parâmetros externos do indicador temos que recalcular todos os seus valores em todo histórico novamente e a partir do zero. Em outras palavras, nós vamos ter que fazer cálculos, que geralmente são feitos apenas no início do indicador. A otimização dos cálculos do indicador permanece, mas agora torna-se mais sutil.

Várias partes de código da primeira versão do indicador modificado estão listadas abaixo. O código completo está anexado no final deste artigo.

Versão "Standard": a descrição das alterações no código-fonte do indicador padrão

Parâmetros externos não são mais externos, mas simples variáveis globais.

Todos os parâmetros externos do indicador perderam o modificador de entrada. Geralmente, eu não poderia mesmo torná-los globais, mas decidi fazer pela tradição:

int              MA_Period   = 13;
int              MA_Shift    =  0;
ENUM_MA_METHOD   MA_Method   =  0;
int              Updated     =  0;     /// Indicates whether the indicator has updated after changing it's values

As três primeiras opções - são o período, o deslocamento e o tipo de MA, e a quarta - Updated (Atualizado) - é responsável pela otimização de cálculos ao alterar os parâmetros MA. Explicações estão algumas linhas abaixo.

Códigos para chaves virtuais

Insira os códigos para as chaves virtuais:

#define KEY_UP             38
#define KEY_DOWN           40
#define KEY_NUMLOCK_DOWN   98
#define KEY_NUMLOCK_UP    104
#define KEY_TAB             9

Estes são os códigos de "seta para cima" e "para baixo", setas semelhantes no teclado numérico (número "8" e "2"), bem como a tecla TAB. Os mesmos códigos (com outros nomes de constantes VK_XXX ) realmente existem no arquivo \ MQL5 \ Include \ VirtualKeys.mqh mas, neste caso, eu decidi deixar assim.


Pequena correção no código na função, cálculo de média móvel ponderada (LWMA)

Eu fiz um pequeno ajuste na função CalculateLWMA (): na versão original a variável weightsum foi declarada usando o modificador estático. Aparentemente, a única razão pela qual os desenvolvedores fizeram isso foi a necessidade de pré-calcular na primeira chamada desta função. Além disso, no código desta variável ainda permanece inalterado. Aqui está o código original desta função, no qual as partes relacionadas ao uso do cálculo e weightsum são marcadas com os comentários:

void CalculateLWMA(int rates_total,int prev_calculated,int begin,const double &price[])
  {
   int              i,limit;
   static int     weightsum;                       // <-- using weightsum
   double               sum;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)                          // <-- using weightsum
     {
      weightsum=0;                                 // <-- using  weightsum
      limit=InpMAPeriod+begin;                     // <-- using weightsum
      //--- set empty value for first limit bars
      for(i=0;i<limit;i++) extlinebuffer[i]="0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++) // <-- using weightsum
        {
         int k=i-begin+1;                          // <-- using weightsum
         weightsum+=k;                             // <-- using weightsum
         firstValue+=k*price[i];
        }
      firstValue/=(double)weightsum;
      ExtLineBuffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++) {="" sum="0;
      for(int j=0;j<inpmaperiod;j++) sum+="(InpMAPeriod-j)*price[i-j];" extlinebuffer[i]="sum/weightsum;" <--="" using weightsum
      }
//---
  }

Anteriormente, esta variável funcionava muito bem, mas quando eu executei o "indicador + advisor" em conjunto (isto é mencionado no final deste artigo), neste mesmo tipo de MA tive problemas. O principal deles foi causado por circunstâncias descritas acima, ou seja weightsum foi a variável estática: esta variável foi aumentando constantemente em cada mudança de parâmetro MA rapidamente, foi necessário recalcular a partir do zero.

A maneira mais fácil e direta é imediatamente calcular o valor weightsum (que é igual a soma dos números inteiros de 1 ao período MA - para este fim existe uma fórmula simples para a soma de progressão aritmética), e, ao mesmo tempo, negar o seu estado como estático, o que eu fiz. Agora, em vez da declaração weightsum anterior usando o modificador estático, nós o declaramos sem ele, apenas inicialize com o valor "correto" e, assim, remova o circuito inicial de "acúmulo de variável".

int weightsum = MA_Period *( MA_Period + 1 ) / 2;

Agora, tudo funciona corretamente.


Função OnCalculate() como um handler

Eu tive que fazer uma série de mudanças na função OnCalculate() e, portanto, cito aqui o seu código completo.

int OnCalculate(const int rates_total,
                const int prev_calculated,            /// Mathemat: full recalculation!
                const int begin,                      /// Mathemat: full recalculation!
                const double &price[])
  {
//--- check for bars count
   if(rates_total<ma_period-1+begin)
      return(0);// not enough bars for calculation
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
      ArrayInitialize(LineBuffer,0);
//--- sets first bar from what index will be draw
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,MA_Period-1+begin);

//--- calculation (Mthmt - optimized by Mathemat)

   if( GlobalVariableGet( "Updated" ) == 1 )
   {
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,prev_calculated,begin,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,prev_calculated,begin,price);
   }
   else
   {
      OnInit( );                 /// Mthmt
      if(MA_Method==MODE_EMA)  CalculateEMA(       rates_total,0,0,price);
      if(MA_Method==MODE_LWMA) CalculateLWMA_Mthmt(rates_total,0,0,price);
      if(MA_Method==MODE_SMMA) CalculateSmoothedMA(rates_total,0,0,price);
      if(MA_Method==MODE_SMA)  CalculateSimpleMA(  rates_total,0,0,price);
      GlobalVariableSet( "Updated", 1 );
      Updated = 1;
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+</ma_period-

A principal mudança refere-se à percepção da necessidade de cálculo completo do indicador "do zero": é óbvio que, se a manipulação do teclado do usuário mudou no período MA 13-14, todas as otimizações anteriores de seus cálculos já são inúteis, e nós temos que calcular o MA novamente. Isso ocorre quando a variável Updated tem valor 0 (TGV mudou depois de pressionar a tecla de atalho, mas o tick, que redesenha o indicador, não chegou ainda).

No entanto, além disso, já temos que chamar explicitamente a função OnInit() porque precisávamos mudar o nome curto do indicador, que será exibido quando o cursor passar sobre a linha. Após o cálculo inicial MA o TGV Updated é definido como 1, o que abre o caminho para o cálculo de indicador otimizado - até que, novamente, você não terá que alterar o parâmetro de algum indicador rapidamente.


Handler OnChartEvent()

Abaixo está um simples código do handler OnChartEvent():

void OnChartEvent( const int          id,
                   const long    &lparam,
                   const double  &dparam,
                   const string  &sparam )
{
   if( id == CHARTEVENT_KEYDOWN )
      switch( lparam )
      {
         case( KEY_TAB          ):  changeTerminalGlobalVar( "MA_Method",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_UP           ):  changeTerminalGlobalVar( "MA_Period",  1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_DOWN         ):  changeTerminalGlobalVar( "MA_Period", -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         
         case( KEY_NUMLOCK_UP   ):  changeTerminalGlobalVar( "MA_Shift",   1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
         case( KEY_NUMLOCK_DOWN ):  changeTerminalGlobalVar( "MA_Shift",  -1 ); 
                                    GlobalVariableSet( "Updated",  0 );
                                    Updated = 0;
                                    break;
      }
      
      return;
}//+------------------------------------------------------------------+      

O handler funciona da seguinte maneira: você pressiona a tecla de atalho, o código virtual é definido, e, em seguida, a função auxiliar changeTerminal Global Var() é iniciada e está corretamente modificando o TGV desejado. Depois disso, a bandeira Updated é resetada a zero, esperando por um tick que vai ativar a função OnCalculate() e redesenhar o indicador "do zero".


Função auxiliar, que "corretamente" muda o TGV

E, finalmente, o código da função changeTerminalGlobalVar() usada no handler OnChartEvent():

void changeTerminalGlobalVar( string name, int dir = 0 )
{
   int var = GlobalVariableGet( name );
   int newparam = var + dir;
   if( name == "MA_Period" )
   {
      if( newparam > 0 )       /// Possible period is valid for MA
      {
         GlobalVariableSet( name, newparam ); 
         MA_Period = newparam;     /// Don't forget to change the global variable    
      }   
      else                       /// we do not change the period, because MA period is equal to 1 minimum
      {   
         GlobalVariableSet( name, 1 );     
         MA_Period = 1;     /// Don't forget to change the global variable 
      }   
   }   
      
   if( name == "MA_Method" )    /// Here when you call the 'dir' it is always equal to 1, the dir value is not important    
   {
      newparam = ( var + 1 ) % 4;
      GlobalVariableSet( name, newparam );  
      MA_Method = newparam;
   }      

   if( name == "MA_Shift" )
   {
      GlobalVariableSet( name, newparam );     
      MA_Shift = newparam;
   }      

   ChartRedraw( );
   return;
}//+------------------------------------------------------------------+

O principal objetivo desta função - o cálculo correto de novos parâmetros MA levando em conta "limitações físicas". Obviamente, não se pode tornar o período MA inferior a 1, o deslocamento MA pode ser aleatório, mas o tipo de MA é o número de 0 a 3, correspondendo a um número de membro condicional na enumeração ENUM_MA_METHOD.

Conferindo funciona, mas "na grade C". O que podemos fazer?

OK, vamos aplicar o nosso indicador ao gráfico e começar a esporadicamente pressionar as teclas de atalho que mudam os parâmetros MA. Sim, tudo funciona corretamente, mas há um fato desagradável: os TGVs estão mudando imediatamente (você pode verificar isso chamando o TGV usando a tecla F3), mas o MA não está redesenhando sempre imediatamente, mas apenas na chegada de um novo tick. Se tivermos uma sessão americana com o fluxo de ticks ativo, então, dificilmente podemos notar o atraso. Mas se isso acontece à noite, durante período calmo, podemos esperar o redesenho por vários minutos. E aí?

Bem, como dizem, o que escrevemos é o que temos. Antes do built 245 em indicadores havia apenas um "ponto de entrada" - a função OnCalculate(). Claro, eu não estou falando de funções OnInit() e OnDeinit() que fornecem cálculos iniciais do indicador, a inicialização e finalização. Agora, existem vários pontos de entrada e estão ligados com o novo Timer e eventos ChartEvent.

No entanto, os novos handlers estão fazendo apenas o que incluem, não estão formalmente associados ao handler OnCalculate(). Então, o que podemos fazer com nosso handler OnChartEvent() "alien" para fazer o trabalho "certo", ou seja, permitiria redesenhar de imediato MA?

Em geral, existem várias maneiras de implementar este requisito:

  • "Matryoshka" (chamada OnCalculate() dentro de OnChartEvent()): insira a chamada da função OnCalculate() neste handler, pré-preenchendo todos os seus parâmetros. Como o handler OnChartEvent() implica mudar pelo menos um parâmetro MA, então, ele vai afetar todo o histórico, ou seja, devemos recalcular novamente, "a partir do zero", sem a otimização dos cálculos.
  • "Tick artificial" que transfere o controle para o início da função OnCalculate() que modifica o buffer gráfico. Aparentemente, não existem métodos "legítimos", como refletido na documentação MT5 (embora, talvez, eu não tenha procurado tão bem). Se você estiver interessado pode procurar algo como «API», «PostMessageA», etc. Portanto, não vamos considerar esta variante aqui, porque não garante que os recursos não documentados algum dia não venham a mudar. Eu não tenho nenhuma dúvida de que isso possa ser realizado.

"Matryoshka" funciona!

Acontece que nós já fizemos a coisa mais importante. Abaixo está um código muito simples da função. Você pode simplesmente colocar sua chamada diretamente na frente do operador return do handler OnChartEvent().

int OnCalculate_Void()
{
   const int rates_total = Bars( _Symbol, PERIOD_CURRENT );
   CopyClose( _Symbol, PERIOD_CURRENT, 0, rates_total, _price );
   OnCalculate( rates_total, 0, 0, _price );
   return( 1 );
}//+------------------------------------------------------------------+

Após a compilação do indicador e aplicá-lo ao gráfico, vemos que, em geral, o código funciona de forma rápida e independente da chegada de ticks.

A desvantagem desta implementação é que exatamente os preços de Fechamento sejam copiados no array price[]. Se desejar, a função CopyClose() pode ser substituída com o que queremos, definindo o campo "Aplicar" na guia "Configurações" da caixa de diálogo Propriedades do indicador. Se o preço atual for básico (Open (Abrir), High (Alto), Low (Baixo), Close (Fechar)), então já temos a função CopyXXXX() correspondente. No caso dos preços mais complicados (mediana, típica ou ponderada), temos que calcular o array de maneira diferente.

Eu não tenho certeza se nós não precisamos da função CopyClose() que copia todo o histórico do array. Por outro lado, esta função é suficientemente rápida quando o histórico não está muito profundamente carregado. Verificando o indicador no EURUSD H1 com histórico antes de 1999 (cerca de 700 mil barras) mostrou que o indicador lida com cálculos e não mostra qualquer desaceleração. Em tal histórico as possíveis desacelerações podem ser causadas não pela função CopyXXXX(), mas pela necessidade de recálculos mais complicados do indicador desde o início do histórico (isto é obrigatório).


Vários resultados e conclusões

O que é melhor - um arquivo indicador ou "indicador + advisor" combinados?

De fato, essa questão não é tão simples. Por um lado, é bom que tenhamos um arquivo indicador, porque todas as funções, incluindo handlers de evento, estão concentradas em um só lugar.

Por outro lado, vamos imaginar que há três ou quatro indicadores aplicados ao gráfico, juntamente com um Expert Advisor - esta situação não é incomum. Além disso, presuma que cada indicador esteja equipado com o seu próprio handler de eventos, além da função OnCalculate() padrão. Para evitar confusão com os eventos processando nesta "desordem" é mais razoável concentrar todos os handlers de eventos, agora permitidos nos indicadores, em um só lugar - no Expert Advisor.

Por muito tempo os desenvolvedores de software têm decido nos fornecer a capacidade de processar eventos no indicador: a partir do release beta não público de 09.09.09 (quando o indicador é considerado como "puro cálculo e entidade matemática" e não deve ser contaminado por quaisquer características que dificultem a velocidade de cálculo) passaram-se exatamente 5 meses. Provavelmente, a "pureza de ideia" tem que sofrer - e agora alguns dos caos das fantasias dos programadores serão desencadeados. Mas o equilíbrio é sempre em algum lugar no meio entre a ideia pura, mas limitada, e não muito clara, mas uma capacidade mais poderosa.

Em setembro-outubro de 2009, quando o número da built da versão beta do MT5 nem sequer chegou a 200, eu escrevi e depurei o código de "Expert Advisor + Indicador" combinados, que permitiu gerenciar parâmetros MA rapidamente, mas "na classe C": ele foi atualizado somente após a chegada do tick, mas não imediatamente. Naquela época, este conjunto era a única solução possível e, agora, provavelmente, não é mais interessante para ninguém.

Eu não poderia, então, pensar em como trazer a funcionalidade do indicador para a "grade B", ou seja, como é apresentado na versão mais recente. Agora tenho o prazer de fornecer a solução mais conveniente para todos a quem possa interessar.


Vídeo demonstração da "Matryoshka"

Em anexo meu curto filme, demonstrando o trabalho da nossa criação. Mudança suave da curva MA (apenas o período está mudando - primeiro aumenta, depois diminui) é mesmo fascinante de alguma forma. Este é o Matryoshka (de forma semelhante ao famoso jogo russo de bonecas).


Claro que, tais truques são úteis apenas quando o cálculo do indicador em si do zero não leva muito tempo. O MA simples, contido neste indicador, cumpre este requisito.


Um aspecto instável

Lembre-se, que os antigos parâmetros externos do indicador são agora as variáveis ​globais de terminal (TGV), que você pode ver pressionando a tecla F3. Suponha que você abriu a caixa de diálogo Variáveis globais e mudou um dos TGVs (por exemplo, o período MA). Você espera que esta alteração seja imediatamente refletida no indicador no gráfico.

Atualmente, no terminal não há nenhum evento correspondente à edição TGV feita pelo usuário (por exemplo, CHARTEVENT_GLOBALVAR_ENDEDIT). Além disso, eu acho que não podemos desativar modificação TGV na caixa de diálogo Variáveis globais. Portanto, aqui não podemos contar com qualquer evento, exceto o tick. O que acontecerá realmente?

Se você não tocar no teclado, então mesmo no próximo tick a atualização estará "errada": a variável Updated (Atualizada) não foi definida como zero e, portanto, apenas o cálculo "otimizado" do indicador (correspondente ao valor anterior do TGV mudado) será feito. Neste caso, para restabelecer a justiça, podemos aconselhar apenas uma coisa: depois de editar o TGV você deve, pelo menos uma vez, pressionar a tecla de atalho que modifica o TGV, definir a atualização = 0 e fazer o recálculo completo do indicador.

Todos os possíveis usuários e desenvolvedores devem ter isso em mente.


Arquivos anexados do código-fonte e vídeo

Finalmente, estou anexando os arquivos de código-fonte. Explicação:

  1. Custom Moving Average.mq5 - arquivo de código fonte MA, que é fornecido com MT5.
  2. MyMA_ind_with_ChartEvent.mq5 - implementação inicial ("grade C"): indicador atualiza somente após a chegada do tick.
  3. MyMA_ind_with_ChartEvent_Matryoshka.mq5 - a segunda (talvez, "grade B") variável: o indicador atualiza imediatamente, sem esperar pela chegada do tick.

Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/39

MQL5: análise e processamento dos relatórios Commodity Futures Trading Commission (CFTC) no MetaTrader 5 MQL5: análise e processamento dos relatórios Commodity Futures Trading Commission (CFTC) no MetaTrader 5

Neste artigo, desenvolverei uma ferramenta para análise de relatório CFTC. Resolveremos o seguinte problema: desenvolver um indicador que permita usar os dados do relatório CFTC diretamente dos arquivos de dados fornecidos pela Comissão sem conversão e processamento intermediários. Além disso, ele pode ser utilizado para diferentes propósitos: organizar dados como um indicador, prosseguir com os dados em outros indicadores, em scripts para análise automatizada, em Expert Advisors para uso em estratégias de trading.

Implementação prática dos filtros digitais no MQL5 para principiantes Implementação prática dos filtros digitais no MQL5 para principiantes

A ideia da filtragem de sinal digital foi amplamente discutida em tópicos de fóruns sobre a construção dos sistemas de negócio. E seria imprudente não criar um código padrão de filtros digitais no MQL5. Neste artigo, o autor descreve a transformação de um simples código do indicador SMA em seu artigo "Indicadores personalizados no MQL5 para iniciantes" em um código do mais complicado e universal filtro digital. Este artigo é uma sequência lógica do artigo anterior. Ele também fala como substituir o texto no código e como corrigir erros de programação.

Criando um indicador com opções de controle gráfico Criando um indicador com opções de controle gráfico

Aqueles que são familiares com os sentimentos do mercado, conhecem o indicador MACD (seu nome completo é convergência/divergência de média móvel) - a poderosa ferramenta para analisar o movimento de preço, usada por negociantes desde os primeiros momentos do aparecimento dos métodos de análise computacionais. Neste artigo, consideraremos possíveis modificações do MACD e o implementaremos no indicador com a possibilidade de mudar graficamente entre as modificações.

Interação entre o MetaTrader 5 e MATLAB Interação entre o MetaTrader 5 e MATLAB

Este artigo cobre os detalhes da interação entre o MetaTrader 5 e o pacote matemático MatLab. Ele mostra o mecanismo da conversão de dados, o processo de desenvolvimento de uma biblioteca universal para interagir com o desktop MatLab. Ele também cobre o uso do DLL gerado pelo ambiente MatLab. Este artigo é destinado a leitores experientes que conhecem C++ e MQL5.