EN

Dados B3 › Guias › Backtest

Guia · Backtest

Retorno total na B3 com o Dados B3: o que a base entrega e o que você ainda constrói

A base entrega o preço do pregão, os proventos e os eventos societários de cada papel, cada um com a sua fonte. O que não vem pronto é a série ajustada nem o retorno total: essa é uma conta sua. Este guia mostra a receita, os pontos em que ela pede uma decisão e a conferência que fecha o cálculo.

O que cada rota entrega

RotaO que trazAjustado?
/empresas/{T}/precosSérie diária (abertura, máxima, mínima, fechamento, volume), numa chamada; de/ate e formato=csvNão
/empresas/{T}/eventosDesdobramentos, grupamentos, bonificações e cisões: fonte, fator declarado, efeito líquido do dia, o que o preço disse—
/empresas/{T}/dividendosProventos com data-com e valor por ação, bruto de IR sobre JCPNa base da época
/empresas/{T}/multiplosMúltiplos ponto-no-tempo, com o preço do 1º pregão depois da publicação do balançoNão

Todas pedem chave, exceto nos papéis abertos; a grátis serve (200 consultas por dia, sem cartão). A série inteira de um papel é uma consulta.

A receita, em cinco passos

import json, os, urllib.request

def get(rota):
    req = urllib.request.Request("https://dadosb3.com" + rota,
                                 headers={"X-API-Key": os.environ["DADOS_B3_API_KEY"]})
    return json.load(urllib.request.urlopen(req))

T = "WEGE3"
precos = get(f"/empresas/{T}/precos")["serie"]          # 1 chamada: a série inteira
eventos = get(f"/empresas/{T}/eventos")["eventos"]
proventos = get(f"/empresas/{T}/dividendos")["proventos"]

# 1) um fator por dia de evento: o efeito líquido já é o do grupo de eventos do dia
fatores = {}
for e in eventos:
    if e["cisao"] or not e["aplicado_no_ajuste"] or e["efeito_liquido_do_dia"] is None:
        continue
    fatores[e["data_ex"]] = e["efeito_liquido_do_dia"]

def fator_depois(data):
    """produto dos eventos que ainda vão acontecer a partir deste dia (data_ex >= data)"""
    f = 1.0
    for d, x in fatores.items():
        if d >= data:
            f *= x
    return f

# 2) fechamento ajustado: o preço de ANTES do evento é dividido pelo efeito líquido
datas = [p["data"] for p in precos]
fech = {p["data"]: p["fechamento"] / fator_depois(p["data"]) for p in precos}

# 3) provento: sai no pregão seguinte à data-com, no valor ajustado como o preço
ex = {}
for p in proventos:
    if p["tipo_acao"] != "ON" or not p["data_com"]:
        continue
    seguinte = next((d for d in datas if d > p["data_com"]), None)
    if seguinte:
        ex[seguinte] = ex.get(seguinte, 0.0) + p["valor"] / fator_depois(p["data_com"])

# 4) retorno total diário e índice acumulado (base 1,0; proventos reinvestidos no fechamento do dia)
indice, anterior = {}, None
acum = 1.0
for d in datas:
    if anterior:
        acum *= (fech[d] + ex.get(d, 0.0)) / fech[anterior]
    indice[d], anterior = acum, d

# 5) conferir: o maior salto diário que SOBROU depois do ajuste
saltos = sorted(((fech[b] / fech[a] - 1, b) for a, b in zip(datas, datas[1:])), key=lambda s: abs(s[0]))
print(saltos[-3:])

Passos 1 e 2: o preço de antes de um evento é dividido pelo efeito líquido dele, e o ajuste é acumulativo. Passo 3: o provento declarado antes de um desdobramento está na quantidade de ações da época, então recebe o mesmo ajuste do preço. Passo 4: o retorno do dia é o fechamento mais o provento que sai nesse dia, sobre o fechamento anterior. Passo 5 é a conferência, explicada mais abaixo.

Dois detalhes que mudam o número

A data do evento é o último dia COM direito. O campo data_ex traz o lastDatePrior da B3: o preço cai no pregão seguinte. Por isso o ajuste divide as linhas com data <= data_ex, como no código.

Eventos do mesmo dia são uma operação só. A B3 registra cada perna como linha separada. No TIMS3, em 02/07/2025, há um grupamento de 0,01× e um desdobramento de 100× aprovados em 02/06/2025: juntos valem 1,00× e o preço não saltou (fechou em 21,96 e 22,60 nos dois pregões em volta). Aplicar uma perna só criaria um salto de cem vezes. Por isso a rota traz efeito_liquido_do_dia, o produto do grupo, e o código acima usa esse campo.

O que fica como decisão sua

Conferir antes de confiar

Depois do ajuste, olhe o maior salto diário que sobrou. No WEGE3, o desdobramento de 28/04/2021 aparece como queda de 50,7% no preço bruto e some no ajustado; o maior salto que resta é de -20,6%, em 16/03/2020, uma queda real de mercado. Um salto que sobra sem explicação de mercado merece fonte primária. Exemplo na própria base: o ITUB4 caiu 18,0% em 04/10/2021 (de 29,67 para 24,34) e a base não tem nenhum evento dele em 2021. Uma queda desse tamanho sem evento registrado costuma indicar uma separação ou distribuição que a base não captura: o ajuste automático não a corrige, e o pesquisador precisa decidir como tratá-la.

Eventos com situação diferente de confirmado_pelo_preco também merecem olhar: divergente_do_preco quer dizer que o fator declarado não explica a queda observada, e a ação sai do cálculo naquele período.

O que a base não faz

This page in English

Fontes: CVM (dados abertos, ODbL) e B3 (COTAHIST). Não afiliado à B3 nem à CVM. Não é recomendação de investimento.

Os números desta página são ao vivo. Versão do dado 2026-11-09-ancora-do-fre · página gerada em 2026-11-10 02:36 UTC. Se isto não bater com o /saude, você está lendo uma cópia em cache.