Aula 12
Do Modelo Prático à Classificação Automatizada
Lição 12 — Do Modelo Prático à Classificação Automatizada
Ideia Central
Ter as variáveis de movimentação de preço calculadas para cada jogo não é suficiente. O próximo passo — e onde a maioria dos operadores para — é classificar esses movimentos em categorias operacionais. A classificação transforma dados brutos em rótulos que permitem backtesting, filtragem de amostras e, finalmente, a construção de modelos preditivos. Nesta lição, você aprenderá a estruturar um pipeline de classificação que vai do manual ao automatizado, com um script Python funcional como ponto de partida.
Modelo Mental
Pense na classificação como uma camada de abstração entre o dado cru e a decisão. Você tem variáveis numéricas (percentuais, tempos, limites). Sem classificação, elas são apenas números. Com classificação, cada movimento recebe um rótulo que carrega informação operacional: o que aconteceu, com que intensidade, e sob quais condições.
O modelo mental é o de um funil de categorização:
- Coleta → dados de odds brutas.
- Transformação → cálculo das variáveis de movimento.
- Classificação → atribuição de rótulos (trend, reversal, fake, drift, etc.).
- Validação → conferência manual de uma amostra para calibrar regras.
- Automação → script que executa a classificação em lote.
Cada etapa depende da anterior. Se a coleta ou transformação estiverem erradas, a classificação será ruído com etiqueta.
O que é
Classificação de movimentos de preço é o processo de atribuir um rótulo categórico a cada sequência de variação de odd observada em um mercado, com base em regras definidas a priori sobre as variáveis calculadas.
Os rótulos mais comuns no contexto de mercados de previsão esportiva são:
| Rótulo | Definição Operacional |
|---|---|
| Trend | Movimento direcional sustentado na mesma direção, com crescimento progressivo das odds ou queda consistente. |
| Reversal | Movimento que inverte a direção após uma fase anterior, com volume ou magnitude suficiente para configurar mudança de regime. |
| Fake | Movimento inicial forte em uma direção que é completamente revertido antes do fechamento, deixando a odd final próxima ou inferior à opening odd na direção oposta. |
| Drift | Movimento lento, gradual e unidirecional, sem acelerações bruscas, tipicamente associado a fluxo de dinheiro discreto. |
| Spike | Movimento abrupto e de curta duração, geralmente causado por notícia ou ação institucional pontual, com possível reversão parcial ou total. |
| Stable | Variação dentro de banda estreita, sem direção clara, com estabilidade pós-movimento elevada. |
| Chop | Oscilação repetida entre direções opostas, sem tendência definida, com múltiplas reversões de baixa magnitude. |
Por que importa
Sem classificação, você não pode:
- Segmentar amostras para backtesting direcionado.
- Identificar padrões recorrentes antes de eventos específicos (lineup announcement, injury news, weather).
- Construir features para modelos de machine learning supervisionado.
- Criar alertas operacionais baseados em tipos de movimento, não apenas em magnitude.
- Avaliar a qualidade do seu modelo comparando previsões contra movimentos classificados, não contra números brutos.
A classificação é a ponte entre análise descritiva e análise preditiva. É o que permite responder: quando um movimento do tipo X ocorre, qual a probabilidade condicional de Y acontecer?
Mecanismo
O mecanismo de classificação segue três etapas lógicas:
1. Definição de regras por rótulo
Cada rótulo é definido por um conjunto de condições sobre as variáveis. As condições podem ser:
- Simples (uma única variável)
- Compostas (combinação de variáveis com operadores lógicos)
- Hierárquicas (verificação em sequência, com stop condition)
A hierarquia é crítica: um movimento pode satisfazer condições de múltiplos rótulos. A ordem de verificação determina qual rótulo prevalece.
2. Implementação de regras em código
Regras são traduzidas para lógica condicional em Python. A estrutura básica é:
se condição_trend → rótulo = "trend"
senão se condição_reversal → rótulo = "reversal"
senão se condição_fake → rótulo = "fake"
...
3. Validação e calibração
Após a primeira execução, uma amostra dos resultados deve ser conferida manualmente. Regras mal calibradas geram:
- Falsos positivos (rótulo incorreto)
- Falsos negativos (movimento não classificado)
- Classificações ambíguas (movimento que não se encaixa em nenhum rótulo)
A calibração ajusta thresholds, ordem de verificação e condições de exclusão.
Exemplo Aplicado de Futebol e Mercado
Vamos classificar um movimento no mercado Over/Under 2.5 gols de um jogo de futebol.
Dados brutos:
| Variável | Valor |
|---|---|
| Opening Odd | 1.90 |
| Closing Odd | 1.72 |
| Max Odd | 2.05 |
| Min Odd | 1.68 |
| Total Move % | -9.47% |
| Max Drop % | -18.42% |
| Max Rise % | +7.89% |
| Reversal % | 58.3% |
| Time of Biggest Move | 47 min before kickoff |
| Limit at Move | 1.68 |
| Limit Growth | -0.22 |
| Stability After Move | 0.82 |
| Movement Type (ground truth) | Reversal |
Análise passo a passo:
- Direção principal: A odd caiu de 1.90 para 1.72 (-9.47%). Movimentação descendente.
- Magnitude do drop: Max Drop de -18.42% é significativo. Houve pressão forte de venda no Over.
- Reversão: Reversal % de 58.3% indica que mais da metade da queda foi recuperada. A odd tocou 1.68 (min) e subiu para 1.72 no fechamento.
- Timing: O maior movimento ocorreu 47 minutos antes do kickoff — janela de lineup/news.
- Estabilidade pós-movimento: 0.82 é alto, indicando que após o spike de queda, o mercado estabilizou na recuperação.
Classificação: O movimento é um Reversal. A queda inicial foi forte, mas houve recuperação significativa (58.3%), com estabilização posterior. Não é fake porque a odd final (1.72) não retornou ao nível de abertura (1.90). Não é trend porque a reversão foi substancial. Não é drift porque a magnitude do drop foi abrupta.
Quadro de Raciocínio (Blackboard)
┌─────────────────────────────────────────────────────────────────┐
│ CLASSIFICAÇÃO DE MOVIMENTO — FLUXO DECISÓRIO │
├─────────────────────────────────────────────────────────────────┤
│ │
│ INPUT: Variáveis calculadas por jogo/mercado │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 1: Verificar Fake │ │
│ │ Condições: │ │
│ │ • Reversal % > 70% │ │
│ │ • Closing Odd ≈ Opening Odd (dentro de ±2%) │ │
│ │ • Max Drop % ou Max Rise % > 10% │ │
│ │ → Se sim: RÓTULO = "fake" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ não │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 2: Verificar Spike │ │
│ │ Condições: │ │
│ │ • Time of Biggest Move < 120 min before kickoff │ │
│ │ • Max Drop % ou Max Rise % > 12% │ │
│ │ • Stability After Move < 0.60 │ │
│ │ → Se sim: RÓTULO = "spike" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ não │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 3: Verificar Trend │ │
│ │ Condições: │ │
│ │ • Total Move % > 5% (na direção) │ │
│ │ • Reversal % < 30% │ │
│ │ • Stability After Move > 0.70 │ │
│ │ → Se sim: RÓTULO = "trend" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ não │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 4: Verificar Reversal │ │
│ │ Condições: │ │
│ │ • Reversal % entre 30% e 70% │ │
│ │ • Max Drop % ou Max Rise % > 8% │ │
│ │ → Se sim: RÓTULO = "reversal" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ não │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 5: Verificar Drift │ │
│ │ Condições: │ │
│ │ • Total Move % entre 2% e 5% │ │
│ │ • Stability After Move > 0.80 │ │
│ │ • Limit Growth < 0.10 │ │
│ │ → Se sim: RÓTULO = "drift" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ não │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PASSO 6: Verificar Chop / Stable │ │
│ │ Condições: │ │
│ │ • Total Move % < 2% → "stable" │ │
│ │ • Reversal % > 40% E |Total Move %| < 4% → "chop" │ │
│ │ → Senão: RÓTULO = "uncategorized" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ OUTPUT: DataFrame com coluna "movement_label" │
│ │
└─────────────────────────────────────────────────────────────────┘
Modo de Falha
Classificação automatizada falha quando:
-
Regras sobreajustadas — thresholds calibrados em uma amostra pequena que não generalizam. Solução: validação cruzada temporal, não aleatória.
-
Ordem de verificação incorreta — um fake classificado como trend porque a condição de trend é verificada primeiro. Solução: hierarquia fixa, com fake sempre em primeiro lugar.
-
Movimentos atípicos — eventos como early red card, weather change extremo, ou lineup surpresa geram movimentos que não se encaixam em nenhum rótulo. Solução: categoria “uncategorized” + análise qualitativa posterior.
-
Dados de qualidade ruim — odds com gaps, timestamps inconsistentes, ou mercados com liquidez insuficiente produzem variáveis distorcidas. Solução: filtro de liquidez mínimo antes da classificação.
-
Cross-market confirmation ignorado — um movimento em um mercado pode ser confirmado ou negado por outro. Classificar isoladamente gera rótulos enganosos. Solução: incluir cross-market confirmation como variável de decisão.
Checklist
Antes de rodar a classificação em lote:
- Dados limpos: odds com timestamps consistentes, sem gaps, liquidez mínima atingida.
- Variáveis calculadas: todas as 12 variáveis presentes e semanticamente corretas.
- Hierarquia definida: ordem de verificação dos rótulos documentada e fixa.
- Thresholds calibrados: baseados em amostra histórica, não em intuição.
- Categoría “uncategorized”: movimentos que não se encaixam são sinalizados, não forçados.
- Validação manual: pelo menos 50 movimentos conferidos manualmente contra a classificação automática.
- Cross-market verificado: movimentos com confirmação cruzada têm prioridade na hierarquia.
- Log de exceções: movimentos classificados como “uncategorized” são registrados para análise posterior.
- Reproducibilidade: script versionado, com parâmetros fixos e documentação de cada threshold.
Exercício Prático
Objetivo: Implementar e testar um classificador de movimentos de preço em Python.
Dados de entrada: Crie um DataFrame com as seguintes colunas para 20 jogos simulados:
opening_odd, closing_odd, max_odd, min_odd,
total_move_pct, max_drop_pct, max_rise_pct,
reversal_pct, time_of_biggest_move,
limit_at_move, limit_growth, stability_after_move
Requisitos do script:
- Implemente a hierarquia de classificação descrita no blackboard.
- Adicione uma coluna
movement_labelcom o rótulo classificado. - Adicione uma coluna
confidence_scorebaseada na aderência às condições (ex: se todas as condições do rótulo são satisfeitas com folga, confidence = 1.0; se apenas parcialmente, confidence < 1.0). - Exporte o resultado para CSV.
- Inclua uma função de validação que compare a classificação automática com rótulos ground truth (forneça 5 exemplos com rótulos conhecidos para testar).
Critério de sucesso: Pelo menos 4 dos 5 exemplos ground truth devem ser classificados corretamente. Movimentos com confidence < 0.5 devem ser marcados como “uncategorized” em vez de forçar um rótulo.
Síntese Operacional
A classificação de movimentos de preço é a etapa que transforma variáveis brutos em informação operacional. Sem ela, você tem números; com ela, tem rótulos que permitem segmentação, backtesting e construção de modelos.
Os pontos críticos são:
- Hierarquia fixa: fake → spike → trend → reversal → drift → chop/stable → uncategorized.
- Thresholds calibrados empiricamente, não adivinhados.
- Validação manual obrigatória antes de qualquer automação em escala.
- Uncategorized é um rótulo válido: movimentos atípicos não devem ser forçados em categorias existentes.
- Cross-market confirmation deve ser considerado como variável de decisão, não como pós-processamento.
O script Python apresentado é um ponto de partida, não uma solução final. Cada mercado, cada bookmaker, cada liga exige ajuste de thresholds. A automação vem depois da compreensão manual.
Próxima lição: Feature Engineering a partir de Movimentos Classificados — como transformar rótulos em variáveis preditivas para modelos de machine learning.