A única ferramenta é um walk-forward rolling, e o que ele valida não é um conjunto de parâmetros.
Você já leu a mesma frase nos livros e até no nosso próprio Como ler um backtest: não otimize em cima de todos os dados, separe pelo menos 20–30% para validação fora da amostra. Aí você abre a área de trabalho, clica em cada aba uma por uma, e não acha aquela configuração de proporção em lugar nenhum.
Não achar é normal: o produto não tem essa funcionalidade. A questão do fora da amostra tem no Blave uma única implementação: o walk-forward rolling da quinta aba, onde o que se preenche são dias e onde o que se valida também é um pouco diferente de uma divisão simples. Este artigo deixa claro onde está a diferença e como se lê cada número daquela aba.
Em Como evitar overfitting há uma tabela que classifica três formas de fazer: otimizar em todos os dados (inútil), treinar nos primeiros 70% e testar nos últimos 30% (útil mas limitado), e reescolher com janela deslizante (o mais realista). Aquela tabela é um julgamento no plano conceitual; o fato no plano do produto é que só a terceira tem botão.
| Forma de fazer | Conceitualmente | No Blave |
|---|---|---|
| Otimizar em todo o histórico e reportar em todo o histórico | Dentro da amostra, necessariamente otimista | A aba Backtest já calcula o resultado em cima de todo o histórico por natureza, e é justamente por isso que precisa validar à parte |
| Um corte só: treinar na frente, testar atrás | Útil, mas só dá para usar uma vez | Esta funcionalidade não existe; não há configuração de proporção para encontrar |
| Walk-forward rolling: reescolher a cada rodada, testar o trecho seguinte | O mais próximo de operar de verdade | A quinta aba da área de trabalho, «Fora da amostra» |
A diferença não é só de interface. Uma divisão simples valida se «este conjunto de parâmetros vai bem nos dados da parte de trás»; um walk-forward rolling valida se a própria prática de «escolher parâmetros a partir do histórico» se sustenta nesta estratégia — ele repete n vezes o ato de «escolher parâmetros com um trecho de histórico» e dá nota a cada vez com o trecho seguinte, que nunca viu.
Em uma frase: reescolher parâmetros dentro de cada janela de treino, aplicá-los à janela de teste que vem logo em seguida e emendar todas as janelas de teste em uma única linha.
| Rodada | Janela de treino | Janela de teste |
|---|---|---|
| 1 | 2022-01-05 → 2024-12-30 | 2024-12-31 → 2025-01-29 |
| 2 | 2022-02-04 → 2025-01-29 | 2025-01-30 → 2025-02-28 |
| 3 | 2022-03-06 → 2025-02-28 | 2025-03-01 → 2025-03-30 |
| … | (as rodadas do meio também avançam uma janela de teste por vez, 20 rodadas no total) | |
| 20 | 2023-07-29 → 2026-07-23 | 2026-07-24 → 2026-08-22 |
As janelas de teste se emendam ponta a ponta até o dia: a rodada 1 para em 2025-01-29 e a rodada 2 engata a partir de 2025-01-30, sem vão nem sobreposição no meio — os 20 trechos emendados são aquela série fora da amostra.
Já as janelas de treino se sobrepõem muito: uma janela de três anos avança só 30 dias por rodada, então o período de treino de quaisquer duas rodadas é praticamente o mesmo trecho de dados. O que se sobrepõe não dá para emendar numa linha contínua — e é por isso que no gráfico só existe a de fora da amostra.
Na implementação ele faz duas passadas: a primeira calcula o sinal de cada conjunto de parâmetros candidato uma única vez sobre todo o histórico e recorta dali a fatia de treino de cada rodada para precificar; a segunda só recalcula o conjunto vencedor de cada rodada, enfia as fatias de teste em uma série só e precifica o trecho inteiro de uma vez. Por isso ele é muito mais rápido do que «rodar n varreduras completas» — o exemplo abaixo, de 20 rodadas e 4.7 anos em gráfico horário, terminou em 3.5 segundos na execução de 2026-09-17 (a caixa de confirmação da interface dá o caso geral: «Costuma levar uns dois minutos; os resultados aparecem nesta aba.»).
Rolling é a janela de treino deslizando inteira para a frente a cada rodada; anchored é o início ficar fixo e a janela de treino ir ficando cada vez mais longa. O produto só oferece rolling; anchored é de propósito que não é oferecido. Se você pedir anchored ao agente, ele responde com uma frase fixa e roda rolling do mesmo jeito:
Também não adianta pensar em dar a volta: a lib que roda o walk-forward é somente leitura e o processo residente recusa a edição na hora; e o arquivo de resultado não tem campo nenhum para marcar «isto rodou como anchored», então, mesmo que você mudasse de verdade, a tela continuaria exibindo como rolling.
Na aba só existem dois campos: janela de treino e janela de teste, ambos em dias, com um indicador ao lado mostrando na hora quantas rodadas aquilo recorta. Se deixar os dois em branco, vale esta tabela padrão:
| Comprimento dos dados (dias) | Janela de treino (dias) | Janela de teste (de quanto em quanto tempo reescolher, em dias) |
|---|---|---|
| ≥ 1185 | 1095(três anos) | 30 |
| 455–1184 | 365(um ano) | 30 |
| < 455 | 4× a janela de teste | total de dias ÷ 12, mínimo 30 |
Aquele degrau de três anos tem motivo: ele fica mais perto do que as pessoas fazem de verdade, que é escolher um conjunto fixo de parâmetros a partir do backtest inteiro. Se um histórico de tamanho médio caísse direto na fórmula de proporção, a janela de treino sairia menor que um ano, então no meio foi acrescentado o degrau de 365 / 30.
Dois limites duros barram na hora em vez de te entregar um resultado pela metade: abaixo de 3 rodadas ele não roda nem escreve o arquivo de resultado («Os dados só dão para {n} rodadas — 3 é o mínimo para ler alguma coisa fora da amostra»); acima de 1000 rodadas ele barra igual («aumente a janela de teste»). Os dados que sobram na ponta e não completam uma rodada não são forçados, e embaixo do gráfico fica a nota «os últimos {d} dias não completam uma rodada e ficaram de fora».
O cartão de conclusão olha um número só:
WFE = Sharpe fora da amostra ÷ Sharpe médio dentro da amostra
O numerador é o Sharpe de todo o trecho já emendado da série fora da amostra; o denominador é a média do Sharpe da própria célula vencedora dentro da janela de treino de cada rodada. Os quatro rótulos seguem estas fronteiras (todas são «menor que», então 0.5 cai em «pouco acima do limiar» e 0.7 em «acima do limiar»):
| WFE | O cartão de conclusão mostra |
|---|---|
| Não dá para calcular | Eficiência fora da amostra: não é possível avaliar |
| < 0.2 | Eficiência fora da amostra: muito abaixo do limiar |
| < 0.5 | Eficiência fora da amostra: abaixo do limiar |
| < 0.7 | Eficiência fora da amostra: pouco acima do limiar |
| ≥ 0.7 | Eficiência fora da amostra: acima do limiar |
E a explicação que fica ao lado daquele número, leia ao pé da letra:
Um denominador muito pequeno ou negativo vira o diagnóstico inteiro de cabeça para baixo: uma estratégia que nunca foi forte dentro da amostra acaba tirando uma «eficiência» altíssima justamente porque «não tinha nada para devolver». Daí as duas defesas:
A estratégia de exemplo do tutorial btc_sma_cross (BTCUSDT 1h, a partir de 2022-01-01, 1,720 dias no total, SMA 45 / 100, sem mudar uma letra dos parâmetros). Os dados caem no primeiro degrau, então valem as janelas padrão 1095 / 30, recortando 20 rodadas (600 dias de janelas de teste no total); os últimos 25 dias não completam uma rodada e ficaram de fora.
| Item | Fora da amostra (janelas de teste emendadas, 600 dias) | Dentro da amostra (20 janelas de treino calculadas cada uma e depois promediadas) |
|---|---|---|
| Sharpe | −0.45 | 1.3471 |
| Retorno anual | −16.55% | +50.16% |
| Drawdown máximo | −46.57% | — |
| Negociações | 183 | — |
Eficiência fora da amostra WFE = −0.45 ÷ 1.3471 = −0.334 → muito abaixo do limiar
Vale apontar três coisas. Primeira, nenhuma rodada foi excluída — o Sharpe da janela de treino das 20 rodadas ficou todo acima de 0, então o denominador é a média completa das 20 rodadas, e não o que sobrou depois da peneira.
Segunda, o denominador de 1.3471 está muito acima de 0.25, então a segunda defesa não disparou e a divisão é válida: «o WFE é negativo» e «o WFE não é possível avaliar» são duas coisas diferentes — a primeira é um resultado calculado, a segunda é uma recusa a responder.
Terceira, aquelas duas colunas cobrem períodos diferentes por construção — dentro da amostra é a média de 20 janelas de treino que se sobrepõem entre si, e fora da amostra são os 600 dias seguintes, então não é uma comparação limpa do mesmo período; e é justamente essa defasagem que o WFE quer medir.
No mesmo dia e com o mesmo código, o valor-p do MCPT desta estratégia é 0.0160 (n = 2000), e o próprio stdout imprime significant edge at 95% — pelo critério de publicação, isso é aprovado.
| Teste | A pergunta que ele faz | Resultado |
|---|---|---|
| MCPT | Nesta série fixa de posições, dá para distinguir este resultado de sorte? | p = 0.0160 → Aprovado |
| Walk-forward | O próprio ato de escolher parâmetros a partir do histórico continua funcionando no trecho seguinte? | WFE = −0.334 → muito abaixo do limiar |
Nenhum dos dois está calculado errado, porque eles não respondem à mesma pergunta. É também por isso que nenhum valor-p, por mais bonito que seja, pode ser tomado como validado fora da amostra (veja Como ler o valor-p do MCPT). E já deixando claro: isto não é dizer que a estratégia está quebrada — ela é o exemplo do tutorial que vem com a área de trabalho, e o que se ilustra aqui é a diferença de significado entre os dois testes.
Cada rodada escolhe os parâmetros usando a média de uma vizinhança 3×3 (a mesma regra da varredura de parâmetros, ou seja, escolher o platô e não o pico, como explica Como evitar overfitting), mas o Sharpe de treino reportado na tabela de rodadas é o número da própria célula vencedora. Isso é de propósito:
| O que o denominador usa | Consequência |
|---|---|
| O Sharpe da própria célula (comportamento atual) | O denominador fica alto, então o WFE sai conservador |
| A média da vizinhança 3×3 | Uma média de vizinhança é estruturalmente mais baixa do que a célula que ela cerca → o denominador é achatado → o WFE fica inflado e a aba inteira se lê otimista demais |
Um diagnóstico com o denominador inflado é pior do que não fazer diagnóstico nenhum.
Na junção entre duas rodadas, a série carrega a posição da própria rodada nova — ela é cortada, não zerada. Forçar o encerramento em cada emenda seria inventar n−1 saídas que ninguém chegou a negociar.
O custo de trocar de parâmetros também não se perde: na emenda o peso muda e, na precificação, as taxas são cobradas direitinho. E como os números de cada rodada são recortados da mesma série já emendada e não são precificados de novo, a soma da tabela de rodadas bate exatamente com o total do trecho inteiro.
Os sinais são calculados sobre todo o histórico (indicadores rolling só saem certos assim), mas cada fatia de treino pula as barras de aquecimento do próprio começo dela — e não só a primeira rodada. Sem esse passo, a rodada 1 treinaria em barras nas quais o indicador ainda não esquentou e acabaria pegando ruído, e o comprimento efetivo de cada rodada também ficaria diferente e incomparável. A tabela de rodadas acima é a prova: o START da estratégia diz 2022-01-01, mas a janela de treino da rodada 1 só começa em 2022-01-05 — aqueles poucos dias de diferença são exatamente as WARMUP = 100 barras horárias (cerca de 4.2 dias) que foram descontadas.
A janela de teste não é aparada, porque ela já vem quente e porque precisa ser contínua para poder ser emendada. E já que estamos aqui, uma pergunta frequente de leitores avançados: aqui não é preciso um período de embargo — a janela de teste fica colada logo atrás da janela de treino que escolheu os parâmetros dela, e os dados posteriores a ela não são usados de forma alguma.
Terminada a execução não existe botão de «aplicar os parâmetros sugeridos», e o agente também não tem permissão para mexer no código da sua estratégia por causa deste resultado. O estado vazio já diz isso de cara:
Por que não dá para copiar? Olhe a deriva de parâmetros daquela execução. Ao longo de 20 rodadas ela escolheu apenas 4 conjuntos de parâmetros diferentes:
(45,100) ×14 → (55,80) → (45,100) → (45,80) ×3 → (35,80)
As primeiras 14 rodadas ficaram todas na mesma célula. Mesmo que «na maior parte do tempo ele escolhe 45 / 100» pareça uma conclusão, aquela curva fora da amostra de −0.45 também não é o resultado de 45 / 100 — ela é um trecho inteiro corrido em revezamento por 4 conjuntos de parâmetros, que não pertence a nenhum deles, então não há nenhum conjunto que possa ser «adotado». Quando você pede que sejam aplicados, o agente responde com uma frase fixa:
A grade de deriva de parâmetros desenha qual célula cada rodada escolheu e em quantas rodadas ela foi escolhida, uma moldura tracejada marca os seus parâmetros atuais, e a legenda deixa escrito que «os parâmetros da última rodada são apenas referência, não um valor recomendado» — a última rodada daquela execução escolheu 35 / 80, o que só significa «a janela de treino daquela última rodada calhou de cair nesta célula». Além disso, esta aba não mostra valor-p e nunca roda MCPT; rodar um walk-forward conta como uma iteração nas regras de trabalho do agente.
As rodadas são suficientes? Abaixo de 3 ele nem roda. Quando há poucas rodadas, o WFE é só a sorte de uma ou duas janelas de teste.
Alguma rodada foi excluída? O detalhe por rodada anota quais tiveram Sharpe da janela de treino ≤ 0. Na execução acima nenhuma foi excluída; quanto mais rodadas forem excluídas, mais isso quer dizer que esta estratégia muitas vezes não acha nada nem dentro das próprias janelas de treino.
O WFE é «não é possível avaliar» ou um número negativo? Não é a mesma coisa. «Não é possível avaliar» quer dizer que a média dentro da amostra está abaixo de 0.25 e essa razão não tem sentido; um número negativo quer dizer que a divisão foi feita e que o trecho fora da amostra deu prejuízo.
Quanto os parâmetros derivam? Olhe a linha «{n} rodadas escolheram {u} pares diferentes». A execução acima foram 20 rodadas e 4 conjuntos; se cada rodada pula para uma célula completamente diferente, cada reescolha está correndo atrás de outra coisa.
Você não estaria procurando parâmetros recomendados? Não existem. Para trocar de parâmetros use o ponto robusto da varredura de parâmetros, e não copie a última rodada.
Depois de rodar uma vez, se o WFE despencar feio, o problema costuma não estar neste passo do fora da amostra, mas no passo de escolher parâmetros — e isso é território de Como evitar overfitting. Se você ainda não tem uma estratégia que valha a pena validar, toda estratégia oficial da Biblioteca de estratégias vem com backtest real e o resultado dos critérios de qualidade, então dá para olhar os números antes de decidir: Biblioteca de estratégias.