Aplicação prática de redes neurais no trading. Embarquemos na prática

Andrey Dibrov | 12 outubro, 2020

Introdução

No artigo anterior "Aplicação prática de redes neurais no trading" descrevi de maneira geral como construir um sistema de negociação usando módulos de redes neurais (MRN). Neste artigo, quero sugerir experimentar o que são MRN na prática, bem como construir um sistema de negociação automático com base neles.

Neste artigo, trabalharemos com o par de moedas EURUSD. No entanto, o próprio módulo de rede neural, como programa, é universal e pode funcionar com vários instrumentos e suas combinações. Ou seja, como variação, você pode usar um MRN integrando redes neurais treinadas para diferentes pares de moedas.

A abordagem de como preparar dados históricos para treinamento de redes neurais do MRN está além do escopo deste artigo. Ao MRN serão anexadas redes neurais já treinadas com base em dados históricos aproximados por tempo no momento da publicação do artigo.

Também gostaria de notar que o MRN está completamente pronto para usar no trading. Para realizar uma apresentação concisa deste artigo, tive que modernizá-lo um pouco de forma a combinar várias funções da MRN num programa. Por isso, transferi do EA para o programa (MRN) determinadas condições para realizar trades. No entanto, a transferência de condições se aplica à parte do MRN que se destina à negociação real. Quanto ao teste da rede neural e à otimização de sua respostas no modo offline, naturalmente deleguei essas funções e condições de trade aos EAs correspondentes. Embora, eu prefira um módulo de rede neural com só uma função para realizar trades, eu sou daqueles que apóiam ideia de que um MRN deve ser tão simples quanto possível, sem quaisquer funções adicionais, e deixar a funções em si fora do complexo de negociação, Neste caso, elas são de treinamento, teste, otimização. Quanto às condições para realização de trades, é melhor tê-las no MRN para receber dele os sinais em forma binária. Todas as variantes de execução do MRN na prática confirmam que são viáveis.

Eu proponho num próximo artigo nós debruçar mais amplamente sobre uma abordagem para preparar e treinar um MRN na plataforma Matlab.

Além disso, no futuro pretendo transferir o sistema para Python. No final do artigo, você também pode assistir a um vídeo sobre esse assunto.

Os MRN dão resultados positivos em períodos de teste mais longos quando são treinados com base em dados históricos recebidos de corretoras com as quais realizamos tradign online. Certamente, é possível tentar unificar esse ponto, mas acho que não faz muito sentido levar a cabo isso. 

Módulo de rede neural EURUSD_MT5

Abaixo está um módulo de rede neural sendo inicializado pela primeira vez.

MRN EURUSD_MT5

  1. O bloco "Online" é projetado para iniciar e parar redes neurais durante o trabalho real e o teste no modo de visualização.
  2. Campos de condições especificando o cruzamento entre a linha de resposta das redes neurais e a linha de sinal quando o bloco "Online" é ativado. 
  3. O bloco "Train" é um bloco de demonstração projetado para aprendizado e "treinamento adicional!!?" de redes neurais.
  4. Campos de exibição dos valores de resposta das redes neurais. Os da esquerda são a resposta das redes neurais, já os da direita, a linha de sinal. Os inferiores são a barra atual, já os superiores, a anterior.
  5. O bloco "Off-line" é projetado para exibir num arquivo uma matriz de respostas das redes neurais de uma amostra de teste.
  6. Janela para inserir o valor da média da linha de resposta das redes neurais ao usar o bloco "Online". Período da linha de sinal. Valor modificável.
  7. Os blocos "Net1,2,3" são três submódulos de redes treinados em diferentes partes da série temporal. Cada bloco inclui duas redes neurais.
  8. Data de término de operação do MRN quando o bloco "Online" é ativado.
  9. Janela para inserir o período de operação do MRN em horas quando o bloco "Online" é ativado. Valor modificável.
  10. Contagem regressiva do tempo decorrido desde o início do MRN quando o bloco "Online" é ativado.

Aplicativos

  1. MyAppInstaller_mcr.exe é o arquivo de instalação.
  2. EURUSD_MT5.exe é o próprio módulo de rede neural.
  3. EURUSD_MT5var.exe é uma variante do módulo de rede neural.
  4. net1-net6.mat são redes neurais de três submódulos Net1-Net3, para exemplificar seu treinamento e teste. 
  1. ExpertMatlabPodkach_MT5.mq5 e ExpertMatlab_MT5.mq5 são dois EAs necessários para preparar dados históricos para teste off-line do MRN.
  2. NWI.mq5 é um indicador para apresentação visual das respostas do MRN.
  3. Matlab_MT5.mq5 é um EA para testar e otimizar a resposta NSM no testador de estratégia.
  4. ExpertMatlabReal_MT5.mq5 é um EA para trabalho on-line em contas reais ou demo, bem como para teste no modo de visualização.
  5. EURUSDData.csv é o arquivo com dados de treinamento.

