Construindo Backtesting de Estratégias de Trading em Python

No mercado financeiro, testar uma estratégia antes de operar com dinheiro real é crucial para reduzir riscos. O backtesting consiste em simular trades passados usando dados históricos para verificar se a estratégia seria lucrativa ou não.

Com Python, podemos implementar backtests de forma flexível, analisando ações, ETFs, criptomoedas ou qualquer ativo com histórico de preços.


1. Por que o Backtesting é Importante

  • Validação da estratégia: saber se a abordagem funciona em condições históricas.

  • Medição de risco: identificar drawdowns, volatilidade e perda máxima.

  • Aprimoramento contínuo: ajustar parâmetros como médias móveis ou stop-loss.

  • Evitar vieses: reduzir decisões emocionais e testar objetivamente regras de trading.


2. Preparando o Ambiente

Instale as bibliotecas necessárias:

pip install pandas numpy matplotlib yfinance
  • pandas → manipulação de dados.

  • numpy → cálculos matemáticos.

  • matplotlib → visualização de gráficos.

  • yfinance → download de dados históricos.


3. Coletando Dados Históricos

Vamos usar ações brasileiras (PETR4) como exemplo.

import yfinance as yf
import pandas as pd

dados = yf.download("PETR4.SA", start="2022-01-01", end="2023-12-31")
dados = dados[["Open", "High", "Low", "Close", "Volume"]]
print(dados.head())

4. Definindo uma Estratégia de Trading

Vamos usar uma estratégia clássica de cruzamento de médias móveis:

  • Média Móvel Curta (MM20) → rápido sinal de tendência.

  • Média Móvel Longa (MM50) → confirmação da tendência.

  • Regra de Compra: MM20 cruza acima da MM50.

  • Regra de Venda: MM20 cruza abaixo da MM50.

dados["MM20"] = dados["Close"].rolling(window=20).mean()
dados["MM50"] = dados["Close"].rolling(window=50).mean()

5. Gerando Sinais de Compra e Venda

dados["Sinal"] = 0
dados.loc[dados["MM20"] > dados["MM50"], "Sinal"] = 1  # Comprar
dados.loc[dados["MM20"] < dados["MM50"], "Sinal"] = -1 # Vender

print(dados[["Close", "MM20", "MM50", "Sinal"]].tail(10))

📌 Sinal 1 = posição comprada, -1 = posição vendida, 0 = neutro.


6. Calculando Retornos da Estratégia

dados["Retorno_Diario"] = dados["Close"].pct_change()
dados["Retorno_Estrategia"] = dados["Retorno_Diario"] * dados["Sinal"].shift(1)

# Acumulado
dados["Retorno_Acumulado"] = (1 + dados["Retorno_Estrategia"]).cumprod()
dados["Benchmark"] = (1 + dados["Retorno_Diario"]).cumprod()

7. Visualizando Resultados

import matplotlib.pyplot as plt

plt.figure(figsize=(12,6))
plt.plot(dados["Retorno_Acumulado"], label="Estratégia MM20x50")
plt.plot(dados["Benchmark"], label="Benchmark (Buy & Hold)")
plt.title("Backtesting - Retorno Acumulado")
plt.xlabel("Data")
plt.ylabel("Retorno")
plt.legend()
plt.show()

📌 Esse gráfico permite comparar a performance da estratégia versus apenas comprar e manter o ativo.


8. Métricas de Performance

Além do retorno, é importante calcular métricas de risco:

# Retorno total
retorno_total = dados["Retorno_Acumulado"].iloc[-1] - 1

# Volatilidade anualizada
vol = dados["Retorno_Estrategia"].std() * (252**0.5)

# Drawdown máximo
dados["Roll_Max"] = dados["Retorno_Acumulado"].cummax()
dados["Drawdown"] = dados["Roll_Max"] - dados["Retorno_Acumulado"]
drawdown_max = dados["Drawdown"].max()

print("Retorno total:", round(retorno_total*100,2), "%")
print("Volatilidade anualizada:", round(vol*100,2), "%")
print("Drawdown máximo:", round(drawdown_max*100,2), "%")

📌 Com isso, sabemos não apenas quanto a estratégia poderia render, mas quão arriscada ela seria.


9. Estratégias Mais Complexas

Com Python, podemos expandir o backtesting para:

Exemplo de stop-loss simples:

stop_loss = 0.05  # 5%
dados["Retorno_Estrategia_Stop"] = dados["Retorno_Estrategia"].apply(
    lambda x: -stop_loss if x < -stop_loss else x
)

10. Boas Práticas em Backtesting

  • Evitar Lookahead Bias: não usar informações futuras para decisões passadas.

  • Separar dados: treino e teste, evitando overfitting.

  • Simular custos e slippage: corretagens, spreads e atrasos impactam resultados reais.

  • Testar diferentes parâmetros: otimização de médias móveis, stop-loss, etc.

  • Usar frameworks profissionaisbacktraderziplinebt para backtests mais avançados e robustos.


11. Conclusão

backtesting em Python permite simular estratégias de trading de forma sistemática e confiável.

  • Começamos com uma estratégia simples de cruzamento de médias móveis.

  • Calculamos retornos diários, acumulados e métricas de risco.

  • Visualizamos performance e comparamos com buy & hold.

  • Python oferece ferramentas para expandir o backtesting, incorporando indicadores avançados, portfólios múltiplos e gestão de risco automatizada.

Backtesting bem feito é fundamental para validar ideias de trading antes de investir capital real, aumentando a chance de sucesso e reduzindo perdas inesperadas.

Comentários

Postagens mais visitadas deste blog

Python para Computação Quântica: Introdução com Qiskit

Gerando Relatórios em PDF com Python (ReportLab e FPDF)

Estrutura Básica de um Programa C# com exemplos