English Русский 中文 Español Deutsch 日本語 Türkçe
preview
Técnicas úteis e exóticas para a negociação automatizada

Técnicas úteis e exóticas para a negociação automatizada

MetaTrader 5Exemplos | 6 maio 2021, 08:55
1 914 0
Evgeniy Ilin
Evgeniy Ilin

Índice


Introdução

Existem muitas técnicas de negociação que os autores ou o público acham que deveriam ser lucrativas. Eu não considerarei essas técnicas neste artigo, pois há muitas informações sobre elas em uma ampla variedade de recursos. Eu não posso oferecer nada de novo ou interessante sobre esses métodos. Em vez disso, eu decidi criar este artigo como uma coleção de várias técnicas úteis e não padronizadas que seriam úteis na teoria e prática. Algumas dessas técnicas podem ser familiares para você. Eu tentarei cobrir os métodos mais interessantes e explicarei por que vale a pena usá-los. Além disso, eu mostrarei o que essas técnicas podem fazer na prática.


Algoritmo de encerramento parcial de posição, utilizando o último movimento da barra

Teoria:

Essa abordagem pode servir como uma técnica de negociação útil quando nós abrimos uma posição e não temos certeza de qual direção o preço irá se mover. O encerramento parcial da posição de maneira inteligente pode compensar as perdas de spreads e até mesmo gerar lucro após uma boa otimização.

Vamos começar com o seguinte. Suponha que nós não saibamos por onde sair, mas nós já entramos em uma posição. Não importa em que direção nós entramos. De qualquer forma, nós teremos que fechar a posição em algum momento. Claro, alguns "players" podem manter suas posições por anos. No entanto, nós assumimos que o robô deve negociar intensamente e fornecer uma alta frequência de negociações. É possível sair de todo o volume ou em poucos passos, fechando parcialmente a posição. Nós sabemos que o mercado tem uma estrutura lateralizada, o que significa que o preço tende a retornar à posição de início da meia-onda atual. Em outras palavras, um movimento ascendente significa que a probabilidade de continuação é sempre inferior a 50%. Consequentemente, a probabilidade de um movimento oposto é maior que 50%. Se nós fecharmos a posição inteira, nós podemos perder todas as ondas e perder o lucro, porque nós não sabemos a amplitude futura das ondas. O encerramento parcial pode ser útil aqui. Nós seremos capazes de obter o lucro máximo com base no fato de que não conhecemos a natureza das ondas futuras.

Agora que nós sabemos o que são as ondas e que nunca vão desaparecer do mercado, nós podemos começar com o princípio de encerramento de posição, que deve proporcionar a geração de pelo menos algum lucro mesmo que a entrada seja feita de forma incorreta. Esse mecanismo realmente existe.

Pode haver muitos desses algoritmos, mas eu mostrarei apenas um, que acredito ser o mais eficiente. Ele explora a suposição de que quanto maior e mais forte for o movimento na vela anterior fechada, mais provável é que haja um movimento de reversão bastante forte. De modo geral, qual é a finalidade desse mecanismo? Isso é simples. O objetivo é aumentar os lucros e, ao mesmo tempo, reduzir as perdas. Na verdade, os impulsos também são ondas. Mas essas ondas são muito mais úteis do que as ondas clássicas usuais. O fato é que as ondas mais próximas do mercado são mais confiáveis. Quanto mais poderoso o impulso e menor sua duração, maior a probabilidade de uma reversão no futuro próximo e maior a magnitude da reversão esperada. A ideia é arranjar um mecanismo de forma que, quando a força de impulso aumentar, o encerramento parcial da posição seja maior. Eu vou mostrar isso em uma imagem:

Encerramento Parcial

Qualquer função pode ser usada para calcular o volume de parte da posição a ser encerrada. Eu vou mostrar dois deles. Um é linear e o segundo é exponencial:

  • { D } - grau
  • { X } - movimento da barra anterior em pontos
  • { C } - fator de escala
  • { Lc(X) = C * Pow(X , D) } - uma função exponencial que calcula o lote a ser fechado na vela atual
  • { Lc(X) = C * X } - uma função linear que calcula o lote a ser fechado na vela atual

Se você olhar de perto, a função linear é apenas um caso especial de uma função exponencial para D = 1, portanto, nós podemos omiti-lo, pois é apenas um exemplo para a lógica do pensamento inicial. No início do pensamento, tudo é sempre simples, mas depois, após ter pensado bem, nós obtemos ferramentas muito mais versáteis. Você só precisa começar com algo simples.

Para evitar a necessidade de especificar esses coeficientes diretamente e, em seguida, nos preocupar com seu impacto, nós apresentaremos vários parâmetros de controle que determinarão esses coeficientes:

  • { StartLotsToOnePoint } - encerra uma posição por este valor quando X = 1 (parâmetro de entrada)
  • { PointsForEndLots } - movimento da vela anterior para a direção do lucro para a velocidade de encerramento da posição final (parâmetro de entrada)
  • { EndLotsToOnePoint } - encerra a posição por este valor quando X = PointsForEndLots  (parâmetros de entrada)

Agora vamos compor um sistema de equações para calcular os coeficientes e obter a forma final da função, expressa através dos parâmetros de entrada. Para tanto, os pensamentos devem ser convertidos em expressões matemáticas:

  1. { Lc( ) = StartLotsToOnePoint }
  2. { Lc( PointsForEndLots ) = EndLotsToOnePoint }

Então, todas as nossas equações estão prontas. Agora, nós vamos escrevê-los de forma expandida e começar a resolver as equações transformando-as gradualmente:

  1. { C * Pow(1 , D) = StartLotsToOnePoint }
  2. { C * Pow( PointsForEndLots  , D) = EndLotsToOnePoint }

Na primeira equação, nós podemos encontrar imediatamente C, dado que 1 em qualquer grau é igual a si mesmo:

  • { CStartLotsToOnePoint }

Dividindo ambos os lados da segunda equação por "C" e, em seguida, encontrar o logaritmo de ambos os lados da equação para a base "PointsForEndLots", nós obtemos o seguinte:

  • { log( PointsForEndLots ) [ Pow( PointsForEndLots  , D)] = log( PointsForEndLots ) [  EndLotsToOnePoint C ] }

Considerando que o logaritmo, onde sua base é o mesmo logaritmo elevado a qualquer potência, é igual a esta potência, nós podemos resolver a equação em relação à potência desejada:

  • { D =  log( PointsForEndLots ) [  EndLotsToOnePoint C ] }

Nós encontramos o segundo coeficiente desconhecido. Mas isso não é tudo, porque na MQL4 e MQL5 não têm uma função básica que implementa um logaritmo para qualquer base necessária, embora haja apenas um algoritmo natural. Portanto, nós precisamos substituir a base do logaritmo por um logaritmo natural (o algoritmo natural é um logaritmo para uma base expressa pelo número de Euler). A ausência de outros logaritmos na língua não é um problema, pois qualquer logaritmo pode ser expresso em termos do logaritmo natural. Isso será muito fácil para quem entende pelo menos alguma coisa em matemática. Depois de alterar a base, a fórmula para o nosso coeficiente desejado será a seguinte:

  • { D = ln(  EndLotsToOnePoint C ) ln(  PointsForEndLots  ) }

