Experiências com redes neurais (Parte 1): Lembrando a geometria
Introdução
Boa tarde, caros usuários da comunidade MQL5. Neste artigo, gostaria de compartilhar meus experimentos com redes neurais. Depois de ler uma grande quantidade de informações disponíveis no site do MQL5, cheguei à conclusão de que a teoria é suficiente. Existem artigos, bibliotecas, códigos-fonte muito bons. Mas foi muito frustrante que esta informação não permita chegar a uma conclusão racional - um sistema de negociação lucrativo. Isto é o que nós vamos procurar corrigir.
Devo dizer desde já que não sou um especialista neste campo, muito menos um escritor ou jornalista, mas tentarei expressar meus pensamentos de maneira acessível, por assim dizer, para compartilhar minha experiência.
O material é projetado principalmente para iniciantes, que é o meu caso.
Como eu entendo: Fundamentos
Em quase todos os lugares, argumenta-se que as redes neurais são boas em reconhecer padrões e fala-se sobre o fato de que um critério muito importante é os dados que transferimos para a rede neural para treinamento. Esse é um bom ponto de partida. Vamos utilizar a geometria, ou seja, vamos enviar formas geométricas para a rede neural. Para começar, vamos pegar um perceptron regular, um que encontrei aqui (MTC Combo - Expert Advisor para MetaTrader 4). Durante os testes, decidi abandonar os osciladores e usar o MA. Não consegui bons resultados quando usei osciladores. Eu assumo que todos provavelmente estão habituados ao fato de que quando o preço está subindo e o oscilador está descendo, isso é chamado de divergência. Os valores do MA estão mais próximos do preço em si.
Formas e linhas
Vamos pegar dois indicadores de média móvel como base, com parâmetros 1 e 24, e método Simple aplicado a Close. Dito de outra forma, a ideia não é apenas enviar a posição atual dos indicadores para a rede neural, mas também para o estado em que eles se encontravam antes do estado atual. Em muitos dos exemplos que vi, o preço é enviado diretamente para a rede neural, o que eu acho que é fundamentalmente errado.
Todos os valores são enviados em pontos, o que também é muito importante, estes valores têm um certo intervalo que não podem exceder. Não faz sentido simplesmente enviar o preço para a rede neural, o preço pode ir em faixas diferentes por 10 anos, por exemplo. Tenha também em mente que podemos utilizar diferentes números de indicadores na construção das formas. As formas podem ser complexas ou simples. Abaixo estão alguns exemplos de algumas das opções. Naturalmente, você também pode criar as suas próprias.
Distâncias em pontos nas velas fechadas 1, 4, 7 e 10 entre os indicadores MA 1 e MA 24.
double perceptron1() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In2[1])/Point(); double a2 = (ind_In1[4]-ind_In2[4])/Point(); double a3 = (ind_In1[7]-ind_In2[7])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Forma 2: linhas simples
Distâncias em pontos entre as velas fechadas 1-4, 4-7 e 7-10 do indicador MA 1.
double perceptron2() { double w1 = y1 - 100.0; double w2 = y2 - 100.0; double w3 = y3 - 100.0; double a1 = (ind_In1[1]-ind_In1[4])/Point(); double a2 = (ind_In1[4]-ind_In1[7])/Point(); double a3 = (ind_In1[7]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3); }
Forma 3: linhas simples
Distâncias em pontos entre as velas fechadas 1-4, 4-7 e 7-10 do indicador MA 24.
double perceptron3() { double w1 = z1 - 100.0; double w2 = z2 - 100.0; double w3 = z3 - 100.0; double a1 = (ind_In2[1]-ind_In2[4])/Point(); double a2 = (ind_In2[4]-ind_In2[7])/Point(); double a3 = (ind_In2[7]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3); }
Forma 4: borboleta (envelope)
Distâncias em pontos entre as velas fechadas 1-10 do indicador MA 1. E a distância em pontos entre as velas fechadas 1-10 do indicador MA 24. Distância em pontos entre a vela 1 do indicador MA 1 e a vela 10 do indicador MA 24. Distância em pontos entre vela 1 do indicador MA 24 e a vela 10 do indicador MA 1. O resultado será uma borboleta.
double perceptron4() { double w1 = f1 - 100.0; double w2 = f2 - 100.0; double w3 = f3 - 100.0; double w4 = f4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/Point(); double a2 = (ind_In2[1]-ind_In2[10])/Point(); double a3 = (ind_In1[1]-ind_In2[10])/Point(); double a4 = (ind_In2[1]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Forma 5: quadrilátero
Distâncias em pontos entre as velas fechadas 1-1, 10-10 entre indicadores. E a distância em pontos entre as velas 1-10 do indicador MA 1 e a distância em pontos entre as velas 1-10 do indicador MA 24. O resultado é um quadrilátero.
double perceptron5() { double w1 = c1 - 100.0; double w2 = c2 - 100.0; double w3 = c3 - 100.0; double w4 = c4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/Point(); double a2 = (ind_In2[1]-ind_In2[10])/Point(); double a3 = (ind_In1[1]-ind_In2[1])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Forma 6: complexa
Aqui vamos combinar todas as formas acima em uma complexa.
double perceptron6() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double w5 = y1 - 100.0; double w6 = y2 - 100.0; double w7 = y3 - 100.0; double w8 = z1 - 100.0; double w9 = z2 - 100.0; double w10 = z3 - 100.0; double w11 = f1 - 100.0; double w12 = f2 - 100.0; double w13 = f3 - 100.0; double w14 = f4 - 100.0; double a1 = (ind_In1[1]-ind_In2[1])/Point(); double a2 = (ind_In1[4]-ind_In2[4])/Point(); double a3 = (ind_In1[7]-ind_In2[7])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); double a5 = (ind_In1[1]-ind_In1[4])/Point(); double a6 = (ind_In1[4]-ind_In1[7])/Point(); double a7 = (ind_In1[7]-ind_In1[10])/Point(); double a8 = (ind_In2[1]-ind_In2[4])/Point(); double a9 = (ind_In2[4]-ind_In2[7])/Point(); double a10 = (ind_In2[7]-ind_In2[10])/Point(); double a11 = (ind_In1[1]-ind_In1[10])/Point(); double a12 = (ind_In2[1]-ind_In2[10])/Point(); double a13 = (ind_In1[1]-ind_In2[10])/Point(); double a14 = (ind_In2[1]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4 + w5 * a5 + w6 * a6 + w7 * a7 + w8 * a8 + w9 * a9 + w10 * a10 + w11 * a11 + w12 * a12 + w13 * a13 + w14 * a14); }
Ângulos
Vamos ver outro método muito interessante que nos permite transferir dados de preços para o perceptron, especificamente, os ângulos dos indicadores. Estes dados também não podem exceder um determinado intervalo, o que é bom para podermos veicular algum tipo de padrão. Assim como no caso anterior com formas e linhas.
Encontrei muitos métodos para determinar os ângulos, mas muitos deles dependem da escala do gráfico de preços, o que não é bom para nós. A solução é calcular não o ângulo, mas, sim, a tangente do ângulo, usando a razão entre o número de pontos e o número de barras. A tangente do ângulo tg(α) é a razão entre o cateto oposto a e o cateto adjacente b.
Também é possível realizar uma análise, usando um número diferente de indicadores, processando estruturas complexas e empregando um número diferente de velas. Nas capturas de tela, os ângulos de inclinação são mostrados como linhas não fixas. Vejamos alguns exemplos.
Inclinação do indicador MA 1 entre as velas 1-4, entre as velas 1-7, entre as velas 1-10.
double perceptront1() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double a1 = (ind_In1[1]-ind_In1[4])/4; double a2 = (ind_In1[1]-ind_In1[7])/7; double a3 = (ind_In1[1]-ind_In1[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3); }
Inclinação do indicador MA 1 entre as velas 1-5, entre as velas 1-10. Inclinação do indicador MA 24 entre as velas 1-5, entre as velas 1-10.
double perceptront2() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[5])/5; double a2 = (ind_In1[1]-ind_In1[10])/10; double a3 = (ind_In2[1]-ind_In2[5])/5; double a4 = (ind_In2[1]-ind_In2[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Perceptront3. 4 ângulos do indicador MA 1 e MA 24 (construção mais ou menos complexa, como exemplo)
Os ângulos são ligados pela inclinação entre os dois indicadores, MA 1 e MA 24.
double perceptront3() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/10; double a2 = (ind_In2[1]-ind_In1[4])/4; double a3 = (ind_In2[1]-ind_In1[7])/7; double a4 = (ind_In2[1]-ind_In1[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Perceptront4. 4 ângulos do indicador MA 1 e MA 24 (construção mais ou menos complexa, como exemplo)
Os ângulos são ligados pela inclinação entre os dois indicadores, MA 1 e MA 24.
double perceptront4() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/10; double a2 = (ind_In2[1]-ind_In1[10])/10; double a3 = (ind_In1[1]-ind_In1[10])/10; double a4 = (ind_In2[1]-ind_In2[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
Estratégia
Decidi usar uma estratégia de contra-tendência para treinamento, especificando-a explicitamente no código abaixo. Para venda, o indicador MA 1 está na primeira vela acima do indicador MA 24. Para compra, o mesmo mas espelhado. A partir de minhas observações, isto é necessário para uma separação explícita entre venda e compra. Você pode fazer o oposto e usar a tendência.
Você também pode usar outros indicadores ou seus valores, como o indicador TEMA. É quase impossível prever o preço de um movimento de 400 pontos em um mercado de cinco dígitos; ninguém sabe aonde o mercado irá se movimentar. É por essa razão que, para realizar o teste, defini um stop loss fixo de 600 pontos e um take profit de 60 pontos com cinco dígitos. Para não sobrecarregar o artigo com linhas desnecessárias e não perder o intuito, você pode baixar os EAs prontos anexos ao artigo. Vejamos os resultados.
//SELL++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1[1]>ind_In2[1]) && (perceptron1()<0) &&(SpreadS1<=MaxSpread)){//v1 OpenSell(symbolS1.Name(), LotsXSell, TakeProfit, StopLoss, EAComment); } //BUY++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1[1]<ind_In2[1]) && (perceptron1()>0) && (SpreadS1<=MaxSpread)){//v1 OpenBuy(symbolS1.Name(), LotsXBuy, TakeProfit, StopLoss, EAComment); }
Otimização, testes e recursos
A otimização de redes neurais, como você sabe, requer grandes recursos computacionais. Por isso, ao utilizar o testador de estratégia para este fim, recomendo a modalidade (apenas preços de abertura) com uma indicação explícita de preços de fechamento no próprio código, caso contrário, esta tarefa dificilmente será viável com nossas bastante modestas capacidades. Nesses modos de otimização, recomendo o serviço (Cloud Network). O objetivo da otimização é que nossos perceptrons encontrem algum tipo de padrão que nos permita obter lucro. A ocorrência de tais padrões, ou seja, o número de negócios lucrativos deve ser maior que os negócios perdedores em nosso caso. Tudo depende da proporção entre StopLoss e TakeProfit.
Em antecipação, eu realizei 10 otimizações de cada EA continuamente. O problema é que existem muitos valores de otimização, o que leva a resultados de cerca de 10.000-15.000 por passagem nesse modo (Algoritmo Genético). Assim, quanto mais corridas, mais chances de encontrar os valores desejados dos coeficientes de peso. Este problema precisa ser resolvido por meio do MQL5. Eu realmente não quero desistir do testador de estratégia.
O passo de 5 valores de otimização, ao contrário do artigo acima onde o passo é 1, não é escolhido por acaso. Durante os experimentos, notei que isto gera resultados mais dispersos no peso do perceptron, o que tem um melhor efeito sobre os resultados.
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modalidades (somente preços de abertura), (algoritmo genético), (rentabilidade máxima) .
- Depósito inicial 10 000.
- TakeProfit = 60, StopLoss = 600.
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e testes forward.
Como vemos, os resultados são deploráveis. O melhor resultado é 0,87. Não vale a pena realizar testes forward. Seguimos em frente.
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modalidades (somente preços de abertura), (algoritmo genético), (rentabilidade máxima) .
- Depósito inicial 10 000.
- TakeProfit = 60, StopLoss = 600.
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e testes forward.
O resultado é muito parecido com o anterior. O melhor resultado é 0,94.
Otimizamos o EA perceptron 4 forma 4. (Quatro perceptrons com quatro formas diferentes).
O código básico é assim:
//SELL++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1[1]>ind_In2[1]) && (perceptron1()<0) && (perceptron2()<0) && (perceptron3()<0) && (perceptron4()<0) && (SpreadS1<=MaxSpread)){//v1 OpenSell(symbolS1.Name(), LotsXSell, TakeProfit, StopLoss, EAComment); } //BUY++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1[1]<ind_In2[1]) && (perceptron1()>0) && (perceptron2()>0) && (perceptron3()>0) && (perceptron4()>0) && (SpreadS1<=MaxSpread)){//v1 OpenBuy(symbolS1.Name(), LotsXBuy, TakeProfit, StopLoss, EAComment); }
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modos (somente preços de abertura), (algoritmo genético), (Máximo critério complexo) .
- Depósito inicial 10 000.
- Take Profit = 200, Stop Loss = 200.
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e testes forward.
Data de teste forward de 2021.05.31 a 2022.05.31. É necessário selecionar dos resultados aquele com o maior fator de lucro com um máximo critério complexo maior que 40-50.
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modos (somente preços de abertura), (algoritmo genético), (lucro máximo).
- Depósito inicial 10 000.
- Take Profit = 60, Stop Loss = 600
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e testes forward.
O resultado foi obtido. O melhor resultado é 32. Vamos alterar a data de 31/05/2021 para 31/05/2022 e realizar o teste forward. É necessário selecionar entre os resultados aquele com o maior fator de lucro com um número mínimo de negócios, de pelo menos 10-20.
Otimizamos o EA perceptron 4 tangente 4. (Quatro perceptrons com quatro ângulos diferentes).
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modos (somente preços de abertura), (algoritmo genético), (Máximo de critério complexo).
- Depósito inicial 10 000.
- Take Profit = 200, Stop Loss = 200.
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e teste forward.
Data de teste forward de 2021.05.31 a 2022.05.31. É preciso selecionar dos resultados aquele com o maior fator de lucro com o máximo critério complexo maior que 20-40.
- Data de otimização de 31/05/2010 a 31/05/2021.
- Modos (somente preços de abertura), (algoritmo genético), (lucro máximo).
- Depósito inicial 10 000.
- TakeProfit = 60, StopLoss = 600.
- Período H1.
- Lote fixo 0,01.
- Parâmetros otimizados x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - coeficientes de peso do perceptron. Otimiza-se com valores de 0 a 200 com incrementos de 5
Resultados de otimização e testes forward.
O resultado foi obtido. O melhor resultado é 32. Deixarei o teste forward para a lição de casa. Acho que vai ser mais interessante. Além disso, é preciso notar que o número de negócios em relação ao fator lucro aumentou.
No decorrer de minhas experiências, surgiram vários problemas que precisam ser resolvidos, isto é:
- Primeiro. Devido à complexidade de otimizar um número tão grande de parâmetros, é necessário transferir esses parâmetros dentro do código EA, isto é, os parâmetros dos coeficientes de peso.
- Segundo. Criação de algum tipo de banco de dados para todos os parâmetros otimizados e depois os utilizamos no EA para negociar ao mesmo tempo. Acho que seria possível utilizar arquivos *.CSV.
Considerações finais
Espero muito sinceramente que minhas experiências o conduzam a novas descobertas, reflexões e, no final, ao sucesso. O objetivo era ter uma estratégia pronta e lucrativa. Conseguimos isso em parte obtendo bons resultados nos testes forward. Então, o que fazemos com o que temos? Ainda há muito trabalho a fazer. Devemos começar a utilizar sistemas mais complexos sem esquecer a experiência adquirida. Temos que utilizar também de forma mais ampla o que está disponível. Falaremos sobre isso, e mais, na segunda parte de nossas experiências. Isso vai ser interessante. Não pode deixar passar.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/11077
- 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