![Redes neurais de maneira fácil (Parte 14): Agrupamento de dados](https://c.mql5.com/2/49/Neural_networks_made_easy_004_600x314.jpg)
Redes neurais de maneira fácil (Parte 14): Agrupamento de dados
Conteúdo
- Introdução
- 1. Aprendizado não supervisionado
- 2. Algoritmo k-médias
- 3. Implementação com Python
- 4. Teste
- Fim do artigo
- Referências
- Programas utilizados no artigo
Introdução
Nesta série de artigos, já avançamos bastante no estudo de vários algoritmos de redes neurais. Mas todos os algoritmos considerados foram baseados nos princípios de aprendizado supervisionado. Ou seja, introduzimos alguns dados históricos na entrada do modelo e otimizamos os coeficientes de ponderação para que o modelo retornasse valores o mais próximo possível dos resultados de referência. Deve-se dizer que, na prática, esta abordagem geralmente produz os melhores resultados. Entretanto, para preparar tal processo, além dos dados históricos da amostra de treinamento, precisamos também de resultados de referência para cada estado do sistema em estudo. Como você pode ver, a obtenção dos valores de referência exige um esforço adicional na preparação da amostra de treinamento. E nem sempre é possível dar um resultado de referência preciso para cada estado do sistema. Como consequência, isto coloca restrições sobre o possível tamanho da amostra de treinamento.
Por outro lado, há uma outra abordagem nos métodos de treinamento de inteligência artificial, isto é, o aprendizado não supervisionado. Este método permite treinar modelos apenas com base nos dados iniciais sem a presença de valores de referência, em outras palavras, sem valores predefinidos. Isto não apenas reduz o esforço adicional na fase de preparação da amostra de treinamento, como também nos dá a oportunidade de usar mais dados de entrada para treinar o modelo. Mas também diminui a variedade de tarefas que podem ser realizadas.
Deixe-me avisar desde já que neste artigo você não verá a já conhecida estrutura vertical de uma rede neural de várias camadas neurais. Em vez disso, estudaremos tudo passo a passo. Bem, sendo assim, vejamos possíveis algoritmos e como podemos usá-los em nossas negociações.
1. Aprendizado não supervisionado
No campo do desenvolvimento de algoritmos de inteligência artificial, costuma-se distinguir 3 áreas:
- aprendizado supervisionado
- aprendizado não supervisionado
- aprendizado por reforço.
Como pode ser entendido pelos nomes mostrados acima, sua principal diferença está nas abordagens aos modelos de treinamento. Com o primeiro método, isto é, como o "aprendizado supervisionado", já estamos um pouco familiarizados graças aos artigos anteriores da nossa série. Como você sabe, para implementar esse método, precisamos de uma amostra de treinamento com pares de valores: estado do sistema/valor de referência. Na prática, esta abordagem maximiza os resultados, mas também exige recursos adicionais (incluindo esforço humano) e tempo para preparar a amostra de treinamento. Depois de tudo, você deve admitir que não é uma tarefa fácil dar um resultado de referência preciso para cada estado do sistema. Além disso, com um certo grau de probabilidade, temos que considerar também o fator humano. Às vezes, esses motivos se tornam as principais limitações na formação de uma amostra de treinamento.
Mas o que fazer quando há muitos dados iniciais e pouco conhecimento sobre eles? Acima de tudo, quando não podemos comparar cada estado do processo estudado com algum valor de referência preciso, ou quando ainda não sabemos qual deve ser esse valor de referência. Esta situação geralmente acontece no momento em que se introduz uma grande quantidade de dados. E em vez de gastar recursos para encontrar valores de referência para cada estado do sistema, voltamos nossos olhos para o aprendizado não supervisionado. E aqui deve ser dito que, dependendo da tarefa proposta, como resultado do aprendizado não supervisionado do modelo podemos obter tanto uma solução para o problema quanto um pré-processamento dos dados iniciais.
Deve-se dizer desde já que as tarefas resolvidas por métodos de aprendizado supervisionados e não supervisionados são muito diferentes. Por exemplo, o aprendizado não supervisionado não serve para resolver problemas de regressão. Até certo ponto, é possível comparar problemas de classificação, resolvidos pelo método de aprendizado supervisionado, e problemas de agrupamento, resolvidos por algoritmos de aprendizado não supervisionado. Com efeito, muitas vezes, ambos os métodos podem dar resultados completamente diferentes. Enquanto no caso da classificação com aprendizado supervisionado pedimos ao modelo que aprenda qual estado do sistema corresponde a qual classe, no caso do agrupamento com aprendizado não supervisionado pedimos ao modelo que determine independentemente a qual agrupamento o estado do sistema pertence em função do conjunto de características que descrevem o estado dado. Assim sendo, no início, talvez nem saibamos o número de tais agrupamentos, porque seu número é um hiperparâmetro para o sistema e pode ser ajustado conforme o modelo é treinado.
O segundo problema resolvido com a ajuda de algoritmos de aprendizado não supervisionado é o de busca de anomalias, isto é, a busca de estados que não são característicos de um determinado sistema, mas que, devido a fatores externos, às vezes podem se manifestar com um pequeno grau de probabilidade.
Outro problema resolvido com a ajuda de algoritmos de aprendizado não supervisionado é o de redução da dimensionalidade dos dados. Lembre-se, resolvemos um problema semelhante usando redes convolucionais. Mas se no aprendizado supervisionado estivéssemos procurando características específicas para uma tarefa específica, na tarefa de aprendizado não assistido temos que comprimir os dados com um mínimo de perda de informação.
Em geral, quanto aos problemas resolvidos por algoritmos de aprendizado não supervisionado, podemos dizer que a principal tarefa é estudar e generalizar as características incorporadas nos dados iniciais. Esta abordagem permite que o modelo explore as características da descrição do estado do sistema por si só. Isso é frequentemente usado na resolução de problemas de aprendizado supervisionado, quando se treina pela primeira vez um modelo não supervisionado introduzindo uma grande quantidade de dados, para que o modelo aprenda o máximo possível sobre as características do sistema. É só depois que com uma pequena quantidade de dados marcados que o modelo é treinado para resolver um problema específico.
Como você pode ver, algoritmos de aprendizado não supervisionados permitem a resolução de diversos problemas. Mas como podemos usá-los em nossa negociação? Vamos pensar. Quando usamos os métodos de análise gráfica, quase sempre falamos sobre certos padrões: topo duplo/fundo duplo, cabeça e ombros, bandeira, padrões harmônicos, etc. Existem também padrões de velas pequenos que consistem em 1-3 velas. E, quase sempre, quando tentamos descrever um padrão em termos matemáticos, somos confrontados com muitas convenções e suposições. O que complica seu uso na negociação algorítmica. Francamente, há também muita subjetividade na hora de o operador humano determinar padrões. É por isso que, após analisar o mesmo gráfico, diferentes operadores encontram padrões diferentes, muitas vezes indo na direção oposta do movimento previsto. Sim, devo aceitar, todo o sistema de negociação é construído sobre isso. Digamos que alguns desses operadores têm lucro e outros, prejuízo, porque, possivelmente, não foram criados novos inventários no curso do pregão, e a oferta de dinheiro permaneceu inalterada. Só que, na verdade, pode ter acontecido que tal oferta tenha apenas pulado de um bolso para outro. Mas como podemos evitar levar prejuízo?
Vamos dar outra olhada nos padrões gráficos mencionados acima. Sim, todos eles têm suas suposições. Mas, ao mesmo tempo, cada padrão tem sua própria estrutura, que o distingue do gráfico geral do movimento de preços. Bem, e se usarmos algoritmos de agrupamento de dados não supervisionados e instruirmos o modelo a destacar todas as possíveis variações nos dados durante um determinado período? Como usamos aprendizado não supervisionado, não precisamos marcar os dados e o período pode ser bastante grande. Obviamente, devemos lembrar que, à medida que o período do histórico aumenta, também os recursos gastos no treinamento do modelo aumentam.
2. Algoritmo k-médias (k-means)
Para resolver o problema de agrupamento proposto acima, usaremos um dos métodos mais simples e fácies de entender, nomeadamente o k-means. Apesar de sua simplicidade, o método é bastante eficaz na resolução de problemas de agrupamento de dados e pode ser usado tanto de forma independente quanto para pré-processamento de dados.
Para usar este método, cada estado do sistema em estudo é descrito por algum conjunto de dados reunidos em um único vetor. Cada um desses vetores representa as coordenadas de algum ponto no espaço N-dimensional. Onde a dimensão do espaço é igual à dimensão do vetor de descrição do estado do sistema.
Essencialmente, o método consiste em encontrar esses centros (vetores) em torno dos quais todos os estados conhecidos do sistema podem ser combinados em agrupamentos. A distância média de todos os estados do sistema até o centro do agrupamento correspondente deve ser mínima. Como se pode notar, é daí que vem o nome do método k-médias. O número de tais agrupamentos é um hiperparâmetro do modelo e é determinado na fase de concepção ou validação do modelo.
Provavelmente, soa um pouco estranho "... é determinado na fase de concepção ou validação do modelo". À primeira vista, esses conceitos são divididos por tempo e etapas de criação e treinamento do modelo. Mas os casos são bem diferentes. Às vezes, o número de tais agrupamentos é determinado ao descrever o problema. Isso é possível quando o cliente, a partir de sua experiência ou do uso planejado dos resultados esperados, entende claramente o número de tais agrupamentos, ou, ao visualizarmos os dados, podemos ver claramente o número de agrupamentos diferenciados. Nesses casos, podemos indicar imediatamente ao modelo o número de agrupamentos que estamos procurando.
Em outros casos, porém, onde não temos conhecimento suficiente para determinar o número de agrupamentos de forma precisa, temos de executar uma série de modelos para saber o número ideal de agrupamentos. Mas falaremos sobre isso um pouco mais adiante. Agora vamos analisar o algoritmo do método.
A figura acima mostra 100 pontos aleatórios em um plano. A visualização de dados é útil para entender sua estrutura, mas não é necessária para o método aqui estudado. Como você pode ver, os pontos são distribuídos de maneira bastante uniforme por todo o plano e não podemos distinguir visualmente nenhum agrupamento, muito menos seu número. Para o primeiro experimento, vamos pegar, por exemplo, 5 agrupamentos.
Bem, já decidimos a quantidade. Mas, e onde deveríamos colocar seus centros? Lembre-se, quando inicializamos os pesos, preenchemos as matrizes com valores aleatórios. Aqui faremos o mesmo. Só que não geraremos vetores aleatórios, pois eles podem ser deixados de fora de nossos dados iniciais. Nós simplesmente pegaremos 5 pontos aleatórios da nossa amostra de treinamento. Na figura abaixo, eles estão marcados com X.
Em seguida, temos que calcular a distância de cada ponto a cada centro. Não me parece que ninguém tenha dificuldade para determinar a distância entre dois pontos em uma linha (espaço unidimensional). Utilizamos o teorema de Pitágoras, conhecido da matemática escolar, para determinar a distância entre dois pontos do plano. Esse teorema diz que a soma dos quadrados dos catetos é igual ao quadrado da hipotenusa. Logo, a distância entre dois pontos no plano é igual à raiz quadrada da soma das distâncias quadradas entre as projeções dos pontos nos eixos coordenados. E, simplesmente, esta é a soma dos quadrados da diferença das coordenadas correspondentes. Acredite, se aplicarmos uma abordagem semelhante para a projeção de um ponto em um plano N-1, obteremos uma igualdade semelhante para um espaço N-dimensional.
Após determinar a distância a cada um dos centros do agrupamento, o mais próximo deles definirá se o ponto pertence a dado agrupamento. Vamos repetir as iterações de distância e de atribuição ao agrupamento para todos os pontos de nossa amostra de treinamento. Depois disso, com uma média aritmética simples, determinamos um novo centro para cada agrupamento. A figura abaixo mostra os resultados da primeira iteração, onde os pontos de cada agrupamento são coloridos em uma cor diferente.
Como se pode ver, após a primeira iteração, a distribuição de pontos entre os agrupamentos não é uniforme. Mas em comparação com o gráfico anterior, os centros dos agrupamentos mudaram. O que quer dizer que a distribuição entre os agrupamentos mudará quando se repetirem iterações de recálculo das distâncias aos centros de agrupamento e se determinar se um ponto pertence a um agrupamento em particular.
Repetimos as iterações em um loop até que os centros dos agrupamentos parem de se mover. E, como resultado, os pontos não mudarão sua associação a um agrupamento em particular, de iteração para iteração.
Após várias iterações sobre os dados do nosso exemplo, obtemos a imagem a seguir. Como se pode notar, obtivemos uma distribuição bastante uniforme de pontos de sequência de treinamento sobre os agrupamentos.
Vamos resumir o algoritmo considerado:
- Determinamos k pontos aleatórios a partir da amostra de treinamento como centros de agrupamento.
- Preparamos um loop de operações:
- Determinamos a distância de cada ponto a cada centro;
- Com ajuda do centro mais próximo, determinamos se o ponto pertence ao agrupamento;
- Com a média aritmética, determinamos um novo centro para cada agrupamento.
- Repetimos as operações no loop até que os centros do agrupamento “parem”.
Devo dizer que já que não estamos interessados na distância específica do ponto ao centro, mas apenas qual deles é menor. Então, para economizar recursos, ao calcular a distância, não extrairemos a raiz quadrada da soma resultante, o que absolutamente não afetará o resultado do agrupamento de dados.
Neste estágio, dividimos nossos dados de amostra de treinamento em agrupamentos. Mas como podemos determinar que o número de agrupamentos que tomamos é o ideal? Pois, como no caso do aprendizado supervisionado, em que introduzimos uma função de perda que nos ajudará a avaliar a qualidade do modelo treinado, bem como comparar o desempenho do modelo com diferentes hiperparâmetros. Para problemas de agrupamento, tal função de perda é o desvio médio dos pontos em relação ao centro do agrupamento correspondente e é calculada pela fórmula:
Onde:
- m é o número de elementos na amostra de treinamento,
- N é a dimensão do vetor de descrição de elemento a partir da amostra de treinamento,
- X i j é o i-ésimo valor do vetor de descrição do j-ésimo elemento da amostra de treinamento,
- C i x j é o i-ésimo valor do vetor central do agrupamento ao qual pertence o j-ésimo elemento da amostra de treinamento.
Como se pode notar facilmente na fórmula acima, o valor da função de perda será igual a "0" quando o número de agrupamentos for igual ao número de elementos na amostra de treinamento. Mas não queremos copiar toda a amostra de treinamento em nossa matriz de centros de agrupamento. Pelo contrário, queremos encontrar uma maneira de generalizar os dados para que possamos procurar possíveis padrões para cada agrupamento de valores.
Repeti o agrupamento da mesma amostra de treinamento com um número diferente de agrupamentos. A dependência da função de perda para com o número de agrupamentos é mostrada na figura abaixo. Evitei intencionalmente exibir o valor da função de perda, pois ela pode variar muito para diferentes dados de entrada e depende da natureza deles. Além disso, o número de agrupamentos também depende bastante da amostra de treinamento, portanto, você não vale a pena confiar nos valores apresentados. Eles são mostrados aqui apenas como um guia para explicar o gráfico. É importante que você entenda os princípios da interpretação de gráficos.
O gráfico acima mostra claramente que quando o número de agrupamentos muda de 2 para 4, o valor da função de erro diminui drasticamente. Com um aumento adicional no número de agrupamentos para 6, a taxa de diminuição no valor da função de erro diminui gradualmente. E quando o número de agrupamentos muda de 6 para 7, o valor da função de erro praticamente não muda. Aqui vemos uma mudança suavizada na função de perda. Mas às vezes você pode encontrar uma quebra em um ponto específico. Esse fenômeno ocorre com mais frequência quando os dados de treinamento são claramente separáveis.
A regra geral para interpretar o gráfico é a seguinte:
- Caso a linha seja quebrada, o número ótimo de agrupamentos é obtido no local da quebra;
- Caso a linha seja mais suave, escolhemos entre um equilíbrio de qualidade e desempenho na área de curva.
Para o exemplo acima, dados os pequenos tamanhos de amostra e o número de agrupamentos, eu recomendaria usar 5 ou 6 agrupamentos.
3. Implementação com Python
Aprendemos os aspectos teóricos do método k-médias recorrendo a dados abstratos como exemplo. Isto levanta a questão de como o método irá funcionar com dados reais. Para responder a esta pergunta, aproveitaremos a integração entre MetaTrader 5 e Python. Como é conhecido, Python possui um grande número de bibliotecas que podem atender a quase todas as necessidades.
As ferramentas de integração já foram discutidas mais de uma vez neste site, inclusive o procedimento para instalação de bibliotecas está descrito na documentação.
3.1. Bibliotecas auxiliares
Para realizar a tarefa em questão, utilizaremos várias bibliotecas, sobretudo, a biblioteca MetaTrader5. É ela que permite garantir todos os pontos de integração entre MetaTrader 5 e Python.
A segunda biblioteca que precisamos é Scikit-Learn. Ela é daquelas que dispõem de ferramentas simples e práticas para a análise de dados. Entre outras coisas, ela possui vários algoritmos de agrupamento de dados, incluindo o método k-means que estamos considerando.
Implementamos a visualização de dados usando a biblioteca Matplotlib.
As ferramentas de integração MetaTrader 5 e Python permitem transferir várias informações sobre o status da conta, operações de negociação e situação do mercado em scripts. Mas não permitem o uso de dados de programas internos, como indicadores. Por isso, toda a implementação dos indicadores precisará ser repetida no lado do Python. Também aqui usaremos a biblioteca TA-Lib, que oferece várias ferramentas de análise técnica, para facilitar nosso trabalho.
Claro, antes de criar o script, todas as bibliotecas utilizadas e o interpretador da linguagem Python devem estar instalados no computador. Esse procedimento está além do escopo deste artigo. Mas se alguém tiver alguma dificuldade, responderei, se possível, nos comentários do artigo.
3.2. Criando um script
Agora que definimos a lista de bibliotecas a serem usadas, podemos começar a escrever o script. Salvaremos o código do script no arquivo "clustering.py".
No início do script, incluímos as bibliotecas necessárias.
# Импорт библиотек import numpy as np import matplotlib.pyplot as plt import MetaTrader5 as mt5 from talib import abstract as tl import sklearn.cluster as cluster from datetime import datetime as dt
Em seguida, preparamos a conexão com o terminal. E verificamos se essa operação é executada corretamente. Em caso de erro, exibimos uma mensagem e saímos do programa.
# Подключаемся к терминалу MetaTrader 5 if not mt5.initialize(): print("initialize() failed, error code =",mt5.last_error()) quit()
Após a conexão bem-sucedida ao terminal, faremos o carregamento dos dados históricos do período analisado e desconectaremos o terminal.
# Загрузка котировок rates=mt5.copy_rates_range('EURUSD',mt5.TIMEFRAME_H1,dt(2006,1,1),dt(2022,1,1)) mt5.shutdown()
Agora que recebemos os dados históricos, vamos determinar os valores dos indicadores. Neste bloco, vamos calcular os valores dos mesmos indicadores que usamos ao testar vários modelos por meio do aprendizado supervisionado. Estes são os osciladores clássicos RSI, CCI e MACD.
# Рассчитаем значение индикаторов rsi=tl.RSI(rates['close']) cci=tl.CCI(rates['high'],rates['low'],rates['close']) macd,macdsignal,macdhist=tl.MACD(rates['close'])
E aqui temos os dados iniciais, mas estão divididos em 6 tensores. Para análise, precisamos combiná-los em um único tensor. Há um outro ponto a ser feito aqui. A função de agrupamento é construída de tal forma que recebe um array bidimensional como entrada, array esse cujas strings são consideradas padrões separados. Ao combinar todos os tensores em um, também obtemos um array bidimensional cujas strings contêm informações sobre uma vela individual. Claro, podemos usá-lo tal qual como está. Mas então estaríamos agrupando velas individuais. E, portanto, quão útil será esta informação para nós? Se quisermos procurar padrões de várias velas, precisamos alterar a dimensão do tensor. Porém, uma simples mudança de dimensão não satisfaz plenamente nossos requisitos. Isto é comparável ao uso de uma janela deslizante com incrementos de deslocamento iguais ao seu tamanho. Mas gostaríamos de entender o padrão em cada vela. Portanto, precisaremos reformatar o tensor através da cópia dos dados. Abaixo está um exemplo de código para combinar um tensor e depois copiar os dados para criar um padrão de 20 velas. Deve-se notar que os dados históricos são recortados onde os valores dos indicadores não são definidos.
# Сгруппируем обучающую выборку data=np.array([rates['close']-rates['open'],rates['high']-rates['close'],rates['close']-rates['low'], rsi,cci,macd,macdsignal,macdhist]).T s=data.shape[0] data=np.hstack([data[40+k:s-20+k] for k in range(0,20)])
Isso conclui o processo de preparação de dados e podemos agrupar os dados. Mas para estimar o número necessário de agrupamentos, precisamos realizar vários testes com um número diferente de agrupamentos. Neste exemplo, realizei o agrupamento para um intervalo de 50 a 1 000 agrupamentos em incrementos de 50 agrupamentos.
# Проведем кластеризацию с различным количеством кластеров R=range(50,1000,50) KM = (cluster.KMeans(n_clusters=k).fit(data) for k in R)
Em conclusão, determinamos o erro para cada caso e visualizamos os dados obtidos.
distance=(k.transform(data) for k in KM) dist = (np.min(D, axis=1) for D in distance) avgWithinSS = [sum(d) / data.shape[0] for d in dist] # Отрисовка результатов обучения модели plt.plot(R, avgWithinSS) plt.xlabel('$Clasters$') plt.title('Loss dynamic') # Вывод созданных графиков plt.show()
Isso conclui o trabalho com o código do script e continuamos com o teste. O código completo do script pode ser encontrado no anexo.
4. Teste
Criamos um script Python e podemos testá-lo. Todos os parâmetros de teste são especificados no código do script:
- Instrumento: EURUSD;
- Período gráfico: H1;
- Intervalo histórico de 16 anos de 01/01/2006 a 01/01/2022
- Número de agrupamentos de 50 a 1 000 em incrementos de 50
Como resultado do treinamento, obtivemos um gráfico das dependências da função de perda em relação ao número de agrupamentos, mostrado abaixo.
Como se pode ver no gráfico, a quebra acabou sendo bastante esticada. Uma utilização ótima parece ser de 400 a 500 agrupamentos. Ao fazer isso, é preciso dizer que foram analisados 98.641 estados do sistema.
Fim do artigo
Neste artigo, nos familiarizamos com o método de agrupamento de dados k-médias, que é um dos algoritmos de aprendizado não supervisionado. Criamos um script usando bibliotecas Python e treinamos o modelo com um número diferente de agrupamentos. Com base nos resultados dos testes, podemos concluir que o modelo foi capaz de identificar cerca de 500 padrões. Claro, entendemos que nem todos eles darão sinais claros para as operações de negociação. Mas falaremos sobre como usar os resultados obtidos na prática nos artigos a seguir.
Referências
- Redes neurais de maneira fácil
- Redes neurais de maneira fácil (Parte 2): treinamento e teste da rede
- Redes neurais de maneira fácil (Parte 3): redes convolucionais
- Redes neurais de maneira fácil (Parte 4): redes recorrentes
- Redes neurais de maneira fácil (Parte 5): cálculos em paralelo com OpenCL
- Redes neurais de maneira fácil (Parte 6): experimentos com a taxa de aprendizado da rede neural
- Redes neurais de maneira fácil (Parte 7): métodos de otimização adaptativos
- Redes neurais de maneira fácil (Parte 8): mecanismos de atenção
- Redes neurais de maneira fácil (Parte 9): documentação do trabalho
- Redes neurais de maneira fácil (Parte 10): atenção multi-cabeça
- Redes neurais de maneira fácil (Parte 11): uma visão sobre GPT
- Redes neurais de maneira fácil (Parte 12): dropout
- Redes neurais de maneira fácil (Parte 13): normalização em lote
Programas utilizados no artigo
# | Nome | Tipo | Canal Equidistante |
---|---|---|---|
1 | clustering.py | Script | Script de agrupamento de dados em Python |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/10785
![Desenvolvendo um EA de negociação do zero (Parte 27): Em direção ao futuro (II)](https://c.mql5.com/2/48/development__3.png)
![Como desenvolver um sistema de negociação baseado no indicador ATR](https://c.mql5.com/2/46/why-and-how__4.png)
![DoEasy. Controles (Parte 5): Objeto base WinForms, controle Painel, parâmetro AutoSize](https://c.mql5.com/2/46/MQL5-avatar-doeasy-library-2__4.png)
![Como desenvolver um sistema de negociação baseado no indicador ADX](https://c.mql5.com/2/46/why-and-how__3.png)
![MQL5 - Linguagem para estratégias de negociação inseridas no terminal do cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso