preview
Desenvolvendo uma Estratégia de Pullback: Validação

Desenvolvendo uma Estratégia de Pullback: Validação

MetaTrader 5 — Negociação |
156 0
Samuel De Souza Ferreira
Samuel De Souza Ferreira

“Robustez não é encontrar o melhor passe. É descobrir o que continua funcionando quando a amostra termina.”

Introdução

Uma estratégia pode apresentar ótimos resultados durante a otimização e, ainda assim, desaparecer assim que encontra dados que não participaram da escolha dos parâmetros. Portanto, a pergunta decisiva não é quanto o EA ganhou no melhor teste, mas sim: quanto da lógica permaneceu de pé quando o mercado mudou?

Este é o terceiro artigo da série sobre o desenvolvimento de uma estratégia de pullback. Após apresentar os fundamentos da ideia e transformar a lógica em um Expert Advisor no MetaTrader 5, chegamos à etapa mais exigente: investigar fragilidades, adicionar contexto somente quando necessário e medir a continuidade fora da amostra.

O objetivo não é encontrar uma combinação “perfeita” de médias, nem apresentar um conjunto pronto para operação real. A proposta é mostrar um processo de pesquisa: partir de um pullback simples, identificar onde ele falha, criar hipóteses com significado de mercado e exigir que cada nova camada prove sua utilidade por meio Walk-Forward Efficiency.


O caminho da investigação

Encontrar robustez não significa procurar a combinação mais lucrativa, mas submeter cada hipótese a um ciclo contínuo de medição, comparação e exclusão. Neste artigo, chamamos de bateria cada bloco controlado de testes que mantém a estrutura já validada e libera apenas uma família de variáveis por vez — como EMAs, slopes, limites mínimo e máximo de ATR, gatilho ou gestão. Para organizar essas baterias, utilizaremos o mt5_global_optimizer, apresentado no artigo MetaTrader 5 Global Optimizer: Uma Estrutura Profissional para Otimizar EAs por Grupos, Subgrupos e Critérios de Robustez, no qual são explicadas sua configuração, estrutura e utilização. A ferramenta permite separar os componentes, aplicar critérios de robustez e comparar os resultados antes de decidir se uma nova lógica deve ser mantida, retestada ou excluída. Um anexo também disponibilizará a estrutura adequada do EA em MQL5 para acompanhar esse processo.

Robustness Cycle

Figure 1 — The robustness cycle used to add, measure, and remove degrees of freedom.


1. Onde começa a busca pela robustez

A investigação começou exclusivamente no WIN$N. O objetivo inicial era avaliar uma ideia simples e conhecida: definir o regime em um timeframe maior, esperar uma retração em um timeframe menor e entrar quando o preço retomasse o movimento na direção do regime.

A configuração manual utilizada como ponto de partida possuía a seguinte estrutura:

Camada Papel no Experimento
Regime Timeframe superior e média de referência para limitar a direção.
Retração Timeframe inferior e média curta para identificar o retorno do preço.
Gatilho Retomada confirmada por distância normalizada pelo ATR.

Table 1 — Baseline pullback layers and their role in the experiment.

Em termos conceituais, o EA possuía três blocos:

  • Regime: Preço e EMA no M15 definiam a direção permitida.
  • Retração: O M1 indicava o retorno do preço em direção à EMA curta.
  • Retomada: Um candle fechado cruzava novamente a EMA e precisava terminar suficientemente afastado dela.

Essa estrutura era simples, compreensível e adequada como hipótese inicial. O problema é que simplicidade lógica não significa robustez estatística.


2. O primeiro WFE: quando a gestão sobrevive, mas o núcleo falha

O primeiro Walk-Forward Efficiency do WIN abrangeu o período de 1º de janeiro de 2021 até 31 de dezembro de 2024, utilizando janelas móveis com seis meses de ISS, três meses de OOS e avanço trimestral. Foram obtidas 13 janelas válidas com saldo inicial de R$ 10.000. Em cada uma delas, o melhor resultado do trecho ISS era selecionado e seus parâmetros eram aplicados, sem nova escolha, ao OOS seguinte.

Essa abordagem é diferente de otimizar todo o histórico e observar apenas a curva final. Cada janela obriga o modelo a tomar uma decisão usando somente o passado local e, depois, verifica quanto dessa decisão sobrevive no trecho seguinte.

Para facilitar esse processo, foi utilizada a estrutura apresentada no artigo MetaTrader 5 Global Optimizer II — Validação por Walk-Forward Efficiency, que integra a montagem das janelas, a seleção dos candidatos e a consolidação dos resultados ao fluxo de otimização do MetaTrader 5.

Os números iniciais foram reveladores:

Grupo Janelas Positivas Lucro OOS (R$) PF OOS Mediano WFE Consolidado (%)
Breakeven 7/13  6603 1,134 60,87
Trailing 10/13  7860 1,184 63,93
Stop inicial 9/13 7508 1,193 64,93
Gatilho ATR 7/13  5699 1,126 40,90
Par de EMAs 8/13  2737 1,026 18,81

Table 2 — Initial WFE diagnosis by strategy component.

O resultado mudou o rumo da investigação. Stop, trailing e breakeven preservavam alguma continuidade, mas o núcleo formado apenas pelos períodos das EMAs e o  gatilho ATR eram fracos, porém ainda positivos; por isso não deveriam ser descartados sem uma investigação adicional.

Essa diferença também revelou um risco metodológico importante: uma gestão eficiente pode esconder uma entrada frágil. Se avaliássemos apenas o resultado completo do EA, poderíamos concluir que a estratégia estava saudável. Ao separar os componentes, tornou-se evidente que parte importante da robustez vinha da forma de saída da posição, e não da qualidade estrutural da entrada. Após o primeiro WFE, a decisão foi: manter as hipóteses de pullback, rejeitar EMAs e os gatilhos isolados como descrição suficiente do regime e investigar o contexto antes de ampliar a gestão.

First Diagnosis

Figure 2 — In the first WFE, management components preserved efficiency while the EMA and ATR Trigger pair remained weak.


3. A EMA não estava errada — estava sem contexto

Situações visualmente muito diferentes podem produzir a mesma regra binária de preço acima ou abaixo da EMA:

  1. O preço está acima da média, mas a EMA permanece praticamente horizontal.
  2. O preço está acima da média após um movimento já excessivamente estendido.
  3. A EMA está inclinada e o preço mantém um afastamento moderado, caracterizando um regime mais organizado.
  4. A retração acontece alinhada ou contrária à inclinação da média curta.

Se todas essas situações recebem a mesma classificação, a EMA deixa de descrever o regime e passa a funcionar apenas como uma fronteira geométrica. A hipótese de desenvolvimento, portanto, não era procurar uma “EMA mágica”, mas fornecer contexto para que a média pudesse distinguir cenários de mercado diferentes.

Com base nesse diagnóstico, foram adicionados graus de liberdade com significado de mercado. O slope passou a medir a direção e a inclinação das EMAs, enquanto a distância do preço em relação à EMA de regime foi normalizada pelo ATR e delimitada por valores mínimo e máximo. O limite mínimo ajuda a evitar regiões indefinidas, nas quais o preço permanece excessivamente próximo da média, e o limite máximo procura impedir sinais após movimentos já muito estendidos.

Essas novas lógicas foram implementadas como filtros opcionais, permitindo que o processo de validação decidisse entre mantê-las ligadas, desligadas ou excluí-las. O objetivo passou a ser verificar se uma EMA contextualizada por inclinação e distância apresentaria maior continuidade fora da amostra do que o par de médias utilizado isoladamente.

3.1 Slope da EMA do regime

O slope mede o deslocamento da EMA do regime ao longo de determinado número de candles. Seu objetivo é verificar se a média apresenta inclinação coerente com a direção esperada. Dessa forma, a simples posição do preço acima ou abaixo de uma EMA praticamente horizontal deixa de ser suficiente para caracterizar um regime direcional.

No código, o cálculo utiliza somente candles fechados. O índice 1 representa o último candle concluído, enquanto 1 + N indica o valor da EMA observado N candles antes:

ΔEMA = EMA[1] − EMA[1 + N]

Legenda:

  • ΔEMA: Deslocamento da EMA durante o intervalo analisado.
  • EMA[1]: Valor da EMA no último candle fechado.
  • EMA[1 + N]: Valor da EMA observado N candles antes.
  • N: Quantidade de candles definida em regimeSlopeBars.

O deslocamento da EMA ainda está expresso na escala nominal do preço. Para relacioná-lo à volatilidade recente, o EA utiliza o ATR calculado no mesmo timeframe da EMA de regime. O parâmetro regimeSlopeMinAtr é multiplicado pelo ATR do último candle fechado:

SlopeRequerido = regimeSlopeMinAtr x ATR[1]

Legenda:

  • SlopeRequerido: Deslocamento mínimo exigido da EMA.
  • RegimeSlopeMinAtr: Fração mínima do ATR definida para o filtro.
  • ATR[1]: Valor do ATR no último candle fechado do timeframe de regime.

A seguir, é apresentado o trecho do EA responsável por calcular o deslocamento da EMA, transformar o limite em ATR para a escala de preço e validar o slope conforme a direção do regime:

//--- Validates the regime EMA slope using the regime ATR.
bool RegimeSlopeFilterIsValid(const bool isBuy)
  {
//--- Ignore the filter when it is disabled.
   if(!useRegimeSlopeFilter)
      return true;

//--- Compare the last closed EMA value with N candles before.
   int slopeShift = 1 + regimeSlopeBars;

   if(ArraySize(g_regimeEMA) <= slopeShift ||
      ArraySize(g_regimeATR) <= 1)
      return false;

//--- Use the ATR from the last closed regime candle.
   double atr = g_regimeATR[1];

   if(atr <= 0.0)
      return false;

//--- Calculate the EMA displacement.
   double slope =
      g_regimeEMA[1] - g_regimeEMA[slopeShift];

//--- Convert the ATR threshold into a price displacement.
   double requiredSlope =
      regimeSlopeMinAtr * atr;

//--- Validate the slope according to the regime direction.
   if(isBuy)
      return slope >= requiredSlope;

   return slope <= -requiredSlope;
  }

Em um regime comprador, a EMA precisa apresentar deslocamento positivo igual ou superior ao valor requerido:

ΔEMA >= SlopeRequerido

Em um regime vendedor, o deslocamento precisa ser negativo e alcançar a mesma magnitude no sentido oposto:

ΔEMA <= -SlopeRequerido

Legenda das condições:

  • ΔEMA: Deslocamento calculado da EMA.
  • SlopeRequerido: Deslocamento mínimo determinado pelo ATR.

Quando useRegimeSlopeFilter está desligado, a função retorna true e não acrescenta essa condição ao regime. Quando está ligado, a posição do preço em relação à EMA continua sendo necessária, mas a média também precisa demonstrar uma inclinação proporcional à volatilidade recente. Assim, o regime passa a considerar tanto a localização do preço quanto a direção apresentada pela EMA.

3.2 Slope da EMA de retração

A EMA de retração descreve o comportamento local do pullback no timeframe mais curto. Enquanto a EMA de regime identifica a direção predominante, a média curta ajuda a observar como o preço se movimenta durante a correção. Uma inclinação moderadamente contrária ao regime pode representar apenas uma retração normal, porém, quando esse deslocamento se torna excessivo, o movimento local pode estar perdendo sua característica de pullback e se aproximando de uma possível reversão.

No EA, o slope da retração é calculado com candles fechados e relacionado ao ATR do próprio timeframe de retração. O parâmetro retracementSlopeMinAtr define a inclinação mínima aceita e pode assumir valores negativos, permitindo certa tolerância ao movimento contrário. Para compras, o slope da EMA curta precisa permanecer acima do limite configurado; para vendas, abaixo do limite simétrico. Dessa forma, o filtro não obriga as duas EMAs a apontarem sempre na mesma direção, mas controlar quanto a média curta pode se inclinar contra o regime antes de invalidar o gatilho. O código no EA e a fórmula seguem o mesmo padrão do slope de regime; por isso, não será apresentado novamente.

3.3 Canal ATR de distância do preço à EMA

O slope informa se a EMA apresenta direção, mas não identifica se o preço está excessivamente próximo ou distante da média. Para acrescentar esse contexto, o EA calcula a distância entre o fechamento do último candle e a EMA de regime, utilizando o ATR do mesmo timeframe para estabelecer os limites mínimo e máximo.

A distância é calculada de acordo com a direção do regime:

Distância = Close[1] - EMA[1], Regime comprador

Distância = EMA[1] - Close[1], Regime vendedor

Legenda:

  • Distância: Afastamento do fechamento em relação à EMA.
  • Close[1]: Fechamento do último candle concluído.
  • EMA[1]: Valor da EMA de regime no mesmo candle.
  • Regime comprador: Calcula a distância do preço acima da EMA.
  • Regime vendedor: Calcula a distância do preço abaixo da EMA.

Os limites do canal são convertidos para a escala de preço por meio do ATR:

DistânciaMínima = regimePriceDistanceMinAtr x ATR[1]

DistânciaMáxima = regimePriceDistanceMaxAtr x ATR[1]

Legenda:

  • DistânciaMínima: Menor afastamento aceito.
  • DistânciaMáxima: Maior afastamento permitido.
  • RegimePriceDistanceMinAtr: Limite mínimo em unidades de ATR.
  • RegimePriceDistanceMaxAtr: Limite máximo em unidades de ATR.
  • ATR[1]: ATR do último candle fechado no timeframe de regime.

A seguir, é apresentada a função original do código responsável pela validação desse canal:

//+------------------------------------------------------------------+
//| Optional regime price distance filter normalized by regime ATR.  |
//+------------------------------------------------------------------+
bool RegimePriceDistanceFromEMAByATRIsValid(const bool isBuy)
  {
   if(!useRegimePriceDistanceFromEMAByATR)
      return true;

   if(ArraySize(g_regimeRates) <= 1 ||
      ArraySize(g_regimeEMA) <= 1 ||
      ArraySize(g_regimeATR) <= 1)
      return false;

   double atr = g_regimeATR[1];

   if(atr <= 0.0)
      return false;

   double close = g_regimeRates[1].close;
   double ema = g_regimeEMA[1];

   double distance =
      (isBuy ? close - ema : ema - close);

   double minDistance =
      regimePriceDistanceMinAtr * atr;

   double maxDistance =
      regimePriceDistanceMaxAtr * atr;

   bool valid = (distance >= minDistance);

   if(valid && regimePriceDistanceMaxAtr > 0.0)
      valid = (distance <= maxDistance);

   if(!valid)
      LogBlockedEventOncePerCandle(
         (isBuy
          ? "BUY_REGIME_PRICE_ATR_BLOCKED"
          : "SELL_REGIME_PRICE_ATR_BLOCKED"),
         StringFormat(
            "close=%.2f ema=%.2f atr=%.2f "
            "distance=%.2f min_atr=%.2f max_atr=%.2f",
            close,
            ema,
            atr,
            distance,
            regimePriceDistanceMinAtr,
            regimePriceDistanceMaxAtr
         )
      );

   return valid;

A função primeiro verifica se o filtro está habilitado e se os buffers possuem os dados necessários. Em seguida, recupera o fechamento, a EMA e o ATR do último candle concluído. A distância é calculada de forma simétrica para regimes compradores e vendedores.

A distância mínima é sempre aplicada quando o filtro está ativo:

Distância >= DistânciaMínima

O limite máximo somente é verificado quando regimePriceDistanceMaxAtr possui valor superior a zero:

Distância <= DistânciaMáxima

O limite mínimo evita que o regime seja validado quando o preço permanece praticamente encostado na EMA. O limite máximo impede a validação após um movimento excessivamente estendido. Quando regimePriceDistanceMaxAtr é igual a zero, apenas o teto do canal é desativado. A exigência de distância mínima continua ativa.

Se alguma condição não for atendida, o EA registra o bloqueio por meio de LogBlockedEventOncePerCandle. A função apenas valida o estado do filtro e não envia ordens.


4. Afrouxando o gatilho ATR: uma nova hipótese para validação

O gatilho original exigia que o candle de retomada cruzasse a EMA curta e terminasse, nesse mesmo fechamento, a uma distância mínima definida pelo ATR. A condição era objetiva, mas criava uma dependência temporal rígida: o cruzamento e o afastamento precisavam ocorrer exatamente no mesmo candle.

Em alguns movimentos, o preço cruzava a EMA e confirmava a retomada, mas somente alcançava a distância ATR necessária nos candles seguintes. Mesmo preservando a direção do regime e a estrutura do pullback, esses casos eram descartados porque as duas condições não aconteciam simultaneamente.

Para investigar essa possibilidade, o EA recebeu uma lógica opcional de afrouxamento por meio de uma janela ATR. Quando a retomada da EMA era identificada sem o afastamento mínimo, o estado podia permanecer armado durante uma quantidade configurável de candles do timeframe de retração.

O fluxo implementado no código pode ser representado da seguinte forma:

//+------------------------------------------------------------------+
//| Starts the relaxed ATR trigger window on the retracement TF.     |
//+------------------------------------------------------------------+
void ArmLooseATRTriggerWindow(const bool isBuy)
  {
//--- Store the opening time of the current retracement candle.
   datetime currentRetracementBar =
      iTime(_Symbol, g_retracementTimeframe, 0);

//--- Use the current server time if the candle time is unavailable.
   if(currentRetracementBar <= 0)
      currentRetracementBar = TimeCurrent();

//--- Store an independent window start for each direction.
   if(isBuy)
      g_buyLooseATRTriggerStartRetracementBar =
         currentRetracementBar;
   else
      g_sellLooseATRTriggerStartRetracementBar =
         currentRetracementBar;
  }

//+------------------------------------------------------------------+
//| Checks whether the relaxed ATR trigger window is active.         |
//+------------------------------------------------------------------+
bool LooseATRTriggerWindowActive(const bool isBuy)
  {
//--- Select the window start according to the setup direction.
   datetime start =
      (isBuy
       ? g_buyLooseATRTriggerStartRetracementBar
       : g_sellLooseATRTriggerStartRetracementBar);

//--- A disabled or unarmed window cannot be active.
   if(!useLooseATRTriggerWindow || start <= 0)
      return false;

//--- Count elapsed candles on the retracement timeframe.
   int shift =
      iBarShift(
         _Symbol,
         g_retracementTimeframe,
         start,
         false
      );

//--- Reject the state when the reference candle is unavailable.
   if(shift < 0)
      return false;

//--- Keep the window active while it remains inside the limit.
   return (
             shift <= looseATRTriggerWindowRetracementCandles
          );
  }

//+------------------------------------------------------------------+
//| Checks whether the relaxed ATR trigger window has expired.       |
//+------------------------------------------------------------------+
bool LooseATRTriggerWindowExpired(const bool isBuy)
  {
//--- Select the stored window start for the current direction.
   datetime start =
      (isBuy
       ? g_buyLooseATRTriggerStartRetracementBar
       : g_sellLooseATRTriggerStartRetracementBar);

//--- A disabled or unarmed window cannot expire.
   if(!useLooseATRTriggerWindow || start <= 0)
      return false;

//--- Locate the starting candle on the retracement timeframe.
   int shift =
      iBarShift(
         _Symbol,
         g_retracementTimeframe,
         start,
         false
      );

//--- Expire when the candle is unavailable or the limit is exceeded.
   return (
             shift < 0 ||
             shift > looseATRTriggerWindowRetracementCandles
          );
  }

//+------------------------------------------------------------------+
//| Expires the relaxed ATR trigger and waits for a fresh pullback.  |
//+------------------------------------------------------------------+
void ExpireLooseATRTriggerWindow(const bool isBuy)
  {
   if(isBuy)
     {
      //--- Clear the buy setup and require a new retracement cycle.
      ClearBuyRetracement();
      g_buyLooseATRExpiredWaitRetracementReset = true;
      return;
     }

//--- Clear the sell setup and require a new retracement cycle.
   ClearSellRetracement();
   g_sellLooseATRExpiredWaitRetracementReset = true;
  }

//+------------------------------------------------------------------+
//| Prevents immediate rearming after a relaxed ATR window expires.  |
//+------------------------------------------------------------------+
bool LooseATRExpiredWaitResetIsActive(const bool isBuy)
  {
   if(isBuy)
     {
      //--- No reset restriction is active for the buy setup.
      if(!g_buyLooseATRExpiredWaitRetracementReset)
         return false;

      //--- Keep waiting while the previous retracement still exists.
      if(BuyRetracementCandle())
         return true;

      //--- Allow a new window after the retracement condition resets.
      g_buyLooseATRExpiredWaitRetracementReset = false;
      return false;
     }

//--- No reset restriction is active for the sell setup.
   if(!g_sellLooseATRExpiredWaitRetracementReset)
      return false;

//--- Keep waiting while the previous retracement still exists.
   if(SellRetracementCandle())
      return true;

//--- Allow a new window after the retracement condition resets.
   g_sellLooseATRExpiredWaitRetracementReset = false;
   return false;
  }
  }