Substituímos o coeficiente C já conhecido e obtemos:

  • { D = ln(  EndLotsToOnePoint StartLotsToOnePoint  )  ln(  PointsForEndLots  ) }

Agora, ambos os coeficientes podem ser substituídos no modelo de função para obter a forma final:

  • { Lc(X) = StartLotsToOnePoint  * Pow( X ,  ln(  EndLotsToOnePoint StartLotsToOnePoint  )  ln(  PointsForEndLots  )  )  }

A vantagem dessa função é que o grau pode ser igual a um, ou pode ser maior que um, bem como menor que um. Assim, ele fornece a máxima flexibilidade para se ajustar a qualquer mercado e instrumento de negociação. Se D = 1, nós obtemos uma função linear. Se D > 1, então a função é sintonizada com a suposição de que todas as ondas são escaláveis e o número de ondas de uma certa amplitude é inversamente proporcional à amplitude (isto é, se contarmos o número de ondas, digamos em M5 e H1, no mesmo período, nós descobriremos que há 12 vezes menos ondas em H1, simplesmente porque há 12 vezes menos velas por hora do que velas de cinco minutos). Se D < 1, nós esperamos ter mais ondas de alta amplitude do que ondas pequenas. Se D > 1, nós assumimos que existem principalmente ondas de baixa amplitude. 

Observe também que você não precisa necessariamente usar uma série de preços discretizados como uma sequência de barras - você pode usar ticks e quaisquer outros segmentos de preços preferenciais. Aqui, nós usamos barras simplesmente porque nós temos barras.

Código:

No código, essa função terá a seguinte aparência:

double CalcCloseLots(double orderlots0,double X)
   {
   double functionvalue;
   double correctedlots;
   if ( X < 0.0 ) return 0.0;
   functionvalue=StartLotsToOnePoint*MathPow(X ,MathLog(EndLotsToOnePoint/StartLotsToOnePoint)/MathLog(PointsForEndLots));
   correctedlots=GetLotAniError(functionvalue);
   if ( correctedlots > orderlots0 ) return orderlots0;
   else return correctedlots;
   }

A função que corrige o lote, para que os lotes tomem apenas o valor correto, é destacada em roxo (não adianta mostrar o seu interior). A função em si é calculada sob o operador destacado em verde, mas é parte de uma função mais geral que é chamada aqui:

void PartialCloseType()// close order partially
   {
   bool ord;
   double ValidLot;
   MqlTick TickS;
   SymbolInfoTick(_Symbol,TickS);
            
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
                            
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == _Symbol )
         {
         if ( OrderType() == OP_BUY )
            {
            ValidLot=CalcCloseLots(OrderLots(),(Open[0]-Open[1])/_Point);
            if ( ValidLot > 0.0 ) ord=OrderClose(OrderTicket(),ValidLot,TickS.bid,MathAbs(SlippageMaxClose),Green);
            }
         if ( OrderType() == OP_SELL )
            {
            ValidLot=CalcCloseLots(OrderLots(),(Open[1]-Open[0])/_Point);
            if ( ValidLot > 0.0 ) ord=OrderClose(OrderTicket(),ValidLot,TickS.ask,MathAbs(SlippageMaxClose),Red);
            }         
         break;
         }
      }

Este código pode ser compilado em MQL5, porque nós usamos a biblioteca MT4Orders. Observe que essas funções são adequadas para o teste. Para usá-los para negociações reais, você precisará estudá-los cuidadosamente e refiná-los, cuidando de erros e casos não contabilizados. De qualquer forma, a versão atual é bem adequada para teste no testador de estratégia.

Testando o Expert Advisor:

Para demonstrar como ele funciona, eu criei uma versão do EA para a MetaTrader 4, porque ao testar na MetaTrader 5, o spread provavelmente esconderá tudo o que queremos ver. Em vez disso, eu defini o spread para 1 e escolhi a abertura da posição em uma direção aleatória:

Backtest USDCHF M5 2000-2021

Isso também funciona da mesma maneira para outros pares de moedas. Também pode funcionar em tempos gráficos maiores, mas isso requer um pouco de paciência para encontrar as configurações adequadas. No entanto, o teste não significa que você pode iniciar imediatamente este EA em uma conta real. Ele só serve como confirmação de que essa técnica pode ser útil quando utilizada de maneira adequada. De qualquer forma, neste ponto, isso é muito, muito insuficiente para o lucro, mesmo para este EA. Mas quando combinado com um bom sinal e uma abordagem adequada, esse método pode ser lucrativo.


Algoritmo de variação de lotes híbrido

Desde o início da pesquisa de mercado, eu queria saber como mudar o fator de lucro de qualquer sistema para valores positivos. Isso significaria que qualquer estratégia que não dependa tanto do spread obterá uma vantagem muito grande em relação a quaisquer outras, que possuem um fator de lucro próximo a um. Por que exatamente o fator de lucro precisa ser melhorado? A resposta é muito simples: porque tanto a redução relativa de todo o sistema quanto a lucratividade do sistema dependem dessa variável. Essa técnica existe e vou mostrá-la a você. Mas, primeiro, vamos examinar rapidamente as técnicas de negociação mais famosas, que podem utilizar a manipulação de lote. Existem as seguintes técnicas alegadas para aumentar o fator de lucro:

  • Martingale
  • Martingale reverso

Na verdade, tudo se resume a dois métodos frequentemente discutidos, mas que dificilmente podem trazer nada além de decepção. Ele é sobre um princípio matemático muito simples, que eu descrevi no artigo Grade e Martingale: o que são e como usá-los? Ele não descreve os princípios em si, mas o que é comum em todos eles. O comum é diminuir ou aumentar muito, dependendo de algumas condições. Se as condições não tem nada a ver com a natureza da formação de preços, tal sistema é deliberadamente não lucrativo.

Qualquer estratégia que utiliza a variação de lote tem um sinal subjacente. Nós podemos obtê-lo fazendo com que os lotes para todas as ordens sejam iguais. Isso nos ajudará a entender se o sinal subjacente está de alguma forma relacionado à natureza da formação do preço. Na maioria dos casos, esse sinal produzirá uma expectativa matemática igual a zero. Mas há um parâmetro neste sinal que pode nos permitir usar ao mesmo tempo tanto o martingale direto quanto o reverso. A condição necessária é a presença de um grande número de ondas de baixa amplitude. Se você usar corretamente a combinação de um martingale e um martingale reverso, poderá transformá-los em um mecanismo híbrido que transformará uma expectativa matemática igual a zero em positiva. A figura abaixo mostra como isso pode ser:

Variação híbrida

Teoria:

Aqui, nós assumimos que temos uma certa linha de saldo inicial, que, sem levar em conta o spread e a comissão, sempre vagará perto do nível inicial de partida, até que um dia você decida parar de negociar com um lucro positivo ou negativo em relação ao nível inicial do saldo, ou até que o sistema perca lentamente o seu depósito, que será desperdiçado por spreads, comissões e swaps. Isso significa que qualquer linha de saldo de uma negociação arbitrária é um processo de onda que flutua em torno do saldo inicial.

