Discussão do artigo "Desenvolvendo um EA multimoeda (Parte 17): Preparação adicional para o trading real"

 

Novo artigo Desenvolvendo um EA multimoeda (Parte 17): Preparação adicional para o trading real foi publicado:

Atualmente, nosso EA utiliza um banco de dados para obter as strings de inicialização de instâncias individuais de estratégias de trading. No entanto, o banco de dados é bastante volumoso e contém muitas informações desnecessárias para a operação real do EA. Tentaremos garantir o funcionamento do EA sem a necessidade de conexão obrigatória ao banco de dados.

Em um dos artigos anteriores, já havíamos voltado nossa atenção para as melhorias necessárias no EA para operar em contas reais. Até então, nossos esforços estavam concentrados principalmente em obter resultados aceitáveis do EA no testador de estratégias. Contudo, o trabalho para avançar para a operação real não foi concluído. Ainda há muito a ser feito.

Além de restaurar o funcionamento do EA após reiniciar o terminal, a possibilidade de usar nomes ligeiramente diferentes para os instrumentos de trading e a finalização automática das operações ao atingir indicadores definidos, enfrentamos outro desafio: para formar a string de inicialização, utilizamos informações obtidas diretamente do banco de dados, onde são armazenados todos os resultados das otimizações das instâncias de estratégias de trading e seus grupos. 

Para iniciar o EA, é necessário que o arquivo do banco de dados esteja na pasta compartilhada dos terminais. O tamanho do banco de dados já ultrapassa vários gigabytes e continuará crescendo. Portanto, incorporar o banco de dados como parte integrante do EA não é racional, pois para a inicialização é necessária apenas uma pequena parte das informações armazenadas. Assim, é necessário implementar um mecanismo para extrair e utilizar essas informações no EA.

Разрабатываем мультивалютный советник (Часть 17): Дальнейшая подготовка к реальной торговле

Autor: Yuriy Bykov

 

Yuri, olá! Estou estudando seu código e não entendo nada.... No arquivo SimpleVolumesStrategy.mqh, no construtor, você tem um parâmetro:

         // Registre o manipulador de eventos da nova barra no período de tempo mínimo
         IsNewBar(m_symbol, PERIOD_M1);

Por que você faz isso? Por que exatamente o período M1, e não o atual, no qual essa instância de estratégia é iniciada? Pelo que entendi, nesse caso, o Expert Advisor não trabalhará por aberturas de barra de um determinado TF, mas simplesmente por m1. Ou estou entendendo algo errado?

E o segundo ponto - na função SignalForOpen() aqui:

      // Se o volume atual exceder o nível definido, então
      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // se o preço de abertura do candlestick for menor que o preço atual (fechamento), então
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {
            signal = 1; // sinal de compra
         } else {
            signal = -1; // caso contrário, um sinal de venda
         }
      }

Você indicou a barra 0 (atual) nos cálculos, embora me pareça que deveria haver a barra 1 (última fechada). É que a barra 0 no primeiro tick (se trabalharmos com preços de abertura) não tem corpo e, portanto, o preço de abertura é sempre igual ao preço de fechamento. E ela não pode ter nenhum volume porque ainda não foi formada. Posso estar entendendo algo errado, mas isso funciona de alguma forma.... Gostaria de entender por que é assim?

E também se eu quiser lançar algum parâmetro (novo) nessa estratégia, preciso criá-lo no Expert Advisor SimpleVolumesStage1.mq5 nas configurações e passá-lo para uma variável string lá, e depois nessa classe (SimpleVolumesStrategy.mqh) no construtor para analisar na ordem correta e é isso? Ou preciso prescrever isso em outro lugar?

 

Olá, Victor.

Зачем Вы это делаете? Почему именно период М1, а не текущий на котором запускается этот экземпляр стратегии? Как я понимаю в этом случае советник будет работать не по открытиям баров заданного ТФ а просто по м1. Или я что-то не правильно понимаю?

O trabalho do Expert Advisor consiste em duas partes: abertura de posições virtuais e sincronização das posições virtuais abertas com as reais. O TF definido é usado apenas na primeira parte para determinar o sinal de abertura. O ideal é que a sincronização seja realizada a cada tick ou, pelo menos, a cada nova barra do timeframe mínimo M1, pois a qualquer momento uma posição virtual pode atingir o TP ou o SL.