Instalando o programa



Antes de usar aplicativos compilados em Matlab pela primeira vez, deve-se usar MyAppInstaller_mcr.exe. Com ajuda de este aplicativo iremos instalar o MATLAB Runtime e o próprio módulo de rede neural.

Após instalar o programa, colocamos o atalho EURUSD_MT5.exe na pasta ...\Common\Files do diretório de dados. Fazemos isso por conveniência no momento do inicialização do sistema. Todos os EAs e MRN gravam arquivos nesta pasta, sendo que, ao iniciar o MRN, este último solicita a pesquisar arquivos do diretório onde está localizado o atalho. 

Arquivo EURUSD_MT5

1. Atalho EURUSD_MT5

Atribuímos uma pasta de trabalho.

Escrevemos o caminho

2. Escrevemos o caminho


Uso prático

A seguir, temos quatro variantes de uso do MRN:

  1. Negociação on-line em contas demo ou reais.
  2. Teste de MRN no modo de visualização.
  3. Treinamento de redes neurais.
  4. Recepção de respostas vindas de blocos de rede neural para otimizar uma estratégia de negociação.

Aqui você pode dizer que seria mais lógico considerar essas variantes seguindo uma sequência diferente. No entanto, devo destacar que em sua forma inicial, o módulo de rede neural foi projetado para executar a primeira variante de uso. Estou mais inclinado a esse tipo de implementação. E a segunda, terceira e quarta variantes foram retiradas fora do MRN, uma vez que podem ser realizadas durante a configuração geral do sistema. Nesta performance, combinei todas essas etapas num monobloco para facilitar o entendimento do processo de preparação geral do sistema para o trabalho real.

Vejamos essa variantes em mais detalhes.

1. Negociação on-line em contas demo ou reais


Como podemos ver, a inicialização do sistema leva menos de cinco minutos.

Primeiro devemos configurar o Excel. A configuração consiste em fazer com que os dados dos scripts e EAs sejam gravados nas células em formato numérico. Caso contrário, o Matlab não é capaz de ler esses dados corretamente. Para fazer isso, precisamos definir o ponto como separador das partes inteiras e fracionárias dos números, ou usando "separadores do sistema" ou diretamente.

Parâmetros do Excel

3. Parâmetros do Excel

Antes da inicialização inicial do MRN, em primeiro lugar, precisamos criar um arquivo de permuta de histórico com a ajuda de um EA. Iniciamos o Expert Advisor ExpertMatlabPodkach_MT5.ex5 no testador de estratégia. 


    Gráfico

Iniciamos o ExpertMatlabPodkach_MT5

4. Iniciamos ExpertMatlabPodkach_MT5.ex5

Como podemos ver, o momento de inicialização do Expert Advisor deve ser escolhido de forma que o período antes do início de operação cubra três dias.

Obtemos o arquivo EURUSDTestPodkach.csv.


Arquivo EURUSDPodkach_MT5

5. Arquivo EURUSDTestPodkach.csv


Abrimos este arquivo e fazemos alterações apagando todas as linhas, exceto a linha com dados no momento da abertura na última hora do dia anterior ao dia em que o sistema é iniciado.

Excluímos as linhas

6. Excluímos as linhas


Agora podemos iniciar o Expert Advisor ExpertMatlabReal_MT5.ex5.

#include<Trade\Trade.mqh>
//--- объект для проведения торговых операций
CTrade  trade;

input int LossBuy;
input int ProfitBuy;
input int LossSell;
input int ProfitSell;

int BarMax;
int BarMin;
int handleInput;
int handleInputPodkach;
int handleBar;
int Con;
int Bar;

double DibMax;
double DibMin;

double in[32];

int Order01;
int Order1;

ulong TicketBuy1;
ulong TicketSell0;

bool send1;
bool send0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   handleInputPodkach=FileOpen("EURUSDTestPodkach.csv",FILE_READ|FILE_CSV|FILE_ANSI|FILE_COMMON,";");
   if(handleInputPodkach==INVALID_HANDLE)
      Alert("Отсутствует файл EURUSDTestPodkach.csv");

   in[0]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[1]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[2]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[3]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[4]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[5]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[6]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[7]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[8]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[9]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[10]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[11]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[12]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[13]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[14]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[15]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[16]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[17]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[18]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[19]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[20]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[21]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[22]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[23]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[24]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[25]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[26]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[27]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[28]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[29]=1/StringToDouble(FileReadString(handleInputPodkach))-1;

   FileClose(handleInputPodkach);

//--- зададим MagicNumber для идентификации своих ордеров
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- установим допустимое проскальзывание в пунктах при совершении покупки/продажи
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- режим заполнения ордера, нужно использовать тот режим, который разрешается сервером
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- какую функцию использовать для торговли: true - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   FileClose(handleInput);
   FileClose(handleBar);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlDateTime stm;
   TimeToStruct(TimeCurrent(),stm);

   if(stm.hour==1)
      DibMax=iHigh(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iHigh(NULL,PERIOD_H1,1)>DibMax && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[20]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[21]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[22]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[23]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[24]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iHigh(NULL,PERIOD_H1,1)>DibMax)
      DibMax=iHigh(NULL,PERIOD_H1,1);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(stm.hour==1)
      DibMin=iLow(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iLow(NULL,PERIOD_H1,1)<DibMin && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[25]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[26]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[27]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[28]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[29]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iLow(NULL,PERIOD_H1,1)<DibMin)
      DibMin=iLow(NULL,PERIOD_H1,1);

   in[30]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
   in[31]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);

   if(Bar<Bars(NULL,PERIOD_H1)&& stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }


   handleInput=FileOpen("Input_mat.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleInput,

             1/(in[0]+1),1/(in[1]+1),1/(in[2]+1),1/(in[3]+1),1/(in[4]+1),1/(in[5]+1),1/(in[6]+1),1/(in[7]+1),1/(in[8]+1),1/(in[9]+1),1/(in[10]+1),1/(in[11]+1),1/(in[12]+1),1/(in[13]+1),1/(in[14]+1),1/(in[15]+1),
             1/(in[16]+1),1/(in[17]+1),1/(in[18]+1),1/(in[19]+1),1/(in[20]+1),1/(in[21]+1),1/(in[22]+1),1/(in[23]+1),1/(in[24]+1),1/(in[25]+1),1/(in[26]+1),1/(in[27]+1),1/(in[28]+1),1/(in[29]+1),1/(in[30]+1),1/(in[31]+1));

   FileClose(handleInput);

   handleBar=FileOpen("Bar.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleBar,stm.hour);

   FileClose(handleBar);

   Order01=FileOpen("Open1.txt",FILE_CSV|FILE_READ|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON," ");

   Order1=StringToInteger(FileReadString(Order01));
   
   FileClose(Order01);

   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
   double PriceAsk=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double PriceBid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   double SL1=NormalizeDouble(PriceBid-LossBuy*point,digits);
   double TP1=NormalizeDouble(PriceAsk+ProfitBuy*point,digits);
   double SL0=NormalizeDouble(PriceAsk+LossSell*point,digits);
   double TP0=NormalizeDouble(PriceBid-ProfitSell*point,digits);

   if(Bar<Bars(NULL,PERIOD_H1))
      Con=0;

   Comment(Order1,"  ",Con);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

   if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;

   if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;


//---------Buy0

   if(send1==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>15 && stm.hour<20)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }
//---------Sell0
   if(send0==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>
        11 && stm.hour<14)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
//-----------------------------------------------------------------------
   Bar=Bars(NULL,PERIOD_H1);
   Con++;
  }
//------------------------------------------------------------------------

Gostaria de notar que, quanto aos limites de tempo num EA projetado diretamente para negociar, eu prefiro defini-los no próprio código após a otimização. E faço isso para minimizar o risco de cometer um erro e alterar ou não alterar acidentalmente essas restrições de tempo em variáveis externas.

ExpertMatlabReal_MT5

7. Iniciamos ExpertMatlabReal_MT5.ex5

Mas num Expert Advisor projetado para otimização, eles já devem ser escritos como variáveis externas.

Matlab_MT5.ex5

7.1 Matlab_MT5.ex5

Se nos esquecermos de criar um arquivo de permuta, receberemos um aviso para que o Expert Advisor não comece a dar sinais falsos.

Alerta

8. Alerta


Na pasta ...\Common\Files, o EA gravará dois arquivos. No arquivo Input_mat.txt, estão localizados os dados de entrada para o MRN.

Resposta do EA

9. Resposta do EA

Iniciamos o módulo de rede neural EURUSD_MT5.exe. Esperamos até que apareça a área de trabalho.

Área de trabalho

10. Área de trabalho do MRN


Nesta variante do programa, os parâmetros modificáveis dos blocos Net2 e Net3 não podem ser alterados.