Com base nisso, nós podemos dividir toda a linha de saldo em seções ascendentes e descendentes (a figura mostra um quarto de uma onda completa). Se um quarto de onda está crescendo, os lotes devem ser diminuídos (martingale reverso); se a onda está caindo, então os lotes devem ser aumentados (martingale) O único obstáculo para um aumento infinito de lote é o fato de que qualquer conta tem um volume de posição máximo permitido. Então, mesmo que tal situação fosse possível, o depósito não nos permitiria abrir posições extras. Portanto, o lote deve obviamente oscilar em um determinado corredor de valores e não deve ir além dele. Portanto, o importante é que a amplitude das ondas não seja muito grande, de preferência ondas mais pequenas e mais compactas. Se você olhar atentamente para a figura e para a máscara de variação de lote abaixo, você entenderá como, usando a variação híbrida, a linha, em relação à qual as flutuações ocorrem, pode adquirir uma inclinação ascendente, que é equivalente a uma expectativa matemática e fator de lucro positivos.

Como calcular os lotes neste caso? A situação pode parecer pouco clara à primeira vista. Obviamente, muitos podem chegar a um dos limites do nosso canal e nunca mais sair de lá. Para tal, nós devemos fornecer um mecanismo de retorno ao lote inicial, a fim de obter flutuações estáveis em torno do valor médio do lote. A óbvia e única desvantagem de tal sistema é a intolerância a ondas de grande amplitude. Em um movimento de baixa amplitude, o mecanismo funcionará perfeitamente. Este problema é resolvido por uma função que calcula o próximo lote de tal forma que a própria função empurra os lotes para o meio, e quanto mais próximos os lotes da ordem fechada anteriormente estiver de um dos limites, mais forte será o empurrão. Vou demonstrar isso na figura a seguir:

Lotes

Agora eu vou escrever uma visão geral de uma função adequada para essa tarefa, usando a notação da figura. Mas, primeiro, vamos definir os parâmetros de entrada e as variáveis auxiliares:

Variáveis de entrada para controlar a variação do lote híbrido

  • { MaxLot } - lote máximo do corredor (parâmetro de entrada)
  • { MinLot } - lote mínimo do corredor (parâmetro de entrada)
  • { LotForMultiplier } - lote de referência para aumentar ou diminuir o volume
  • { ProfitForMultiplier } - perda e lucro em pontos de referência para o aumento ou diminuição do lote

Variáveis auxiliares

  • MiddleLot = (MaxLot + MinLot)/2 } - o meio entre os lotes máximo e mínimo
  • { h(MaxLot MinLot)/2 } - tamanho do canal intermediário (usado para cálculos)
  • { L } - o lote do último negócio do histórico
  • { X } - variável auxiliar
  • { OrderProfit ,OrderComission ,OrderSwap ,OrderLots } - lucro excluindo a comissão, comissão, ordem de swap calculada e o último volume de encerramento da ordem do histórico (eles são conhecidos)
  • { TickSize } - um aumento no lucro da posição em aberto, desde que seu volume seja igual a 1 lote e o preço tenha se movido 1 ponto na direção desejada
  • { PointsProfit( OrderProfit + OrderComission + OrderSwap ) / OrderLots * TickSize ) } - lucro da última ordem do histórico, convertido em pontos

Função para o caso em que os lotes estão acima ou abaixo da linha central

  • { L  >=  MiddleLot  ?  X = MaxLot - L  } - se os lotes estiverem na parte superior do corredor, o valor "X" é a diferença para a borda superior do canal
  • L  <  MiddleLot  ?  X = L - MinLot } - se os lotes estiverem na parte superior do corredor, então "X" é a distância até a borda inferior do canal
  • { L  >=  MiddleLot & PointsProfit < 0   ?  Lo(X)OrderLots - LotForMultiplier * (  PointsProfit / ProfitForMultiplier ) * X / h )  } - o lote lento aumenta ao se aproximar da borda superior do canal
  • L  <  MiddleLot & PointsProfit >= 0   ?  Lo(X) =  OrderLots - LotForMultiplier * (  PointsProfit / ProfitForMultiplier ) * X / h )  } - o lote lento diminui ao se aproximar da borda inferior do canal
  • L  >=  MiddleLot & PointsProfit >= 0   ?  Lo(X) =  OrderLots - LotForMultiplier * (  PointsProfit / ProfitForMultiplier ) / X / h )  )  } - diminuição acelerada do lote 
  • L  <  MiddleLot & PointsProfit < 0   ?  Lo(X) =  OrderLots - LotForMultiplier * (  PointsProfit / ProfitForMultiplier ) / X / h )  } - aumento acelerado do lote

É muito difícil perceber todas essas relações, pois são difíceis de ler. Se você tentar combinar tudo em uma função contínua, obterá uma estrutura tão complexa que seria impossível trabalhar com ela. Eu vou mostrar mais adiante como fica no código, para que tudo fique mais claro. Aqui, eu mostro a implementação do estilo do código em MQL4. O código pode ser facilmente executado em MQL5 se você usar a conveniente e famosa biblioteca MT4Orders:

Código:

double CalcMultiplierLot()
   {
   bool ord;
   double templot=(MaxLot+MinLot)/2.0;
   for ( int i=OrdersHistoryTotal()-1; i>=0; i-- )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_HISTORY );
      if ( ord && OrderSymbol() == CurrentSymbol &&  OrderMagicNumber() == MagicF )
         {
         double PointsProfit=(OrderProfit()+OrderCommission()+OrderSwap())/(OrderLots()*MarketInfo(CurrentSymbol,MODE_TICKVALUE));
         if ( OrderLots() >= (MaxLot+MinLot)/2.0 )
            {
            if ( PointsProfit < 0.0 ) templot=OrderLots()-(LotForMultiplier*(PointsProfit/ProfitForMultiplier))*((MaxLot-OrderLots())/((MaxLot-MinLot)/2.0));
            if ( PointsProfit > 0.0 ) templot=OrderLots()-(LotForMultiplier*(PointsProfit/ProfitForMultiplier))/((MaxLot-OrderLots())/((MaxLot-MinLot)/2.0)) ;
            if ( PointsProfit == 0.0 ) templot=OrderLots();
            break;
            }
         else
            {
            if ( PointsProfit > 0.0 ) templot=OrderLots()-(LotForMultiplier*(PointsProfit/ProfitForMultiplier))*((OrderLots()-MinLot)/((MaxLot-MinLot)/2.0));
            if ( PointsProfit < 0.0 ) templot=OrderLots()-(LotForMultiplier*(PointsProfit/ProfitForMultiplier))/((Orderlots()-MinLot)/((MaxLot-MinLot)/2.0));
            if ( PointsProfit == 0.0 ) templot=OrderLots();
            break;
            }
         }
      }
   if ( templot <= MinLot ) templot=(MaxLot+MinLot)/2.0;
   if ( templot >= MaxLot ) templot=(MaxLot+MinLot)/2.0;
         
   return templot;
   }

Esta biblioteca será especialmente útil quando você precisar controlar cada ordem em aberto. Então, essa é toda a abordagem. As variáveis de entrada do algoritmo são destacadas em amarelo.

Testando o Expert Advisor:

Este EA também se destina a plataforma MetaTrader 4, pelo mesmo motivo do EA anterior, porque será mais fácil ver uma melhoria no fator de lucro:

Backtest USDCHF M5 2020-2021

Os sinais neste Expert Advisor são gerados sucessivamente. A compra é seguida pela venda e a venda é seguida pela compra. Isso é feito para demonstrar a essência do mecanismo. No segundo teste, nós usamos um lote fixo e a variação do lote híbrido é usada para o primeiro teste. Pode-se ver que o sistema pode fornecer uma melhoria no fator de lucro apenas se houver flutuações mínimas de saldo do sinal original. O sistema não sobreviverá a ondas grandes.


Princípio do preço médio

O princípio do preço médio é um algoritmo bem interessante. Embora ele não seja lucrativo, como a grade de martingale e a pirâmide, ele tem um recurso muito interessante que pode ajudar na negociação de ondas. Se for de nosso conhecimento que o movimento continuará até certo nível e então haverá necessariamente um retrocesso em um certo número de pontos, então o preço médio com martingale pode ser aplicado neste caso. Essa técnica funciona especialmente bem com o martingale, porque o martingale permite reduzir a reversão necessária, enquanto mantém o fator de lucro maior que 1.0. 

Este princípio explora a suposição de que se o preço não se mover na direção de nossa posição em aberto, então, depois de algum tempo, ele sem dúvida irá retroceder em uma parte desse movimento. Mas isso nem sempre acontece na realidade, embora você possa ajustar esse algoritmo para muitos símbolos estudando a natureza de suas ondas. Para gerar lucro com esse retrocesso, nós precisamos prevê-lo ou determiná-lo empiricamente.

Isso também funciona com níveis fortes, porque muitas vezes, quando um nível é rompido, o mercado pode tentar fazer um teste de inversão. Se nós acertamos com a direção do primeiro negócio e o lucro atingiu o valor exigido, encerramos o negócio e abrimos um novo na direção que parece mais atraente. Se o preço estiver na direção errada, então, por meio de certas etapas, nós podemos tentar aumentar o volume de nossa posição. Nós devemos ter muito cuidado ao aumentar a posição - isso deve ser feito com precisão, com base na reversão esperada. Abaixo estão os exemplos de dois possíveis.

Exemplo para uma série de ordens de compra:

Compra

Exemplo para uma série de ordens de venda:

Venda

Agora eu vou mostrar como o lucro ou perda de todas as ordens é calculada e como, com base na situação existente, calcular o lote da próxima ordem, com base na reversão necessária. Para fechar um leque de posições, é necessário saber por que esse leque deve ser construído e em que condição o torna útil. Eu usaria o Fator de Lucro. Se o leque for positivo, seu fator de lucro também será positivo. Seria tolice fechar o leque assim que o lucro total de todos as ordens se tornasse positivo, porque qualquer flutuação de preço no servidor ou uma derrapagem (slippage) pode deslocar o lucro para uma direção negativa - tais leques podem parecer inúteis sob tais condições. Além disso, o fator de lucro do ciclo oferece uma oportunidade para o ajuste adicional da agressividade da média, que pode ser usado na otimização de uma estratégia automatizada ou na busca manual de configurações.

Suponha que haja um limite para o número máximo de ordens em uma série. Então, suponha que estejamos em alguma situação desconhecida, onde nós já abrimos k ordens - seus índices começam em 0, como em qualquer coleção ou arrays. Portanto, o índice da última ordem da série será "k-1". Quando nós abrirmos a próxima ordem, seu índice será k e o número de ordens será "k + 1". Vamos formalizar esses ideais nos dados de entrada do problema:

  • { MaxOrders } - o número máximo permitido de ordens em uma série
  • {  k = 0 ... 1 ... 2 ...  (MaxOrders-1)  } - o índice da próxima ordem na série, que queremos abrir se não gerarmos lucro com a abordagem anterior
  • {  ProfitFactorMax } - fator de lucro permitido para o encerramento
  • {  i = 1 ... 1 ... 2 ... k  } - índices de ordens do leque já existentes e da próxima ordem que nós queremos abrir
  • {  S[i-1]  } - a distância em pontos da ordem anterior até a atual
  • {  X[i-1]  } - a distância em pontos da ordem zero da série até a atual
  • { D[k] } - reversão prevista na direção desejada em relação ao preço de abertura da última ordem da série

Além disso, nós podemos dizer que as linguagens MQL4 e MQL5 fornecem os seguintes dados quando nos referimos a uma ordem específica, que nós precisamos para descrever todas as opções de cálculo:

  • { P[i] } - o lucro de uma ordem específica sem excluir a comissão e swaps
  • { С[i] } - comissão da ordem selecionada
  • { S[i] } - swap das ordens calculadas durante uma rolagem às 0:00
  • L[i] } - volume da ordem
  • { Sp[i] } - spread ao abrir uma posição de Compra / spread atual para posições de Venda
  • { TickSize } - um aumento no lucro da posição em aberto, desde que seu volume seja igual a 1 lote e o preço tenha se movido 1 ponto na direção desejada

Nem todos esses valores serão necessários para o uso prático na negociação automatizada, mas eles permitem destacar todas as opções possíveis para calcular esses valores. Alguns desses valores, que são relevantes e podem ser representados em relação ao preço, são mostrados nas figuras acima. Vamos começar com o método de cálculo mais simples que eu uso em meu código:

Se a primeira ordem fechar com resultado positivo, não fazemos nada. A qualquer momento que nós consideramos adequado, nós abrimos uma nova ordem na direção desejada. Se o preço não atingiu a meta e ele foi na direção oposta, então nós devemos decidir quantos pontos o preço deve se mover na direção da perda, a fim de abrir a próxima ordem (S[k-1] ) Se o preço atingiu esse nível, nós devemos decidir qual reversão é apropriada (D[k]) Depois disso, nós devemos determinar o lote da ordem, que nós abriremos agora para que, com uma reversão planejada, nós obtenhamos o fator de lucro necessário de todos as ordens maiores do que o valor que escolhemos (ProfitFactorMax) Para fazer isso, nós precisamos primeiro calcular qual o lucro que será gerado pelas ordens abertas no momento, bem como qual perda será gerada e seu valor total. Eu explicarei o propósito disso mais tarde, depois de escrever as fórmulas correspondentes:

Primeiro, vamos apresentar o valor do lucro futuro para cada ordem específica. Ela é igual ao lucro atual e o incremento que a ordem irá receber, desde que a reversão necessária aconteça:

  • {  j = 0 ... 1 ... 2 ... k-1 }
  • {  PF[j] = P[j] + С[j] + S[j] + (D[k] * L[j] * TickSize) } - o lucro da ordem específica será igual a este valor quando a reversão acontecer
  • {  PF[k] = { ( D[k] - Spread[k] ) * L[k]TickSize } - este valor não pode ser calculado já que ele contém o lote necessário da posição que nós queremos abir; mas esta expressão será necessária mais tarde

No primeiro caso o valor P[i] é conhecido, e nós podemos obtê-lo usando as funções embutidas da linguagem, bem como podemos calculá-lo nós mesmos. Este método de cálculo será mostrado no final do artigo como um acréscimo, porque tudo pode ser encontrado usando os meios da linguagem padrão. Quanto a última ordem da série que nós vamos abrir, ele também precisa da comissão e swap, mas esses valores só podem ser obtidos para ordens já abertas. Além disso, é impossível determinar o valor do swap, pois nós não sabemos se a posição mudará às 0:00. Sempre haverá valores imprecisos. É possível selecionar apenas os pares de moedas que têm swaps positivos 

Depois disso, nós podemos usar esse lucro previsto para dividir as ordens lucrativas e perdedoras e calcular o fator de lucro resultante:

  • { i = 0 ... 1 ... 2 ... k } - índices de ordens já abertas
  • { Pr[i] >= 0, Ls[i] >= 0} - introduzimos 2 arrays que aceitarão o lucro ou a perda da ordem dependendo do seu sinal ("+" será usado para lucro, que é necessário para calcular o fator de lucro)
  • {  PF [i] < 0  ?  Pr[i] = 0 & Ls[i] = - PF[i]  } - se o lucro da ordem for negativo, escreva seu lucro como "0", enquanto o valor do lucro deve ser escrito com um sinal invertido em uma variável para as perdas
  •  PF [i] > 0 ?  Ls[i] = 0 & Pr[i]PF[i]  } - se o lucro da ordem for positiva, basta escrevê-la no array apropriado e definir um valor igual a zero no array de perda

Depois de preencher esses arrays, nós podemos escrever uma fórmula para calcular o lucro e a perda total, bem como o seu resultado.

  • { SummProfit = Summ[0,k]( PF[i] ) } - módulo de lucro total de todas as ordens lucrativas
  • { SummLoss = Summ[0,k]( Ls [i] ) } - módulo de perda total de todos as ordens com prejuízo

Agora nós precisamos escrever a condição de fechamento do loop:

  • { SummLoss > 0 ?  SummProfit/SummLoss  = ProfitFactorMax }

Para usar mais esta equação, você precisa entender que o lucro da última ordem da série é sempre positivo quando um leque de posições é fechado. Com base nisso, você pode escrever:

  • { SummProfit = Summ[0,k-1]( PF[j] )  +  PF[k] }

Substituímos este valor na equação e obtemos o seguinte:

  • {  ( Summ[0,k-1]( PF[j] )  +  PF[k] ) /  SummLoss  =  ProfitFactorMax }

Agora, resolvendo esta equação para PF[k], nós temos:

  • { PF[k]  =  ProfitFactorMax * SummLoss  -  Summ[0,k-1]( PF[j] ) }

Considerando que nós já temos uma fórmula para o valor PF[k], nós podemos substituir essa expressão aqui e obter:

  • { ( D[k] - Spread[k] ) * L[k] TickSize = ProfitFactorMax * SummLoss  -  Summ[0,k-1]( PF[j] ) }

Agora nós podemos resolver esta equação em relação a L[k]. Assim, nós finalmente obteremos a fórmula para calcular o volume de posição necessário para a sua abertura:

  • { L[k] =  ( ProfitFactorMax * SummLoss  -  Summ[0,k-1]( PF[j] ) )  /  ( ( D[k] - Spread[k] ) *  TickSize ) }

Isso é tudo. Agora vamos considerar como calcular o valor P[i] sem usar funções internas.

  • { P[i] = ( X[i-1] - Spread[i] ) * L[i] * TickSize + С[j] + S[j] }

Calculando o valor da reversão

Agora, vamos examinar os métodos de cálculo de reversão. Eu uso de duas maneiras. Pode haver muitos deles, mas eu irei fornecer apenas dois métodos que eu considero os mais úteis. A reversão é calculada em relação a quanto o preço foi na direção errada. Isso significa que D[i] e X[i] podem ser conectados por qualquer função que seja positiva em todo o eixo X:

  • { D=D(X) }
  • { D[k] = D( X[k-1] ) }

Eu uso duas funções para calcular a reversão. A primeira é linear. A segunda é uma função exponencial. A segunda função é mais difícil, mas mais interessante. Aqui estão as funções:

  • { D = K * X }
  • { D = DMin + C * Pow(S , X) }

Os coeficientes a serem encontrados são destacados. Com base nesses coeficientes, as funções começam a agir de forma diferente e, dessa forma, nós podemos ajustar com flexibilidade nossa estratégia a um par de moedas ou um tempo gráfico específico.

  1. { K } - coeficiente de reversão para uma função linear (também é usado como um parâmetro de entrada para um sistema automatizado) 
  2. { DMin } - a reversão mínima permitida (D>= DMin, no caso de uma função exponencial)
  3. { C } - fator de escala da função exponencial
  4. { S } - a base da exponenciação

Estritamente falando, C pode ser adicionado ao grau, mas eu acho que desta forma a função é mais legível e conveniente de usar. Observe também que os valores K e DMin são parâmetros de entrada, portanto, esses coeficientes já são conhecidos por nós. Não está claro como calcular os dois coeficientes restantes. Vamos fazer isso agora. Para encontrar os 2 valores desconhecidos, nós precisamos de um sistema de pelo menos duas equações. Os coeficientes podem ser encontrados resolvendo o sistema. para escrever tal sistema, primeiro nós precisamos decidir como a forma da função será controlada. Na verdade, eu escolhi a forma atual da função exponencial porque seria mais fácil e mais conveniente fazer uma redução suave na reversão. É por isso que eu escolhi a função exponencial. As considerações foram as seguintes:

  1. { HalfX } - movimento do preço para a metade da reversão adicional (um parâmetro de entrada adicional para controlar a função)
  2. { D(0) = DMinK*DMin }
  3. { D(HalfX) = DMin K*DMin/2 }

Assim, nós obtemos o sistema de equações necessário, que iremos resolver. Em outras palavras, nós definimos o movimento do preço em direção à perda, em relação à primeira ordem em aberto, na qual a adição à reversão é a metade do valor inicial. Esta adição tem um valor máximo no início. Como resultado, nós obtemos uma função que não pode assumir um valor menor que a reversão mínima e, como X tende ao infinito, a função para a reversão mínima. Matematicamente, ela é expressa da seguinte forma:

  • { D >= DMin }
  • { Lim( X -> +infinity ) = DMin }

Agora nós podemos começar a resolver este sistema de equações, mas primeiro vamos reescrever o sistema completo:

  1. DMin + C * Pow(S , 0) = DMin K*DMin
  2. { DMin + C * Pow(S , HalfX) =  DMin K*DMin/2 }

Na primeira equação, nós podemos encontrar imediatamente C, considerando o fato de que qualquer número no número zero se transforma em um. Assim, nós excluímos a variável S. Tudo o que nós precisamos fazer agora é resolver a equação relativa a variável C.

  • { С = K * DMin }

Agora que nós temos C, nós podemos encontrar o restante desconhecido de S simplesmente substituindo a expressão anterior pela variável C:

  • { Pow(S , HalfX) = 0.5 }

A fim de eliminar o grau, nós devemos elevar ambas as partes da equação ao grau recíproco de HalfX. Como resultado, nós obteremos a seguinte expressão simples que será o coeficiente desejado:

  • { S = Pow(0.5  , 1/HalfX) }

Agora nós podemos escrever nossa função de potência substituindo os coeficientes. Isso descreve tudo o que nós precisamos para implementar essa estratégia:

  • { D(X) = DMinK *  DMin * Pow( Pow(0.5  , 1/HalfX)  , X ) }

Esta é a aparência desta função no código:

Código:

double D(double D0,double K0,double H0,double X)
   {
   return D0+(D0*K0)*MathPow(MathPow(0.5,1.0/H0),X);
   }

Aqui estão algumas funções mais importantes que serão usadas no EA para testar a teoria. A primeira é a função que determina a distância em pontos do preço até a ordem em aberto mais próxima da série:

double CalculateTranslation()
   {
   bool ord;
   bool bStartDirection;
   bool bFind;
   double ExtremumPrice=0.0;
   
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         if ( OrderType() == OP_SELL ) bStartDirection=false;
         if ( OrderType() == OP_BUY ) bStartDirection=true;
         ExtremumPrice=OrderOpenPrice();
         bFind=true;
         break;
         }
      }      
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
                        
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         if ( OrderType() == OP_SELL && OrderOpenPrice() > ExtremumPrice ) ExtremumPrice=OrderOpenPrice();
         if ( OrderType() == OP_BUY && OrderOpenPrice() < ExtremumPrice ) ExtremumPrice=OrderOpenPrice();
         }
      }
   if ( bFind )
      {
      if ( bStartDirection ) return (ExtremumPrice-Close[0])/_Point;
      else return (Close[0]-ExtremumPrice)/_Point;      
      }   
   else return -1.0;
   }

Nós precisamos dessa função para cumprir a etapa necessária entre as ordens da série. Esta etapa será corrigida. Não se esqueça de que o array "Close[]" não é implementado em MQL5 e nós precisamos implementá-lo como mostrado em meus artigos anteriores. Acho que essa etapa está bem clara.

A fim de calcular o X eD atuais, nós usaremos a função a seguir, que não tem valores de retorno, como todas as outras funções. Ele gravará o resultado em variáveis globais (é melhor minimizar o acesso as ordens e evitar chamadas desnecessárias das funções que trabalham com o histórico:

double Xx;//shift of X
double Dd;//desired rollback of D
void CalcXD()//calculate current X and D
   {
   bool ord;
   bool bStartDirection=false;
   bool bFind=false;
   double ExtremumPrice=0.0;
   
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         if ( OrderType() == OP_SELL ) bStartDirection=false;
         if ( OrderType() == OP_BUY ) bStartDirection=true;
         ExtremumPrice=OrderOpenPrice();
         bFind=true;
         break;
         }
      }   
   
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
                        
      if ( OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         if ( OrderType() == OP_SELL && OrderOpenPrice() < ExtremumPrice ) ExtremumPrice=OrderOpenPrice();
         if ( OrderType() == OP_BUY && OrderOpenPrice() > ExtremumPrice ) ExtremumPrice=OrderOpenPrice();
         }
      }
   Xx=0.0;
   Dd=0.0;   
   if ( bFind )
      {
      if ( !bStartDirection ) Xx=(Close[0]-ExtremumPrice)/_Point;
      if ( bStartDirection ) Xx=(ExtremumPrice-Close[0])/_Point;
      if ( MODEE==MODE_SINGULARITY ) Dd=D(DE,KE,XE,Xx);
      else Dd=Xx*KE;
      }      
   }

Este código é totalmente compatível com a biblioteca MT4Orders e, portanto, ela pode ser compilada em MQL5. Isso também se refere às funções que serão discutidas posteriormente. As variáveis de entrada do algoritmo são destacadas em amarelo.

Para calcular o lucro atual e previsto, nós usaremos as três variáveis:

double TotalProfitPoints=0.0;   
double TotalProfit=0;
double TotalLoss=0;   

Os valores de retorno serão adicionados a essas variáveis, enquanto as próprias funções não terão valores de retorno - com isso, nós evitamos iterações de ordem todas as vezes, o que torna a operação do código mais lenta.

Uma das próximas duas funções será usada para a condição de fechamento, e a segunda será usada para calcular o lucro previsto das posições atualmente abertas:

void CalcLP()//calculate losses and profits of all open orders
   {
   bool ord;
   double TempProfit=0.0;
   TotalProfit=0.0;   
   TotalLoss=0.0;    
   TotalProfitPoints=0.0;
   
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
                            
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         TempProfit=OrderProfit()+OrderCommission()+OrderSwap();
         TotalProfitPoints+=(OrderProfit()+OrderCommission()+OrderSwap())/(OrderLots()*SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE));
         if ( TempProfit >= 0.0 ) TotalProfit+=TempProfit;
         else TotalLoss-=TempProfit;
         }
      }
   }
   
void CalcLPFuture()//calculate losses and profits of all existing orders in the future
   {
   bool ord;
   double TempProfit=0;
   TotalProfit=0;   
   TotalLoss=0;    
    
   for ( int i=0; i<OrdersTotal(); i++ )
      {
      ord=OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
                            
      if ( ord && OrderMagicNumber() == MagicF && OrderSymbol() == Symbol() )
         {
         TempProfit=OrderProfit()+OrderCommission()+OrderSwap()+(OrderLots()*SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE)*Dd);
         if ( TempProfit >= 0.0 ) TotalProfit+=TempProfit;
         else TotalLoss-=TempProfit;
         }
      }
   }

Além disso, aqui está a função que atribui a condição de fechamento da ordem da série:

bool bClose()
   {
   CalcLP();
   if ( TotalLoss != 0.0 && TotalProfit/TotalLoss >= ProfitFactorMin ) return true;
   if ( TotalLoss == 0.0 && TotalProfitPoints >= DE*KE ) return true;
   return false;
   }

Testando o Expert Advisor:

Eu criei um expert advisor para a MetaTrader 5 usando o princípio descrito, pois este método, quando aplicado corretamente, pode superar quase todos os spreads, comissões e swaps. Aqui está o resultado do teste do EA explorando a média:

USDJPY M1 2019-2020 Backtest

No entanto, observe que é apenas uma técnica de negociação que deve ser usada com muito cuidado. No entanto, ela é muito flexível e pode ser usada em conjunto com uma ampla variedade de estratégias. Mais uma vez, tenha cuidado.


Sinais diretos e indiretos da consistência de uma técnica de negociação

