English Русский 中文 Español Deutsch 日本語
preview
Técnicas do MQL5 Wizard que você deve saber (Parte 59): Aprendizado por Reforço (DDPG) com Padrões da Média Móvel e do Oscilador Estocástico

Técnicas do MQL5 Wizard que você deve saber (Parte 59): Aprendizado por Reforço (DDPG) com Padrões da Média Móvel e do Oscilador Estocástico

MetaTrader 5Sistemas de negociação |
16 0
Stephen Njuki
Stephen Njuki

Introdução

No último artigo, introduzimos o DDPG, um algoritmo de aprendizado por reforço, e analisamos 3 de suas classes cruciais conforme implementadas em Python. A classe de buffer de replay, a classe da rede ator e a classe da rede crítica. O que não foi abordado foi a classe agente DDPG; a importação de dados de preços do MetaTrader 5 para o Python; funções para a Média Móvel e o Oscilador Estocástico; uma função get-pattern para reunir dados dos dois indicadores em um vetor binário de entrada para a rede de aprendizado supervisionado (implementada no artigo anterior sobre aprendizado supervisionado via MQL5); e, por fim, um loop de simulação de ambiente para treinar as redes ator e crítica.

Tudo isso faz parte do Aprendizado por Reforço (RL), que estamos analisando como uma transição entre o Aprendizado Supervisionado (SL) e o Aprendizado por inferência (IL), no sentido aqui adotado de aprendizado não supervisionado Qualquer um desses modos pode ser utilizado individualmente para treinar e usar um modelo, porém estes artigos procuram defender a ideia de que eles podem ser usados em conjunto para construir algo mais interessante. Portanto, continuamos nossa análise do RL abordando a importantíssima classe Agente DDPG.



Agente DDPG

A arquitetura principal e a inicialização desta classe podem ser definidas da seguinte forma:

def __init__(self, state_dim, action_dim):

    # Actor networks
    self.actor = Actor(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.actor_target = Actor(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.actor_target.load_state_dict(self.actor.state_dict())
    self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=LR_ACTOR)
   
    # Critic networks  
    self.critic = Critic(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.critic_target = Critic(state_dim, action_dim, HIDDEN_DIM).to(device)
    self.critic_target.load_state_dict(self.critic.state_dict())
    self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=LR_CRITIC)

    self.replay_buffer = ReplayBuffer(BUFFER_SIZE)

Os componentes críticos aqui são a arquitetura de rede dupla, a configuração dos otimizadores e o gerenciamento de experiências. A arquitetura dupla mantém uma política separada (rede ator) e um valor separado (rede crítica) das duas redes principais de política e valor. Ela implementa redes-alvo para ambas, o que é importante para a estabilidade durante o treinamento. A inicialização dos respectivos alvos é realizada com os mesmos pesos de suas redes principais.

A configuração dos otimizadores apresenta otimizadores Adam separados para as redes ator e crítica. Além disso, como normalmente ocorre, utilizamos taxas de aprendizado separadas para as redes de política e de valor. Por fim, no gerenciamento de experiências, garantimos que o buffer de replay armazene transições para aprendizado off-policy e, ao fixar o tamanho do buffer, evitamos o uso ilimitado de memória. Selecionamos ações incorporando exploração da seguinte forma:

def select_action(self, state, noise_scale=0.1):
    state = torch.FloatTensor(state).unsqueeze(0).to(device)
    action = self.actor(state).cpu().data.numpy().flatten()
    action += noise_scale * np.random.randn(self.action_dim)
    return np.clip(action, -1, 1)

Os principais mecanismos aqui são processamento de estado, estratégia de exploração e gerenciamento de dispositivos. O processamento de estado cuida da conversão de arrays NumPy para o formato adequado de tensor, a adição de uma dimensão de lote (através do unsqueeze) e, por fim, garante que os cálculos sejam realizados no dispositivo correto.

A estratégia de exploração adiciona ruído Gaussiano à saída determinística da política. A escala do ruído controla a magnitude da exploração e o clipping mantém um intervalo de ação válido. O gerenciamento de dispositivos garante movimentação eficiente entre GPU e CPU, quando aplicável. Além disso, a função retorna como saída final um array NumPy para compatibilidade com o ambiente. O mecanismo de atualização de aprendizado é o seguinte:

def update(self):

    if len(self.replay_buffer) < BATCH_SIZE:

        return

Esta cláusula if atua como um controle de atualização, onde as atualizações são ignoradas até que experiências suficientes, em quantidade igual ao tamanho do lote, sejam coletadas. Isso garante estatísticas de lote significativas. A atualização das 2 redes críticas é realizada da seguinte forma:

# Sample batch

states, actions, rewards, next_states, dones = self.replay_buffer.sample(BATCH_SIZE)

# Target Q calculation
next_actions = self.actor_target(next_states)
target_q = self.critic_target(next_states, next_actions)
target_q = rewards + (1 - dones) * GAMMA * target_q

# Current Q estimation
current_q = self.critic(states, actions)

# Loss computation and backpropagation
critic_loss = nn.MSELoss()(current_q, target_q.detach())
self.critic_optimizer.zero_grad()
critic_loss.backward()
self.critic_optimizer.step()

Os principais aspectos abordados por este código são o cálculo do valor-alvo, o cálculo da perda e o gerenciamento de gradientes. O cálculo do valor-alvo utiliza redes-alvo para obter alvos Q estáveis. Ele implementa a equação de Bellman com tratamento de término, conforme definido pelo parâmetro de experiência “dones”. Um fator de desconto GAMMA controla a importância das recompensas futuras.

Para o cálculo da perda, é determinado o erro quadrático médio entre os valores Q atuais e os valores Q-alvo. O método detach() impede que os gradientes dos alvos fluam (ou sejam transportados pelo tensor para transferibilidade). E o aprendizado padrão por diferença temporal é aplicado. O gerenciamento de gradientes simplesmente garante que todos os gradientes sejam redefinidos para zero, e a otimização da rede crítica é realizada em uma etapa separada. As atualizações da rede ator também são realizadas da seguinte forma:

actor_loss = -self.critic(states, self.actor(states)).mean()
self.actor_optimizer.zero_grad()
actor_loss.backward()
self.actor_optimizer.step()

Os aspectos específicos do gradiente de política tratados aqui são a maximização dos valores Q através da minimização do Q negativo, a diferenciação através das redes ator e crítica, bem como a aplicação de uma abordagem de gradiente de política puro sem probabilidades logarítmicas (por ser determinística). As atualizações da rede-alvo são as seguintes:

for target, param in zip(self.actor_target.parameters(), self.actor.parameters()):

    target.data.copy_(TAU * param.data + (1 - TAU) * target.data)

for target, param in zip(self.critic_target.parameters(), self.critic.parameters()):

    target.data.copy_(TAU * param.data + (1 - TAU) * target.data)

Esse mecanismo de atualização suave utiliza a média de Polyak (Polyak averaging) com um valor TAU que normalmente é inferior a 1. Os pesos da rede são acompanhados lentamente, fornecendo uma alternativa às atualizações rígidas periódicas. Esse processo, como um todo, mantém a estabilidade enquanto permite o aprendizado. Nosso modelo precisa ser persistente. Ele deve ser capaz de carregar pesos de rede previamente salvos e também salvá-los após o treinamento. Realizamos isso da seguinte forma:

def save(self, filename):

    torch.save({
        'actor': self.actor.state_dict(),

        'critic': self.critic.state_dict(),

        'actor_target': self.actor_target.state_dict(),

        'critic_target': self.critic_target.state_dict(),
    }, filename)


def load(self, filename):

    checkpoint = torch.load(filename)
    self.actor.load_state_dict(checkpoint['actor'])
    self.critic.load_state_dict(checkpoint['critic'])
    self.actor_target.load_state_dict(checkpoint['actor_target'])
    self.critic_target.load_state_dict(checkpoint['critic_target'])

Os principais recursos da listagem acima são: salvar/carregar todos os estados da rede; manter a consistência das redes-alvo; permitir a continuidade do treinamento; e dar suporte à avaliação do modelo. Resumindo a classe agente, ao implementar um agente DDPG existem algumas escolhas críticas de projeto que precisam ser feitas. Essas escolhas podem ser agrupadas em três categorias principais: seleção dos componentes específicos do DDPG, aproveitamento dos pontos fortes da implementação e realização de melhorias potenciais.

Os componentes do DDPG utilizados são principalmente as redes-alvo, a política determinística e taxas de aprendizado separadas. As redes-alvo são muito importantes para o aprendizado estável das recompensas das ações executadas (Q-Learning) ao lidar com espaços de ação contínuos. O uso de espaços contínuos torna isso ainda mais importante. Essa política determinística exige então exploração externa por meio de ruído para aumentar a robustez. O uso de taxas de aprendizado separadas também é uma prática comum, onde a política (rede ator) possui uma taxa de aprendizado mais lenta que a rede de valor.

As escolhas realizadas que tornam esta uma implementação relativamente forte incluem uma clara “separação de responsabilidades”, onde possuímos métodos bem definidos para seleção de ações e também para atualizações. Além disso, existe uma gestão de execução em CPU/GPU(device-awareness) que garante o tratamento consistente das transições entre eles. O processamento em lote também é utilizado para tornar as operações com tensores mais eficientes e, por fim, a segurança de formato (shape-safety) é verificada em vários pontos para garantir consistência na dimensionalidade dos tensores.

As melhorias potenciais, porém, poderiam incluir: clipping de gradiente para evitar gradientes explosivos; utilização de um cronograma de taxa de aprendizado para refinar e controlar melhor o processo de aprendizado; uso de replay priorizado para amostragem mais eficiente, embora isso esteja relacionado ao buffer de replay já mencionado no artigo anterior; e, por fim, exploração paralela, onde múltiplas instâncias do ator podem ser utilizadas para coleta de dados mais rápida.

Também existem algumas dinâmicas de treinamento dignas de nota, relacionadas à sequência de atualização e às considerações sobre hiperparâmetros. A sequência de atualização prioriza a atualização das redes críticas. Isso ocorre porque valores Q mais precisos orientam melhor a melhoria da política. Para introduzir estabilidade adicional, também pode ser implementado o atraso nas atualizações da política. Por fim, atualizações frequentes das redes-alvo são realizadas para acompanhar lentamente os parâmetros (pesos da rede) aprendidos.

As considerações sobre hiperparâmetros devem incluir um foco especial em TAU, pois ele controla a velocidade das redes-alvo e, portanto, é um fator fundamental para a estabilidade de todo o processo de aprendizado. Também deve ser utilizada uma escala de ruído que permita decaimento ao longo do tempo. O dimensionamento do buffer também é crítico, pois afeta a eficiência do aprendizado, enquanto o tamanho do lote influencia a variância das atualizações.



Funções de Média Móvel e Estocástico

Essas duas funções são implementadas em Python para aprendizado por reforço (RL), ao contrário do artigo sobre aprendizado supervisionado, onde fizemos isso em MQL5 e simplesmente exportamos os dados de entrada da rede para o Python para treinamento. Em nossa implementação aqui, estamos utilizando o módulo Python do MetaTrader 5 para conectar a uma instância em execução do terminal e então recuperar dados de preços. Existem guias na documentação aqui explicando como fazer isso. As funções dos indicadores abaixo transformam dados brutos de preços em dados de indicadores técnicos que serviram como entradas para nosso modelo de aprendizado supervisionado após serem convertidos/normalizados em um vetor binário de entrada representando padrões. 

As saídas do modelo de aprendizado supervisionado são o que definimos como estados, pois, em essência, elas preveem mudanças na ação do preço. Esses estados são então utilizados como entradas para o agente DDPG de RL. Nossa função de Média Móvel recebe como entrada um DataFrame pandas contendo preços provenientes do módulo Python do MetaTrader 5. Esse DataFrame precisa ser validado e preparado da seguinte forma:

p = np.asarray(p).flatten()  # Convert to 1D array if not already

if len(p) < window:

    raise ValueError("Window size cannot be larger than the number of prices.")

O que estamos fazendo aqui é padronizar o array para garantir um formato de entrada unidimensional consistente, independentemente da forma da entrada. Também temos tratamento de erros para evitar tamanhos de janela inválidos que poderiam causar erros de cálculo. A integridade dos dados também mantém um fluxo limpo de informações ao longo do pipeline de processamento. O mecanismo de cálculo é o seguinte:

return np.convolve(p, np.ones(window), 'valid') / window

Essa implementação utiliza convolução para realizar de forma eficiente o cálculo da média móvel. O uso do parâmetro de entrada 'valid' garante que apenas janelas completamente calculadas sejam retornadas. A normalização também é feita pelo tamanho da janela para produzir uma média real. Toda a operação é vetorizada para desempenho ideal. A importância financeira disso é que ela suaviza os dados de preço para ajudar na identificação de tendências, e o tamanho da janela utilizada (também conhecido como período de média) determina a sensibilidade às mudanças de preço. A função do oscilador estocástico valida suas entradas da seguinte forma:

p = np.asarray(p).flatten()

if len(p) < k_window:
    raise ValueError("Window size for %K cannot be larger than the number of prices.")

As considerações de projeto aqui são a consistência da formatação de entrada com a função de Média Móvel. É necessária uma validação separada para a janela de cálculo do %K, com geração de erro como falha antecipada para parâmetros inválidos. O cálculo do %K é o seguinte:

for i in range(k_window - 1, len(p)):

    current_close = p[i]
    lowest_low = min(p[i - k_window + 1:i + 1])
    highest_high = max(p[i - k_window + 1:i + 1])
    K = ((current_close - lowest_low) / (highest_high - lowest_low)) * 100
    K_values.append(K)

Os componentes importantes aqui são a análise de janela deslizante, o contexto de mercado e a implementação geral. A análise de janela deslizante precisa examinar a faixa de preços ao longo de um período retrospectivo. Isso ajuda a identificar a posição relativa do preço de fechamento atual, sendo aplicada uma escala padrão de 0 a 100. O contexto de mercado ajuda a avaliar condições de sobrecompra e sobrevenda. Valores próximos de 100 sugerem uma possível reversão para baixo, enquanto valores próximos de 0 sugerem uma possível reversão para cima. A implementação geral utiliza um laço explícito para maior clareza, emprega indexação adequada da janela para lidar com casos extremos e preserva a ordem temporal dos resultados. O cálculo do %D é o seguinte:

D_values = MA(K_values, d_window)

Essencialmente, trata-se de um refinamento de sinal onde é utilizada uma versão suavizada da média móvel do %K. A atribuição típica para esse período de média é 3, e é isso que estamos utilizando. Esse buffer adicional fornece confirmação para as oscilações do %K e, assim, ajuda a reduzir sinais falsos provenientes do %K bruto.


Função Get Pattern

Esta função é utilizada para integrar os dados dos dois buffers de indicadores acima ao pipeline de aprendizado. Ela desempenha um papel de engenharia de atributos. Isso ocorre porque: ajuda na redução de dimensionalidade, já que transforma preços brutos em sinais mais significativos; ajuda na melhoria da estacionariedade, pois os indicadores geralmente são mais estáveis do que os preços brutos; e, por fim, permite capturar contexto temporal, uma vez que cálculos baseados em janelas mantêm dependências temporais (um vetor de entrada gerado, por exemplo, [1,0,0,1], pode ser associado ao momento em que foi produzido, da mesma forma que qualquer valor de indicador ou preço bruto também é marcado com o instante em que é gerado).

Principalmente, porém, ela é utilizada para a preparação do aprendizado supervisionado. Os atributos que produz em um vetor binário de 0s e 1s treinam o modelo para prever as próximas mudanças de preço. A Média Móvel fornece informações de tendência, enquanto a função STO nos fornece informações de momentum e reversão. Abordamos os padrões complementares combinados de ambos os indicadores no artigo 57. As saídas de previsão de mudança de preço passam então a servir como representação de estado para o RL.

Isso implica que as previsões do nosso modelo de aprendizado supervisionado tornam-se entradas de estado para o DDPG. Portanto, os indicadores utilizados, MM e STO, acabam auxiliando o agente DDPG ao fornecer contexto de mercado para ajudar na compreensão de um determinado regime de mercado. Isso reduz a necessidade de utilizar preços históricos brutos na definição do estado.

Os pontos fortes da implementação incluem robustez por meio da validação de entradas para evitar falhas silenciosas, tratamento de dimensionalidade para garantir formatos consistentes dos arrays e mensagens de erro claras em caso de uso inadequado. Também existem considerações de desempenho, como o uso de operações vetorizadas sempre que possível, laços explícitos quando necessários e eficiência de memória graças a um design favorável ao processamento em fluxo. Ela continua relevante para os traders, sem se perder em tecnicismos. Isso porque indicadores amplamente utilizados pela indústria estão sendo empregados para gerar estados. Os indicadores são complementares, pois combinam métricas de tendência e momentum, e as saídas de estado estão em uma faixa normalizada, algo importante para a consistência.

Possíveis melhorias incluem otimização computacional através de uma implementação vetorizada do cálculo do %K, utilização da aceleração com numba (importado via JIT) para acelerar os laços da função STO e armazenamento em cache de cálculos intermediários. Funcionalidades estendidas também podem ser adicionadas através de validações adicionais para valores NaN/inf. Este código que implementa aprendizado por reforço com DDPG é extenso e, embora fosse apropriado comentar suas principais seções, limitarei-me a anexar ao final deste artigo as partes que ainda não foram abordadas. Entre elas, destaca-se esta função get pattern.



Testes

Dos 10 padrões que testamos no artigo sobre aprendizado supervisionado, nº 57, apenas 7 conseguiram avançar de forma lucrativa durante um ano, tendo sido treinados no ano anterior. Como cada padrão resultou em sua própria rede, também precisamos gerar redes e ambientes de aprendizado por reforço para cada padrão. Seguimos uma metodologia semelhante à utilizada no artigo 57, treinando o par EUR USD para o ano de 2023 no período gráfico diário. Neste caso, treinamos nossas redes de aprendizado por reforço simulando o ano de 2023 como um ambiente de “mercado ao vivo”. Como argumentado nos dois artigos anteriores, o aprendizado por reforço é um sistema destinado a apoiar e proteger um modelo já estabelecido e treinado, que em nosso caso é a rede treinada por aprendizado supervisionado no artigo 57. 

Ele faz isso realizando retropropagação enquanto está em produção ou em ambientes ao vivo, e não sobre dados históricos. Como a retropropagação de uma rede ONNX a partir do MQL5 não é viável, estamos “simulando” um ambiente ao vivo, que no nosso caso continua sendo o ano de 2023.

Em vez da pergunta que fizemos no aprendizado supervisionado, “o que o preço fará a seguir?”, fazemos a seguinte pergunta: “dadas essas mudanças de preço recebidas, quais ações o trader deve tomar?”. Assim, realizamos os treinamentos de simulação descritos acima para o ano de 2023 e depois executamos um teste forward para o ano de 2024, onde nossas condições de entrada são ligeiramente modificadas.

Em vez de basearmos nossas posições compradas ou vendidas apenas no que o preço fará a seguir, também consideramos quais ações realmente precisamos tomar diante do que o preço fará. Também levamos em conta se as recompensas serão lucrativas. Dos 7 padrões que avançaram nos testes forward no artigo 57, apenas 3 avançam de forma significativa quando o aprendizado por reforço é utilizado. Utilizando nossa indexação dos 10 padrões, numerados de 0 a 9, esses padrões são 1, 2 e 5. Seus relatórios são apresentados abaixo:

Para o padrão 1:

r1

c1

Para o padrão 2:

r2

c2

Para o padrão 5:

r5

c5

O Expert Advisor testado, como sempre, é construído com uma classe de sinal personalizada cujo código está anexado abaixo. Realizamos alterações no arquivo da classe de sinal utilizado no artigo 57, renomeando a função 'IsPattern' para 'Supervise'. Também introduzimos uma nova função chamada 'Reinforce'. O código de ambas é compartilhado abaixo:

//+------------------------------------------------------------------+
//| Supervised Learning Model Forward Pass.                          |
//+------------------------------------------------------------------+
double CSignal_DDPG::Supervise(int Index, ENUM_POSITION_TYPE T)
{  vectorf _x = Get(Index, m_time.GetData(X()), m_close, m_ma, m_ma_lag, m_sto);
   vectorf _y(1);
   _y.Fill(0.0);
   int _i=Index;
   if(_i==8)
   {  _i -= 2;
   }
   ResetLastError();
   if(!OnnxRun(m_handles[_i], ONNX_NO_CONVERSION, _x, _y))
   {  printf(__FUNCSIG__ + " failed to get y forecast, err: %i", GetLastError());
      return(double(_y[0]));
   }
   if(T == POSITION_TYPE_BUY && _y[0] > 0.5f)
   {  _y[0] = 2.0f * (_y[0] - 0.5f);
   }
   else if(T == POSITION_TYPE_SELL && _y[0] < 0.5f)
   {  _y[0] = 2.0f * (0.5f - _y[0]);
   }
   return(double(_y[0]));
}
//+------------------------------------------------------------------+
//| Reinforcement Learning Model Forward Pass.                       |
//+------------------------------------------------------------------+
double CSignal_DDPG::Reinforce(int Index, ENUM_POSITION_TYPE T, double State)
{  vectorf _x(1);
   _x.Fill(float(State));
   vectorf _y(1);
   _y.Fill(0.0);
   vectorf _y_state(1);
   _y_state.Fill(float(State));
   vectorf _y_action(1);
   _y_action.Fill(0.0);
   vectorf _z(1);
   _z.Fill(0.0);
   int _i=Index;
   if(_i==8)
   {  _i -= 2;
   }
   ResetLastError();
   if(!OnnxRun(m_handles_a[_i], ONNX_NO_CONVERSION, _x, _y))
   {  printf(__FUNCSIG__ + " failed to get y action forecast, err: %i", GetLastError());
   }
   _y_action[0] = _y[0];
   ResetLastError();
   if(!OnnxRun(m_handles_c[_i], ONNX_NO_CONVERSION, _y_state, _y_action, _z))
   {  printf(__FUNCSIG__ + " failed to get z reward forecast, err: %i", GetLastError()); 
   }
   //normalize action output & check for state-action alignment
   if(T == POSITION_TYPE_BUY && _y[0] > 0.5f)
   {  _y[0] = 2.0f * (_y[0] - 0.5f);
   }
   else if(T == POSITION_TYPE_SELL && _y[0] < 0.5f)
   {  _y[0] = 2.0f * (0.5f - _y[0]);
   }
   else
   {  _y[0] = 0.0f;
   }
   return(double(_y[0]*_z[0]));
}

Este arquivo de classe de sinal personalizada destina-se a ser montado em um Expert Advisor através do MQL5 Wizard e, para leitores iniciantes, é possível encontrar orientações aqui e aqui sobre como fazer isso.


Conclusão

Analisamos a aplicação do aprendizado por reforço quando os modelos estão em implantação/produção. Nosso aprendizado por reforço utilizou o algoritmo Deep Deterministic Policy Gradient e essa implementação continha as classes: buffer de replay, ator, crítico e agente, abordadas neste e no artigo anterior. O aprendizado por reforço em implantação/produção serve como um meio de manter o modelo focado no que foi aprendido durante a fase de aprendizado supervisionado (exploitation/aproveitamento), ao mesmo tempo em que observa novas mudanças desconhecidas no ambiente/condições de mercado que devem ser consideradas na tomada de decisões futuras (exploitation/exploração). Ao fazer isso corretamente, inerentemente precisamos realizar retropropagação e treinar um modelo enquanto ele está sendo utilizado. 

No entanto, como o treinamento de um modelo ONNX no MQL5 não é suportado, optamos por uma simulação de condições de negociação ao vivo utilizando dados históricos. Após a simulação, testamos os modelos de aprendizado por reforço treinados no ano subsequente ao ano de treinamento e apenas 3 dos 7 conseguiram avançar nos testes forward, embora com resultados de negociação enviesados, já que as posições foram mantidas predominantemente apenas compradas ou apenas vendidas. Como argumentamos no artigo 57, isso provavelmente se deve a uma janela de testes pequena, o que significa que treinamento e testes extensivos em uma quantidade maior de dados devem corrigir esse problema. Agora analisaremos o aprendizado por inferência.

Tipo Descrição
*.*onnx files Arquivos de modelo ONNX na subpasta Python dentro do local do arquivo da classe de sinal personalizada
*.*mqh files Arquivo da classe de sinal personalizada e arquivo com função para processamento dos dados de entrada da rede (57_X)
*.*mq5 files Expert Advisor montado pelo Wizard cujo cabeçalho mostra os arquivos utilizados.

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

Arquivos anexados |
MQL5.zip (1106.07 KB)
Experts.zip (1.67 KB)
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
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 em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Gerenciamento Avançado de Memória e Técnicas de Otimização em MQL5 Gerenciamento Avançado de Memória e Técnicas de Otimização em MQL5
Descubra técnicas práticas para otimizar o uso de memória em sistemas de negociação MQL5. Aprenda a construir Expert Advisors e indicadores eficientes, estáveis e com alto desempenho. Exploraremos como a memória realmente funciona no MQL5, as armadilhas comuns que desaceleram seus sistemas ou causam falhas e, mais importante ainda, como corrigi-las.
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.
Algoritmo do Duelista - Duelist Algorithm Algoritmo do Duelista - Duelist Algorithm
E se as suas estratégias de trading pudessem aprender umas com as outras, como verdadeiros combatentes? O Duelist Algorithm é um novo método de otimização em que os parâmetros dos sistemas de trading realmente duelam entre si pelo direito de serem chamados os melhores.