No método VirtualAdvisor::Tick(), há uma verificação no início da ocorrência de uma nova barra em todos os símbolos e timeframes monitorados, incluindo o M1. Se ela não tiver ocorrido, o Expert Advisor não executará mais nenhuma ação. Ele fará outra coisa somente quando uma nova barra ocorrer em M1. Nesse caso, você pode otimizar no modo OHLC em M1 e obter quase os mesmos resultados quando o EA trabalha no gráfico (onde há todos os ticks). E a otimização é muito mais rápida dessa forma. A linha de código que você mencionou é apenas uma rede de segurança para o caso de não precisarmos rastrear uma nova barra em M1 na estratégia. Dessa forma, é garantido que ela seja rastreada pelo menos em um símbolo.

Se quiser, você pode, é claro, desativar esse modo de operação por meio da variável useOnlyNewBars_ = false. Assim, o Expert Advisor verificará e sincronizará as posições em cada tick disponível.

Só que a barra 0 no primeiro tick (se trabalharmos compreços de abertura) não tem corpo, de modo que o preço de abertura é sempre igual ao preço de fechamento. E ela não pode ter nenhum volume porque ainda não foi formada. Posso estar entendendo algo errado, mas isso funciona de alguma forma...

A abertura de uma nova barra M1 pode ocorrer dentro de uma barra de um período de tempo superior. Observe que SignalForOpen() usa o timeframe atual, que geralmente é H1, M30 ou M15. Portanto, não haverá mais coincidência entre os preços de abertura e fechamento do timeframe atual. Além disso, essa verificação é feita somente quando o volume de ticks da barra atual no período de tempo atual excede significativamente o volume de ticks típico de uma barra. Isso não pode acontecer no primeiro tique, quando o volume do tique é apenas 1.

E também, se eu quiser lançar algum parâmetro (novo) nessa estratégia, preciso criá-lo no Expert Advisor SimpleVolumesStage1.mq5 nas configurações e passá-lo para uma variável de cadeia de caracteres e, em seguida, nessa classe (SimpleVolumesStrategy.mqh) no construtor para analisar na ordem correta e é isso? Ou há algum outro lugar em que você tenha que explicitar isso?

Com certeza.

 
Yuriy Bykov #:

O trabalho do Expert Advisor consiste em duas partes: abertura de posições virtuais e sincronização das posições virtuais abertas com as reais. O TF definido é usado somente na primeira parte para determinar o sinal de abertura. O ideal é que a sincronização seja realizada a cada tick ou, pelo menos, a cada nova barra do timeframe mínimo M1, pois a qualquer momento a posição virtual pode atingir o TP ou o SL.

No método VirtualAdvisor::Tick(), há uma verificação no início quanto à ocorrência de uma nova barra em todos os símbolos e timeframes monitorados, incluindo o M1. Se ela não tiver ocorrido, o Expert Advisor não executará mais nenhuma ação. Ele fará outra coisa somente quando uma nova barra ocorrer em M1. Nesse caso, você pode otimizar no modo OHLC em M1 e obter quase os mesmos resultados quando o EA trabalha no gráfico (onde há todos os ticks). E a otimização é muito mais rápida dessa forma. A linha de código que você mencionou é apenas uma rede de segurança para o caso de não precisarmos rastrear uma nova barra em M1 na estratégia. Dessa forma, é garantido que ela seja rastreada pelo menos em um símbolo.

Se quiser, você pode, é claro, desativar esse modo de operação por meio da variável useOnlyNewBars_ = false. Assim, o Expert Advisor verificará e sincronizará as posições em cada tick disponível.

Entendo. Mas, por exemplo, podemos fazer com que a sincronização de posições funcione em cada tick, e a abertura de posições virtuais (novas) ocorra quando uma nova barra ocorrer no TF especificado na estratégia (m15,m30,h1)?

Yuriy Bykov #:
A abertura de uma nova barra M1 pode ocorrer dentro de uma barra de um período de tempo superior. Observe que SignalForOpen() usa o timeframe atual, que geralmente é H1, M30 ou M15. Portanto, não haverá mais coincidência entre os preços de abertura e fechamento do timeframe atual. Além disso, essa verificação é feita somente quando o volume de ticks da barra atual no período de tempo atual excede significativamente o volume de ticks típico de uma barra. Isso não pode acontecer no primeiro tick, quando o volume do tick é de apenas 1.