No âmbito deste artigo, seria útil considerar quais variáveis matemáticas de backtest podem provar que a técnica utilizada fortalece nossa estratégia ou mesmo transforma uma estratégia perdedora em lucrativa. A questão é muito importante, porque se nós interpretarmos os resultados do backtest incorretamente, nós podemos excluir uma técnica que realmente funciona ou utilizar uma errada. Ao desenvolver novas técnicas de negociação, eu sempre sigo duas regras, que criam uma condição necessária e suficiente para a detecção mais provável de técnicas de trabalho e a rejeição mais provável de técnicas falsas:

  1. O tamanho da amostra de dados, bem como o número de negociações no backtest, deve ser maximizado para a avaliação estatística
  2. Mesmo uma ligeira mudança nos valores do backtest pode indicar mudanças positivas

Em muitos casos, qualquer mudança positiva pode ser ampliada para torná-la benéfica para a negociação. Existem vantagens inegáveis:

  1. Essas técnicas de negociação podem funcionar em qualquer instrumento de negociação
  2. As técnicas podem ser combinadas e transformadas em técnicas híbridas
  3. Quando usado corretamente, suas chances de gerar lucro são maiores do que de ter prejuízo, mesmo com o spread

Agora eu vou mostrar quais variáveis devem ser analisadas ao tentar usar uma técnica de negociação. Vamos usar o exemplo da última técnica de negociação discutida neste artigo. Vamos começar com as métricas de backtest e ver como usá-las para criar as métricas sintéticas para a detecção de melhorias.

Em primeiro lugar, preste atenção às seguintes variáveis:

  • Lucro final do backtest
  • Rebaixamento máximo do saldo
  • Rebaixamento máximo de capital

Existem algumas variáveis adicionais mais precisas que podem ajudar, mas que não estão disponíveis nos relatórios do testador de estratégia:

  • Rebaixamento médio do saldo
  • Rebaixamento médio do capital

Por que essas métricas mostram com precisão o quão seguro e lucrativo o sistema é? O ponto é que, para qualquer backtest, existem as seguintes identidades matemáticas, como para qualquer sistema de negociação que negocia em uma conta demo ou real:

  • { i = 0 ... 1 ... 2 ... m } - o número de uma meia onda (uma meia onda é um segmento de capital crescente ou de saldo, seguido por um segmento decrescente)
  • { j = 0 ... 1 ... 2 ... k } - segmentos de meia onda negativos (segmentos de saldo começam e terminam no ponto de abertura e fechamento da posição, e segmentos de capital terminam e começam em outros pontos)
  • { OrderProfit[j]-OrderComission[j]-OrderSwap[j] < 0 !  Lim( m --> +infinity ) [ Summ(i) [Summ(j) [ OrderProfit[j]-OrderComission[j]-OrderSwap[j] ]] / m  ] = lucro total excluindo spreads de comissão e swaps   } - rebaixamento médio para o backtest ou saldo do negociação
  • { SegmentEquity[j]-SegmentComission[j]-SegmentSwap[j] < 0 !  Lim( m --> +infinity ) [ Summ(i) [Summ(j) [ SegmentEquity[j]-SegmentComission[j]-SegmentSwap[j] ]] /  ] = lucro total excluindo spreads de comissão e swaps      } - rebaixamento médio para o backtest ou saldo da negociação

Em outras palavras, o rebaixamento médio, tanto em termos de saldo quanto de capital, com um backtest infinito ou uso infinito da estratégia em uma conta demo ou real, tende para o valor do saldo final, se a taxa de transação fosse igual a zero. Claro, isso só é verdade quando a estratégia tem um lucro positivo pronunciado. Se o lucro total tiver um sinal negativo, você pode tentar fórmulas de espelho, nas quais você deve somar não os segmentos negativos, mas sim os positivos. Mas é mais conveniente operar com um backtest positivo já conhecido e aplicar algumas técnicas a ele. Isso, entretanto, não significa que um backtest global mostrará lucro. Você deve encontrar esses intervalos de histórico onde a estratégia mostra o lucro (de preferência, vários desses intervalos). Em seguida, aplicamos uma abordagem. 

Vamos ver agora como, usando um martingale simples, nós podemos fortalecer sua estabilidade e mudar ligeiramente seu desempenho em direção ao lucro. Com base nas fórmulas fornecidas acima, é possível traçar tais métricas sintéticas, segundo as quais é possível avaliar o efeito da técnica de negociação na negociação como um todo, com base em alguns pequenos segmentos:

Dados de entrada para as métricas sintéticas:

  • { Tp } - backtest final ou lucro da negociação
  • { BdM } - rebaixamento médio do saldo
  • { EdM } - rebaixamento médio do capital
  • { BdMax } - rebaixamento máximo do saldo
  • { EdMax } - rebaixamento máximo do capital

A cor destaca os dados não disponíveis no backtest. Mas esses dados podem ser calculados no código e exibidos no final da negociação ou backtest. Mas eu prefiro usar outros dados disponíveis. O ponto é que quanto menor o rebaixamento médio, menor o rebaixamento máximo de ambos os valores na maioria dos casos. Esses valores estão intimamente ligados às probabilidades, e as alterações em uma métrica geralmente implicam em alterações aproximadamente proporcionais em outra métrica. 

Métricas sintéticas:

  • { A = Tp/BdM } - igual a um se a estratégia não prevê o futuro, e mais de um se ela sabe prever e obtém lucro (o que equivale a responder à pergunta sobre sua lucratividade)
  • { B = Tp/EdM } - o mesmo que o valor anterior
  • { C = Tp / BdMax } - se houver um aumento nesta métrica, então nós podemos concluir que a técnica aumenta a eficácia do método (uma diminuição significa um efeito negativo)
  • { D = Tp / EdMax } - o mesmo que o valo anterior

Qualquer um desses 4 critérios pode ser usado. Os dois primeiros são mais precisos, mas o backtest não pode fornecer os dados necessários para calculá-los, então você teria que ler os dados de entrada. Os outros dois podem ser calculados usando os valores do backtest. Então, eu pessoalmente uso as duas últimas métricas, porque elas estão disponíveis e podem ser facilmente encontradas. Agora, vamos ver a aplicação desse método usando um exemplo de um martingale simples que fecha por ordens de stop. Nós tentaremos fortalecer suas variáveis usando a última abordagem exótica.


Usando as ondas de saldo e capital

Teoria:

Na verdade, essa técnica pode ser usada não apenas para o martingale, mas também para qualquer outra estratégia que tenha uma frequência de negociação suficientemente alta. Neste exemplo, eu usarei a métrica com base no rebaixamento do saldo. Porque tudo relacionado ao saldo é considerado mais fácil. Vamos dividir o gráfico de saldo em segmentos crescentes e decrescentes. Dois segmentos adjacentes formam uma meia onda. O número de meias-ondas tende ao infinito, assim como o número de transações tende ao infinito. Uma amostra finita será suficiente para tornarmos o martingale um pouco mais lucrativo. O diagrama a seguir explica a ideia:

Ondas de Saldo