Pressionamos o botão "Start" e selecionamos o arquivo net1.m (ou outro arquivo de rede neural).

Pressionamos o botão "Start"

11. Pressionamos o botão "Start"

Se você prestar atenção à imagem acima, verá que o MRN muda um pouco durante a preparação do artigo. No entanto, sua funcionalidade permanece a mesma.

Módulo de rede neural iniciando seu trabalho.

MRN negociando

12. MRN operando


Não podemos alterar nenhum parâmetro variável durante a operação do MRN.

No canto superior esquerdo do gráfico, vemos os números que o Expert Advisor recebe do MRN: 1.0, -1.0 e 0.0. Isso significa que o Expert Advisor recebe um sinal de compra (venda) do bloco Net1, do Net2, um para ficar fora do mercado, e do Net3, um sinal de venda (compra). Como esta versão do programa é apenas introdutória, não receberemos sinais variáveis dos blocos Net1 e Net2.

Neste exemplo, nosso sistema usa a linha de sinal com suavização de cinco horas da resposta do MRN. É por isso que para evitar o recebimento de um sinal falso inicial, o módulo deve ser iniciado cinco horas antes da realização de trades, partindo das condições de abertura de posições, bem como da mudança no parâmetro de suavização.

Quero notar imediatamente que o fato de usar o arquivo de permuta, "atirar informações através do disco" e esperar a paginação de dados é devido à necessidade de controlar as informações que chegam em ambas as direções. Os dados da janela do MRN no gráfico e nos arquivos Open1,2,3 devem ser idênticos.

Controle de informação

13. Controle de informação

A imagem mostra uma variante de um módulo de rede neural que transmite apenas a resposta vinda do net1, net2 e net3 para este EA. As condições para abrir posições são especificadas no Expert Advisor. Ressalto que eu prefiro esta variante. Em nosso caso, o MRN transmite um sinal pronto e o Expert Advisor negocia com base apenas no limite de tempo para realizar trades.

Este controle é especialmente útil ao depurar o sistema. E também é necessário fazer o controle visual durante os testes e negociação.

Variante do MRN

14. Variante do MRN

A imagem acima mostra outra variante do módulo de rede neural. Neste caso, é aconselhável integrar redes neurais diretamente no arquivo executável. Quando pressionamos o botão verde, só precisamos selecionar o arquivo Input_mat.txt. Para o trabalho, eu recomendaria usar um modelo semelhante. Nesta versão, é deixado apenas o bloco para negociação, já os blocos para treinamento e teste são excluídos. Quero enfatizar que a aparente complexidade do sistema na fase de preparação durante o período de negociação se torna de uma simplicidade invejável. A principal análise do mercado ocorre no MRN instantaneamente por conta das redes neurais, enquanto o robô de negociação tem apenas que interpretar dois números, claro, se não usar outras condições de otimização. 

 if(send1==false && Order1==1)
     {
      send1=trade.Buy(1);
      TicketBuy1 = trade.ResultDeal();
     }

 if(send1==true && Order1==0)
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

Como conclusão, eu gostaria de enfatizar algumas diferenças na inicialização do Expert Advisor ExpertMatlabReal_MT4.ex4 para trabalhar com o terminal MetaTrader 4. Isso se deve às peculiaridades dos testadores de estratégia, à maneira como eles determinam os pontos finais dos testes. No MetaTrader 5, o final do teste é a última barra do dia anterior, já no MetaTrader 4, a barra atual. Portanto, no Expert Advisor para MetaTrader 4, apresentei a variável externa "Hours".

Variável externa "Hours"

14.1 Variável externa "Hours"

Com ajuda do ExpertMatlabPodkach_MT4.ex4, criamos um arquivo de permuta com uma linha para a barra atual, portanto, na primeira inicialização, definimos a hora da barra atual na variável "Hours". Após iniciar o Expert Advisor, vamos para suas propriedades e retornamos a variável como 0. Isso deve ser feito para que as mudanças de dados subsequentes ocorram às 00:00 horas.

Hours-0

14.2 Hours -0

2. Teste de MRN no modo de visualização