Não estou entendendo um pouco aqui. Sim, SignalForOpen() usa o TF definido nas configurações da instância da estratégia virtual atual, isso eu posso ver. Mas, por exemplo, se eu quiser que o EA funcione estritamente nas últimas barras fechadas, terei de especificar unidades em vez de zeros.

      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // se o preço de abertura do candlestick for menor que o preço atual (fechamento), então
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {

Devo especificar unidades em vez de zeros? Entendi corretamente?

 
Viktor Kudriavtsev #:
Por exemplo, podemos fazer com que a sincronização de posições funcione em cada tick, e a abertura de posições virtuais (novas) ocorra quando uma nova barra ocorrer no TF especificado na estratégia (m15,m30,h1)?

Sim, esse será o caso se useOnlyNewBars_ = false. Essa variável não é usada pelas estratégias, pois elas mesmas determinam quando verificar se há um sinal de abertura e quando abrir posições quando um sinal é recebido anteriormente. Por exemplo, somente quando ocorrer uma nova barra no H1. Nesse caso, você deve modificar o código para que o sinal recebido no meio da barra sobreviva até o início da próxima barra. Agora, o sinal recebido é usado imediatamente (leva à abertura de posições virtuais), portanto, não é salvo em lugar algum.

Não estou entendendo um pouco aqui. Sim, SignalForOpen() usa o TF definido nas configurações da instância atual da estratégia virtual, isso eu posso ver. Mas, por exemplo, se eu quiser que o EA trabalhe estritamente nas últimas barras fechadas, então aqui eu deveria especificar unidades em vez de zeros? Eu entendi corretamente?

Se, com as palavras"o EA trabalhou estritamente nas últimas barras fechadas", você quis dizer que, quando o volume do tick exceder o valor limite na barra atual para determinar a direção do sinal de abertura, pegaremos a barra anterior e observaremos sua direção, então você entendeu tudo corretamente.

 

Yuri Olá. Estou tendo um erro ao executar o Expert Advisor SimpleVolumesStage3.mq5 e ao salvar informações no banco de dados:

2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   database error, FOREIGN KEY constraint failed
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   CDatabase::Execute | ERROR: 5619 in query
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   INSERT INTO strategy_groups VALUES(0, 'EA_EG_EU (H1, M30, M15, 9x16 items)')
2024.09.11 21:02:09.909 Core 1  final balance 24603.99 USD

O que isso significa e como corrigi-lo? A tabela foi adicionada ao banco de dados usando sua consulta do artigo.

 

Yuri, examinei seu código e vi que o erro ocorre um pouco antes na função CDatabase::Insert, o registro escreve o seguinte:

2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   CDatabase::Insert | ERROR: Reading row for request 
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   INSERT INTO passes VALUES (NULL, 0, 0, 10000.00,0.00,11096.20,21542.31,-10446.11,92.51,-63.35,630.89,39.00,444.04,53.00,-376.27,52.00,-376.27,52.00,9430.69,569.31,5.69,5.69,569.31,9325.11,683.96,6.83,6.83,683.96,2.15,2.06,16.22,3.44,3736.76,8435.00,5170.00,3042.00,2128.00,2766.00,2404.00,1706.00,1336.00,6.00,4.00,99.11,8122.90,'class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADCHF",16385,220,1.40,1.70,150,2200.00,200.00,46000,24)
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59          ],66.401062),class CVirtualStrategyGroup([

.....

2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),class CVirtualStrategyGroup([
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADJPY",15,132,0.40,1.90,0,7200.00,600.00,45000,27)
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],2.970797),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],1.462074)',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '2024.09.06 23:54:59') RETURNING rowid;
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   failed with code 5039

Cannot execute

      if(DatabaseReadBind(request, row)) {

A que isso pode estar relacionado? O segundo estágio é aprovado e o teste em si é aprovado (as negociações do Expert Advisor e as passagens do banco de dados são carregadas).

 

Olá, Victor.

Voltarei em breve para continuar trabalhando neste projeto e tentarei resolver os erros que encontrei. Obrigado por tê-los encontrado. Consegui reproduzir alguns dos erros sobre os quais você escreveu anteriormente. Eles acabaram sendo relacionados ao fato de que, em partes posteriores, foram feitas edições que visavam a uma coisa, mas que, além disso, tiveram um impacto em outras coisas que não foram consideradas no próximo artigo. Essa influência gerou erros. No próximo artigo, passaremos novamente por todas as etapas da otimização automatizada, eliminando todos os erros que foram detectados.