A janela utiliza candles do timeframe de retração. Seu início é associado ao candle em que a retomada ocorreu sem a distância necessária, enquanto o número de candles transcorridos determina se o estado permanece ativo ou deve expirar.

A estrutura também impede o rearme contínuo. Quando a janela expira, o estado da retração é limpo e o EA espera que a condição anterior deixe de existir. Somente após uma nova retração válida, o processo pode ser iniciado novamente.

A inclusão dessa lógica não representa sua aprovação antecipada. Ela transforma a rigidez temporal do gatilho em uma hipótese mensurável, que será avaliada nas baterias posteriores para verificar se o tempo adicional preserva confirmações válidas ou apenas amplia a quantidade de sinais.


5. Duas etapas da validação do WIN: exploração e consolidação

As duas baterias cumpriram funções complementares. A primeira foi exploratória: manteve janelas de seis meses de ISS para medir o efeito dos novos graus de liberdade. A segunda foi confirmatória: ampliou o ISS para 12 meses, devolveu os timeframes ao espaço de teste e procurou regiões paramétricas estáveis. Por fazerem parte do mesmo caminho de validação, elas são apresentadas juntas neste capítulo.

5.1 Bateria exploratória: adicionar contexto às EMAs

Com os novos graus de liberdade, o WIN foi novamente submetido a 13 janelas de seis meses de ISS e três meses de OOS. A seleção foi refeita com critério de saldo máximo.

Grupo Janelas Positivas PF OOS Mediano DD Máximo (%) WFE Consolidado (%) Lucro OOS (R$)
Breakeven 7/13 1,066 11,35 53,08 4805 
Canal/ Distância ATR do Regime 10/13 1,372 14,55 46,70 5342 
Trailing 9/13 1,173 9,58 60,15 6024 
Stop 9/13 1,271 8,70 66,50
6378 
Slope da Retração 7/13 1,002 10,55 41,95 4172 
Slope do Regime 10/13 1,213 10,46 67,20 7036 
Par de EMAs 8/13 1,073 12,32 42,86 5483
Gatilho ATR 7/13 1,126 13,01 40,90 5699 
Janela ATR Flexível 10/13 1,070 15,18 69,50 8380

Table 3 — Exploratory WIN battery after adding contextual degrees of freedom.