Com este teste concluímos a preparação, determinando finalmente que o módulo de rede neural nos dê o resultado que alcançamos, de igual maneira, preparando os dados para treinamento da rede neural, seu treinamento em si e a obtenção da matriz de respostas, de maneiras que possamos visualizá-las e, em seguida, otimizá-las. Para isso, vamos repetir as ações do primeiro ponto, ou seja, vamos iniciar o MRN como ao negociar. No testador de estratégia, iniciamos o Expert Advisor ExpertMatlabReal_MT5.ex5 usando visualização. No MetaTrader 5, vamos habilitar a simulação "OHLC em M1", já no MetaTrader 4, "Pontos de controle". Esses modelos devem ser usados para obter um resultado de teste confiável, uma vez que nossos trades serão realizados usando o MRN no próximo tick após a barra ser aberta. E se usarmos o modelo "Apenas preços de abertura", durante o teste, a abertura das posições será defasada numa barra. Neste modo, é conveniente considerar o atraso de resposta com ajuda do módulo EURUSD_MT5var.exe. No trabalho real, isso está fora de questão. Gostaria de ressaltar que este sistema mostra resultados quase idênticos para todos os tipos de teste. O que mais uma vez confirma sua viabilidade.

Visualização

Visualização

15. Modo visual


3. Treinamento de redes neurais


Esta versão de modo do módulo de rede neural é usado como uma mostra da etapa de treinamento e preparação das redes neurais para o trabalho real. Eu chamo de mostra apenas porque você não pode retreinar os dados da rede neural, uma vez que o módulo usa redes neurais já treinadas. Mas não há necessidade de introduzir tal submódulo no programa de trabalho, uma vez que realizamos o treinamento em modo off-line e é mais conveniente e confiável fazê-lo diretamente no ambiente MATLAB.

 Assim, por exemplo, para treinar duas redes neurais para o submódulo Net1, precisamos ter as próprias redes neurais net1-2 e o arquivo EURUSDData.csv com dados de treinamento no diretório ...\Common\Files.

Data

16. Arquivo com dados

Os dados de treinamento são reais e diretamente aqueles que são usados para preparar o sistema de negociação usando o bloco "Online". Aqui, gostaria de notar mais uma vez a vantagem de usar redes neurais para avaliar a situação do mercado. A tabela EURUSDData.csv tem 90 colunas, que são um conjunto de valores sequenciais dos dados de entrada da rede neural. Em outras palavras, são entradas. Para simplificarmos, imaginemos que cada coluna é um indicador que é preliminarmente calculado por um EA e que depois é extraído como valores para treinar uma rede neural. Afinal, é isso que fazemos off-line ao preparar um sistema de negociação. Agora imaginemos que deveríamos nos comprometer a analisar este conjunto de informações significativo diretamente num EA ativo durante a negociação.

No processo de redação deste artigo, alterei os nomes dos botões, a fim de melhorar a compreensão da ordem das ações.

Nomes de botões alterados

17. Novos nomes de botões


Ou seja, pressionando o botão “Train net1” e abrindo o arquivo net1.mat, treinaremos a rede neural net1 e a rede neural net2 para o bloco Net1. E assim por diante, net3.4 para Net2 e net5.6 para Net3.

Train net1

18. Train net1


Mais uma vez, ressalto que será mais conveniente não só colocar o atalho do aplicativo na pasta onde os arquivos de trabalho estão localizados, mas também alterar o caminho para a "Pasta de trabalho" em suas propriedades. Em seguida, o MRN começará a treinar as redes neurais.

4. Recepção de respostas vindas de blocos de rede neural para otimizar uma estratégia de negociação


Eu adicionei ao módulo de rede neural a capacidade de testar redes neurais no modo off-line, em particular a possibilidade de obter uma resposta das redes neurais sobre os dados históricos, com o objetivo de gerar um indicador de sinal do sistema e sua posterior otimização. Como exemplo, vamos obter respostas históricas vindas de Net1.

Como mencionado, na pasta ...\AppData\Roaming\MetaQuotes\Terminal\Common\Files preparamos o arquivo EURUSDTestPodkach_MT5.csv. Para fazer isso, no testador de estratégia, iniciamos o EA ExpertMatlabPodkach_MT5. Naturalmente, fazemos isso somente a partir da data anterior à data de início do teste (observe que foi carregado o volume de histórico necessário).

Por exemplo:

Podkach

19. Iniciamos ExpertMatlabPodkach_MT5.ex5


No arquivo resultante, excluímos todas as linhas, exceto uma.

EURUSDTestPodkach

20. Deixamos uma linha


Para gerar um arquivo com dados para o período de teste, iniciamos o ExpertMatlab_MT5.ex5 no testador de estratégia.

ExpertMatlab

21. Iniciamos o ExpertMatlab_MT5.ex5

Observe como escolhemos a data de início do período.


EURUSDTest, EURUSDDate

22. Obtemos EURUSDTest.csv e EURUSDDate.csv


ExpertMatlab_MT5.ex5 gera os dois arquivos de teste EURUSDDate.csv e EURUSDTest.csv. Iniciamos o módulo de rede neural, pressionamos o botão "Test net1" e selecionamos net1.mat.