A figura mostra uma meia onda formada e a que acabou de começar. Qualquer gráfico de saldo consiste em tais meias-ondas. O tamanho dessas meias-ondas flutua constantemente, e nós podemos sempre distinguir os grupos dessas meias-ondas no gráfico. O tamanho dessas meias-ondas é menor em uma onda e maior na outra. Assim, baixando gradualmente os lotes, nós podemos esperar até que apareça uma meia onda com um levantamento crítico no grupo atual. Como os lotes desse rebaixamento crítico serão mínimos na série, isso aumentará as métricas médias gerais de todos os grupos de ondas e, como resultado, as mesmas variáveis de desempenho do teste original também devem aumentar.

Para a implementação, nós precisamos de dois parâmetros de entrada adicionais para o martingale:

  • { DealsMinusToBreak } - o número de negociações com prejuízo para o ciclo anterior, que ao atingi-lo, deve-se redefinir o lote do ciclo para seu valor inicial
  • { LotDecrease } - etapa para diminuir o lote inicial do ciclo quando um novo ciclo aparece no histórico de negócios

Esses dois parâmetros nos permitirão fornecer lotes maiores para os grupos de meia onda seguros e lotes reduzidos para os grupos de meia onda perigosos, o que deveria, em teoria, aumentar as métricas de desempenho mencionadas acima.

O código a seguir será adicionado ao EA martingale. Ele calcula o lote inicial do próximo ciclo e o zera, se necessário:

Código:

double DecreasedLot=Lot;//lot to decrease
double CalcSmartLot()//calculate previous cycle
   {
   bool ord;
   int PrevCycleDeals=0;
   HistorySelect(TimeCurrent()-HistoryDaysLoadI*86400,TimeCurrent());
   for ( int i=HistoryDealsTotal()-1; i>=0; i-- )
      {
      ulong ticket=HistoryDealGetTicket(i);
      ord=HistoryDealSelect(ticket);
      if ( ord && HistoryDealGetString(ticket,DEAL_SYMBOL) == _Symbol 
      && HistoryDealGetInteger(ticket,DEAL_MAGIC) == MagicC 
      && HistoryDealGetInteger(ticket,DEAL_ENTRY) == DEAL_ENTRY_OUT )
         {
         if ( HistoryDealGetDouble(ticket,DEAL_PROFIT) > 0 )
            {
            for ( int j=i+1; j>=0; j-- )//found a profitable deal followed by losing (count them)
                {
                ticket=HistoryDealGetTicket(j);
                ord=HistoryDealSelect(ticket);
                if ( ord && HistoryDealGetString(ticket,DEAL_SYMBOL) == _Symbol 
                && HistoryDealGetInteger(ticket,DEAL_MAGIC) == MagicC 
                && HistoryDealGetInteger(ticket,DEAL_ENTRY) == DEAL_ENTRY_OUT )
                   {
                   if ( HistoryDealGetDouble(ticket,DEAL_PROFIT) < 0 )
                      {
                      PrevCycleDeals++;
                      }
                   else
                      {
                      break;
                      }
                   }                
                }
            break;    
            }
         else
            {
            break;
            }
         }
      }
      
   if ( PrevCycleDeals < DealsMinusToBreak ) DecreasedLot-=LotDecrease;
   else DecreasedLot=Lot;
   if ( DecreasedLot <= 0.0 ) DecreasedLot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);

   return DecreasedLot;
   }

Os parâmetros de entrada são destacados em amarelo. Observe que esta é uma função de teste, que só é adequada neste formato para o teste no Testador de Estratégia. No entanto, é suficiente que façamos o primeiro teste grosseiro e simples dessa suposição. O artigo fornece apenas o código mínimo necessário para a compreensão da ideia. Eu não irei fornecer o resto do código do EA para não distrair o leitor com reflexões desnecessárias. O mesmo se aplica aos outros EAs que foram criados durante a escrita do artigo. Agora vamos testar o martingale usual e, em seguida, ativar o novo modo e ver como ele afeta as variáveis de desempenho. Este Expert Advisor também é projetado para a MetaTrader 5, uma vez que o sinal inicial é um martingale regular, que tem o mesmo desempenho com spreads diferentes.

Testando o Expert Advisor:

Backtest EURUSD M1 2017-2021

Se você calcular D para o teste original, ele levará o valor de 1.744. Com o novo modo habilitado, este valor é 1.758. A lucratividade mudou ligeiramente na direção certa. Claro, se nós fizermos mais alguns testes, esse valor pode cair, mas na média deve haver um aumento na variável. A rigor, a lógica é suficiente para demonstração.


Conclusão

Neste artigo, eu tentei coletar as técnicas mais interessantes e proveitosas que podem ser úteis para os desenvolvedores de sistemas de negociação automatizados. Algumas dessas técnicas podem auxiliar na melhoria dos lucros, após estudo e pesquisa adequados. Espero que este material seja interessante e útil. Essas técnicas podem ser consideradas uma caixa de ferramentas, mas não um guia sobre como construir um Graal. Até mesmo um simples conhecimento de tais técnicas pode salvá-lo de investimentos precipitados ou perdas críticas. Ao investir mais tempo e esforço, você pode tentar criar algo mais interessante e estável do que um sistema de negociação convencional baseado na interseção de dois indicadores.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/8793

Arquivos anexados |
Test_Bots.zip (380.34 KB)
Trabalhando com preços e sinais na biblioteca DoEasy (Parte 65): coleção de livros de ofertas e classe para trabalhar com sinais MQL5.com Trabalhando com preços e sinais na biblioteca DoEasy (Parte 65): coleção de livros de ofertas e classe para trabalhar com sinais MQL5.com
Neste artigo, criaremos uma classe-coleção de livros de ofertas para todos os símbolos e começaremos a desenvolver a funcionalidade para trabalhar com o serviço de sinais MQL5.com - criaremos uma classe objeto-sinal.
Redes Neurais de Maneira Fácil (Parte 11): Uma visão sobre a GPT Redes Neurais de Maneira Fácil (Parte 11): Uma visão sobre a GPT
Talvez um dos modelos mais avançados entre as redes neurais de linguagem atualmente existentes seja a GPT-3, cuja variante máxima contém 175 bilhões de parâmetros. Claro, nós não vamos criar tal monstro em nossos PCs domésticos. No entanto, nós podemos ver quais soluções arquitetônicas podem ser usadas em nosso trabalho e como nós podemos nos beneficiar delas.
Outras classes na biblioteca DoEasy (Parte 66): classe-coleção de Sinais MQL5.com Outras classes na biblioteca DoEasy (Parte 66): classe-coleção de Sinais MQL5.com
Neste artigo, criaremos uma classe-coleção de sinais - do serviço Sinais MQL5.com - com funções para gerenciar sinais assinados e também modificaremos a classe do objeto-instantâneo do livro de ofertas para exibir o volume total de ordens sell e buy.
Trabalhando com preços na biblioteca DoEasy (Parte 64): livro de ofertas, classes do objeto-instantâneo e objeto-série de instantâneos do livro de ofertas Trabalhando com preços na biblioteca DoEasy (Parte 64): livro de ofertas, classes do objeto-instantâneo e objeto-série de instantâneos do livro de ofertas
Neste artigo, criaremos duas classes (a do objeto-instantânea do livro de ofertas e a do objeto-série dos instantâneos do livro de ofertas) e testaremos a criação de uma série de dados do livro de ofertas.