A segunda bateria mostra que os novos graus de liberdade acrescentaram contexto ao núcleo da estratégia. O avanço mais importante ocorreu no par de EMAs: o WFE passou de 18,81% para 42,86%, aumento de 24,05 pontos percentuais. O lucro OOS praticamente dobrou, de R$ 2.737 para R$ 5.483, enquanto o PF mediano subiu de 1,026 para 1,073. As janelas positivas permaneceram em 8/13, indicando melhora na qualidade e eficiência, mas não na distribuição temporal dos resultados.

Entre os novos filtros, o slope do regime apresentou a evidência mais equilibrada: WFE de 67,20%, 10/13 janelas positivas, PF de 1,213 e lucro OOS de R$ 7.036. O canal de distância ATR alcançou o maior PF mediano, 1,372, embora com WFE mais moderado e drawdown de 14,55%. Já o slope da retração apresentou benefício isolado limitado, com PF próximo da neutralidade.

EMA Context WFE

Figure 3 — WFE improved as contextual filters were added to the EMA structure.

A janela ATR flexível foi promissora em lucro e eficiência, alcançando WFE de 69,50% e R$ 8.380 no OOS. Entretanto, também apresentou o maior drawdown, 15,18%, e PF de apenas 1,070. Portanto, não deve ser escolhida somente pelo lucro ou WFE: sua permanência depende da estabilidade paramétrica e da validação nos períodos externos.

A gestão continuou relevante, mas não melhorou de maneira uniforme. O stop elevou seu WFE de 64,93% para 66,50% e o PF de 1,193 para 1,271. Breakeven e trailing perderam eficiência. O resultado central é que a segunda bateria reduziu a dependência exclusiva da gestão: slopes e limites ATR deram mais significado ao regime e fortaleceram o próprio núcleo das EMAs.

5.2 Bateria de consolidação: ampliar o ISS e procurar regiões

Na etapa final, cada janela passou a utilizar 12 meses de ISS, mantendo três meses de OOS e avanço trimestral. Foram analisadas 12 janelas. Os timeframes também voltaram ao espaço de teste e confirmaram a arquitetura M15/M1.

Grupo WFE (%) Janelas Positivas PF Mediano DD Máximo (%)  Lucro OOS (R$)
Timeframes 85,94 8/12 1,229 9,78 6729 
EMAs 74,37 9/12 1,103 9,54 7173
Gatilho ATR 54,84 9/12 1,211 17,08 6027 
Slope do Regime 72,49 9/12 1,120 9,44 6237 
Slope de Retração 66,27 7/12 1,270 10,45 5464 
Canal ATR do Regime 64,58 9/12 1,188 9,09 6007 
Janela ATR Flexível 58,45 8/12 1,046 17,22 5525 
Stop 51,82 7/12 1,148 13,90 4017 
Breakeven 58,89 6/12 1,049 11,35 4531
Trailing 53,86 7/12 1,095 9,78 4540 

Table 4 — Consolidation WIN battery using 12-month ISS windows.

As 12 rodadas da bateria final foram classificadas como fortes. Mais importante que o melhor passe, surgiu uma região de continuidade aproximadamente formada por:

  • Estabilidade da separação entre regime e retração.
  • Vizinhanças consistentes nos períodos das médias.
  • Faixa de ATR não dependente de um único valor.
  • Região coerente para stop, slopes e canal ATR.
  • Limites mínimo e máximo de distância avaliados em conjunto.

Essas faixas não devem ser tratadas como receita operacional. Seu valor está em mostrar que o comportamento não dependia de um único ponto. Quando configurações vizinhas permanecem aceitáveis, existe um platô paramétrico. Quando somente uma combinação se destaca e todas ao redor falham, existe um pico com maior risco de sobreajuste.


Conclusão: de uma ideia simples à validação

Esta série acompanhou a evolução completa de uma estratégia de pullback: dos fundamentos, passando pela construção do EA no MetaTrader 5, até a investigação de sua robustez fora da amostra.

O primeiro WFE mostrou que a gestão sobrevivia melhor que o núcleo das EMAs. A introdução de slope, canal ATR e afrouxamento controlado do gatilho permitiu testar novas hipóteses, mas também confirmou que adicionar complexidade nem sempre melhora a continuidade.

A principal contribuição não é um set definitivo, mas um método: adicionar graus de liberdade com significado, permitir que cada lógica seja desativada, procurar platôs paramétricos e exigir consistência em WFE.

Uma estratégia não se torna robusta por apresentar o maior lucro, mas por continuar reconhecível quando suas fragilidades são deliberadamente testadas.

É aí que termina a otimização, e começa a validação de verdade.

Próximos passos

A investigação avançará para uma WFA aninhada, com os seguintes objetivos:

  • analisar os clusters formados nos resultados ISS para selecionar os representantes destinados aos respectivos OOS;
  • identificar, ao final das janelas, quais regiões paramétricas e medoides apareceram com maior frequência;
  • montar e congelar poucos sets representativos para submetê-los a um teste final e intocado de robustez.
Nº Nome Tipo Descrição
1 SimplePullback_WIN_GlobalOpt.mq5 Expert Advisor EA utilizado na validação inicial da estratégia.
2 OneEMA_LooseCore_GlobalOpt.mq5 Expert Advisor EA ampliado utilizado nas etapas de exploração e consolidação.
Automatizando Estratégias de Trading em MQL5 (Parte 14): Estratégia de Layering de Trades com MACD, RSI e Métodos Estatísticos Automatizando Estratégias de Trading em MQL5 (Parte 14): Estratégia de Layering de Trades com MACD, RSI e Métodos Estatísticos
Neste artigo, apresentamos uma estratégia de trade layering (escalonamento de posições) que combina os indicadores MACD e RSI com métodos estatísticos para automatizar o trading dinâmico em MQL5. Exploramos a arquitetura dessa abordagem em cascata, detalhamos sua implementação por meio dos principais segmentos de código e orientamos os leitores sobre o backtesting para otimizar o desempenho. Por fim, concluímos destacando o potencial da estratégia e preparando o terreno para melhorias futuras no trading automatizado.
Redes neurais em trading: Treinamento de modelos spiking profundos (SEW-ResNet) Redes neurais em trading: Treinamento de modelos spiking profundos (SEW-ResNet)
Convidamos você a conhecer o framework SEW-ResNet, que permite construir modelos spiking profundos sem problemas de degradação e com controle eficiente dos gradientes. Neste artigo, demonstramos como implementar um neurônio spiking básico e seus algoritmos com MQL5.
Engenharia de Atributos com Python e MQL5 (Parte IV): Reconhecimento de Padrões de Candlestick com Regressão UMAP Engenharia de Atributos com Python e MQL5 (Parte IV): Reconhecimento de Padrões de Candlestick com Regressão UMAP
Técnicas de redução de dimensionalidade são amplamente utilizadas para melhorar o desempenho de modelos de machine learning. Vamos discutir uma técnica relativamente nova conhecida como Uniform Manifold Approximation and Projection (UMAP). Essa nova técnica oi desenvolvida explicitamente para superar as limitações de métodos tradicionais que criam artefatos e distorções nos dados. UMAP é uma poderosa técnica de redução de dimensionalidade e nos ajuda a agrupar candlesticks semelhantes de uma maneira nova e eficaz, reduzindo nossas taxas de erro em dados out-of-sample e melhorando nosso desempenho de trading.
Criação de um robô market-neutral probabilístico com base na distribuição dos retornos Criação de um robô market-neutral probabilístico com base na distribuição dos retornos
Uma estratégia de trading market-neutral baseada na distribuição empírica dos retornos oferece uma alternativa aos métodos clássicos de análise técnica, substituindo a previsão da direção do preço pelo posicionamento estatístico de ordens em níveis com determinada probabilidade de serem atingidos. O artigo analisa em detalhes o formalismo matemático usado no cálculo de percentis, os algoritmos de ponderação do volume das posições de acordo com a probabilidade de execução e os mecanismos de adaptação às mudanças nas condições de mercado por meio da expiração da grade. Também é apresentada uma implementação completa em MQL5.