Test net1

23. Pressionamos o botão "Test net1"

Precisamos esperar algum tempo até que o arquivo de resposta Indicator1.csv seja gerado.

Indicator1

24. Obtemos o arquivo de resposta Indicator1.csv


Salvamos o Indicator1 como Indicator. Além disso, se "Indicator1.csv" for salvo pela unidade de rede neural em "Modo de compatibilidade", devemos salvá-lo no formato "csv" na guia "Salvar como".

Indicator

25. Salvamos Indicator1.csv como Indicator.csv


Vemos quais são as respostas do MRN visualmente no gráfico EURUSD H1. Para fazer isso, usaremos o indicador NWI.ex5.

NWI

26. Iniciamos o indicador NWI.ex5

Por padrão, o período é 5. Só quero mencionar que no momento este período de linha de sinal é o mais produtivo segundo meus experimentos em EURUSD H1. No entanto, você pode experimentar.

NWI

27. Exibição de NWI


Com a ajuda do EA Matlab_MT5.ex5, podemos testar e, depois, otimizar as respostas recebidas.

#include<Trade\Trade.mqh>

CTrade  trade;

input int Период=5;
input int H1;
input int H2;
input int H3;
input int H4;

input int LossBuy;
input int ProfitBuy;
input int LossSell;
input int ProfitSell;

ulong TicketBuy1;
ulong TicketSell0;

datetime Count;

double Per;
double Buf_0[];
double Buf_1[];

bool send1;
bool send0;

int h=4;
int k;
int K;
int bars;
int Handle;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      StringToTime(FileReadString(Handle));
      bars++;
     }
   FileClose(Handle);

   ArrayResize(Buf_0,bars);
   ArrayResize(Buf_1,bars);

   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      Count=StringToTime(FileReadString(Handle));
      Buf_0[k]=StringToDouble(FileReadString(Handle));
      h=Период-1;
      if(k>=h)
        {
         while(h>=0)
           {
            Buf_1[k]=Buf_1[k]+Buf_0[k-h];
            h--;
           }
         Buf_1[k]=Buf_1[k]/Период;
        }
      k++;
     }
   FileClose(Handle);

   int deviation=10;
   trade.SetDeviationInPoints(deviation);
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
   trade.SetAsyncMode(true);

//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   MqlDateTime stm;
   TimeToStruct(TimeCurrent(),stm);

   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
   double PriceAsk=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double PriceBid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   double SL1=NormalizeDouble(PriceBid-LossBuy*point,digits);
   double TP1=NormalizeDouble(PriceAsk+ProfitBuy*point,digits);
   double SL0=NormalizeDouble(PriceAsk+LossSell*point,digits);
   double TP0=NormalizeDouble(PriceBid-ProfitSell*point,digits);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

//---------Buy1
   if(send1==false && K>0 && Buf_0[K-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>H1 && stm.hour<H2 && H1<H2)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true && K>0 && Buf_0[K-1]>Buf_1[K-1] && Buf_0[K]<Buf_1[K] && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

//---------Sell0

   if(send0==false && K>0 && Buf_0[K-1]>Buf_1[K-1] && Buf_0[K]<Buf_1[K] && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>H3 && stm.hour<H4 && H3<H4)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true && K>0 && Buf_0[K-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
   K++;
  }

//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
//---

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

Matlab_MT5

Matlab_MT5

28. Iniciamos o Matlab_MT5.ex5

saldo da conta

29. saldo da conta

Chamo sua atenção para o fato de que não devem ser realizados testes forward. Após o backtest, o encaminhamento começa na próxima data, e o arquivo é carregado a partir da data inicial a partir da qual o backtest foi realizado. E, naturalmente, obteremos resultados incorretos.

Vamos realizar a otimização de imediato. Realizamos o teste anterior sem níveis restritivos e de acordo com o princípio de preparação do sistema, descrito no livro. Para otimização, também introduzimos níveis.

Optim

Optim

Optim

30. Fazemos a otimização

Até a linha vermelha 2011-2013, otimizações. Depois dela, 2013-2016, testes. É claro que não iremos negociar após a otimização durante um período tão longo. Além disso, as redes neurais precisam ser periodicamente retreinadas, segundo a prática, a cada mês. No gráfico, o período entre a linha vermelha e a linha azul é de 4 meses.

Testemos esse período separadamente.

Test

Test

Teste de referência Teste de referência

Teste de referência

31. Teste de referência

Observe que não fiz esses testes de propósito antecipadamente nem os ajustei, mas fiz tudo durante a redação desta seção do artigo. É claro que podem ser usadas outras variantes. E também é necessário preparar redes neurais com cobertura. Mas quero ressaltar mais uma vez o quanto as redes neurais simplificam a preparação do sistema, bem como a própria negociação.

Podemos dizer que as negociações emuladas durante este teste tiveram condições ideais. Por isso, tomaremos o resultado deste teste como padrão.

5. Trabalho em bugs

Enquanto trabalhava neste ponto, decidi voltar ao início e explicar por que ele é tão complicado. Acontece que o "Trabalho em erros" foi realizado em tempo real durante a redação desta seção. Em outros assuntos, como o anterior. Para o MetaTrader 4, tudo isso já foi resolvido, mas para o MetaTrader 5 eu tive que trabalhar neste modo. Para mim, pessoalmente, isso acabou sendo bastante útil... E gostaria de chamar a sua atenção mais uma vez para o fato de que a preparação da negociação deve ser feita de forma muito escrupulosa e sistemática.

É possível, ou melhor, mesmo necessário, voltar ao passo 2 e testar o resultado obtido (que chamamos de referência) ao simular a negociação no modo de visualização.

E obtivemos este resultado.

Relatório

32. Teste mal-sucedido

Embora o resultado seja positivo, é completamente diferente do anterior. Isso significa que em algum lugar do código do programa temos um erro e precisamos localizá-lo. E, neste caso, seremos ajudados pelo fato de podermos rastrear todas as etapas da transferência de informações.

Comparamos as respostas nos campos de saída de valores (4) do submódulo Net1 e as respostas MRN recebidas usando o Expert Advisor ExpertMtatlab_MT5.ex5, naturalmente, na mesma barra de tempo.

Comparamos as respostas do MRN

33. Comparamos as respostas do MRN

Como podemos ver, as respostas do submódulo Net1 e as respostas do MRN não correspondem. Com base nisso, concluímos que, como usamos o mesmo bloco de redes neurais, as informações recebidas em suas entradas durante esses dois testes são diferentes. 

Vamos comparar se são idênticas as informações nos arquivos EURUSDTest.csv e Input_mat.txt selecionando uma barra durante a operação do MRN.

Input_mat.txt

34. Comparamos se as informações são idênticas


Estávamos certos e as informações são muito diferentes. Isso significa que precisamos verificar o código do programa dos EAs ExpertMtatlab_MT5.ex5 e ExpertMatlabReal_MT5.ex5. 

ExpertMtatlab_MT5.ex5
if(stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }
ExpertMatlabReal_MT5.ex5
if(Bar<Bars(NULL,PERIOD_H1) && stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }

Como resultado, encontramos um erro no código do Expert Advisor ExpertMatlabReal_MT5.ex5. Não tínhamos a condição principal para a deslocamento de dados em 00 horas. E no trabalho real, nosso MRN receberia do terminal uma informação que não corresponderia ao que as redes deveriam receber. Como resultado, eles dariam uma "resposta falsa". Coloquei as aspas porque, na verdade, a própria rede neural dá uma resposta normal, mas para nós é falsa, pois não fornecemos as informações com base em nossas considerações.

Novamente comparamos as respostas nos campos de saída de valor (4) do submódulo Net1 e as respostas do MRN recebidas usando o Expert Advisor ExpertMtatlab_MT5.ex5. 

Comparamos as respostas do MRN

35. Comparamos as respostas do MRN

Concluímos que agora as informações que chegam ao MRN estão corretas.

Corrigimos esse erro e executamos outro teste no modo de visualização:


Test

36. O teste difere do de referência

Vemos que, embora o resultado já esteja um pouco mais próximo do resultado do teste pela matriz de respostas, ainda é significativamente diferente. E o módulo de rede neural para de funcionar por conta própria.

Como resultado da verificação, encontramos um erro nas condições para fechar uma posição de venda diretamente no EA ExpertMatlabReal_MT5.mq5. Realizamos outro teste no modo de visualização OHLC no M1.

Sem espera de tick

Sem espera de tick Sem espera de tick

Sem espera de tick

37. Teste sem espera de tick

O resultado ainda não corresponde, digamos, ao de referência.

Teste de referência

38. Referência

Depois de analisar este teste, podemos dizer que obtivemos o resultado de emular o trading em condições desfavoráveis. Isso se reflete num aumento no número de sinais falsos e, como resultado, de negociações desnecessárias. Exitem situações em que na barra anterior há um sinal para abrir uma posição, enquanto na abertura de uma nova barra o MRN nos dá um sinal para fazer um trade oposto ou ficar fora do mercado. No entanto, como realizarmos o teste num modo acelerado, as informações do MRN podem estar atrasadas e o Expert Advisor faz um trade com base no sinal anterior. Neste caso, um teste desse tipo é útil, pois nos dá a oportunidade de ver como o sistema se comporta sob condições adversas de nervosismo do mercado.

Vejamos que resultado obteremos se no Expert Advisor escrevermos restrições de abertura de posições para a situação descrita no parágrafo anterior.

 if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;
   
 if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;

//---------Buy

Realizaremos o teste em todos os ticks e com velocidade de visualização máxima. Você pode assistir ao processo no vídeo.

Teste com condições

Teste com condições Teste com condições

Teste com condições

39. Aproximamos-nos do teste de referência


Como podemos ver, o resultado está próximo da referência, embora eu ache que o teste anterior ficaria próximo da referência se reduzíssemos a velocidade do teste. Você pode experimentar por conta própria.


Vejamos por que o MRN parou. Eu poderia pular essa questão. Mas quero ressaltar que identificamos esse "bug" no programa no modo de teste e que ele é de natureza positiva. Afinal, poderíamos enfrentar esse problema durante o período de trading. Acontece que se as redes neurais no MRN não forem treinadas ou se iniciarmos o módulo antes da execução do EA sem termos gerado o arquivo Input_mat.txt, então ao pressionar o botão de ação "Start" o MRN não nos dará nenhuma resposta. Por outra parte, eu programei o aparecimento da janela de aviso com saída forçada desde o temporizador interno. Removi esse erro lógico e deixei o aviso. No entanto, se a janela aparecer no processo de trabalho, não tem nada de estranho. Basta clicar em "OK" para que a janela desapareça. Nesse caso, o programa irá funcionar sem interrupção.

Janela de erro

40. Janela de erro

Também há um outro problema que precisa de atenção. No MetaTrader 5 ao gravar dados usando o testador de estratégia, o número de barras exibidas é maior do que o que é exibido no gráfico. Isso significa que o indicador acaba sendo um pouco "mais comprido". No entanto, isso não afeta a qualidade dos testes. Já que ao executar o teste a barra extra é levada em consideração, mas não é exibida no gráfico. Isso pode ser verificado com uma execução passo a passo.

Indicador MT5

41. Indicador NWI em MT5

Indicador MT5

42. Vejamos a mudança de tempo

Este problema não existe no MetaTrader 4.

Indicador MT4

43. Indicador 1_MT4 no MetaTrader 4

Indicador MT4

44. Sem mudança de tempo

A imagem abaixo mostra porque acontece isso.

23:59

45. Encontramos o motivo da mudança

Fim do artigo

Quero insistir na questão: "por que as redes neurais existem, afinal?"

  1. As redes neurais nos permitem processar uma quantidade significativa de informações fora do mercado.
  2. O fato de processarmos as informações off-line nos dá a oportunidade não de correr atrás do mercado, mas, sim, de ir à frente dele, ou pelo menos acompanhando.
  3. E, como resultado disso, também nos permite levar em consideração prontamente as mudanças na situação do mercado, não apenas durante o período de negociação, mas também na fase de preparação para a negociação. Ou seja, assim podemos não incorrer em grandes perdas durante uma mudança de tendência ou durante quaisquer fatores que influenciam os mercados.
  4. Quanto à rede neural apresentada no artigo e ao método de treino, a vantagem indiscutível desta simbiose é que podemos realizar a otimização com base nas respostas recebidas no intervalo de tempo em realizado o treino. Ao contrário das redes neurais de outras arquiteturas que fornecem resultados excelentes para o período de treinamento e, ao mesmo tempo, os resultados para o segmento de teste diferem significativamente, os resultados apresentados aqui são aproximadamente idênticos. Isso nos dá a oportunidade de treinar a rede de uma forma densa até a atualidade e levar em consideração todos os fatores de mercado disponíveis no histórico. Eu não toquei estas questões no artigo, mas você pode explorá-lo sozinho.

Enquanto trabalhava no artigo, inicialmente queria integrar ao MRN apenas redes neurais para o bloco Net1 que foram treinadas no momento da publicação do artigo. No entanto, ao final, decidi integrar redes neurais treinadas em 31/12/2019 para Net2, e para Net3, até 31/12/2010. Seria interessante testá-los com base nas atuais condições de mercado. Para todos os outros tipos de trabalho no MRN, apenas serão usadas redes neurais para Net1.

Depois de baixar os arquivos

Peço desculpas pelo "vídeo lento", o processo foi filmado praticamente "num quadro".


Python