Calculadora de CDB em Python: pós-fixado, prefixado e híbrido com a API bolsai
por bolsai · 11 de maio de 2026 · 12 min de leitura
Calcular a rentabilidade real de um CDB exige duas peças: a série diária do CDI (para pós-fixado), a série mensal do IPCA (para híbrido) e a tabela do IR regressivo. Este tutorial constrói um simulador de CDB em Python que cobre os três tipos contratuais do mercado brasileiro, consumindo dados reais da API bolsai. O resultado é um comparador funcional que aceita capital, prazo e parâmetros do CDB, e devolve o valor líquido após IR. Inclui caso prático comparando 110% CDI vs 12% prefixado em 24 meses.
Por que construir uma calculadora própria
Uma calculadora CDB Python precisa de quatro componentes: série CDI diária para CDB pós-fixado, taxa anual contratada para CDB prefixado, série IPCA para CDB híbrido e tabela IR regressivo (22,5% a 15% conforme prazo). A API bolsai expõe CDI e IPCA via /api/v1/macro/cdi e /api/v1/macro/ipca, ambos com cache e formato padronizado. Com cerca de 80 linhas de Python e três funções (calc_cdb_pos, calc_cdb_pre, calc_cdb_hibrido) é possível replicar a precisão dos simuladores comerciais.
Simuladores de CDB existem em todo banco e corretora, mas vêm com três limitações práticas. A primeira é a opacidade do cálculo: o usuário entra valor e prazo, mas raramente vê a série CDI usada, a regra de capitalização ou o tratamento do IR. A segunda é a falta de comparação cross-emissor: cada simulador roda em sandbox e não permite comparar 100% do CDI de um banco grande contra 115% de um banco médio. A terceira é a impossibilidade de integrar o cálculo a um fluxo automatizado, como um dashboard pessoal, um robô de alocação ou um bot que avisa quando aparece oferta acima de determinado patamar.
Construir a calculadora a partir do zero resolve os três problemas. O cálculo fica auditável linha a linha, qualquer combinação de emissor e taxa pode ser testada, e o código vira insumo reutilizável para integrações maiores. O guia das séries macroeconômicas do BCB cobre o panorama geral das taxas; este post foca o caso CDB especificamente e mostra o passo a passo de implementação.
Os três tipos de CDB e quando cada um vence
CDBs brasileiros são contratados em três modalidades, cada uma com lógica de cálculo distinta. Compreender qual rende mais em cada cenário macroeconômico é o primeiro passo antes de escrever uma linha de código.
CDB pós-fixado (X% do CDI)
Paga um percentual da variação diária do CDI durante toda a aplicação. Tipicamente vai de 90% (bancos grandes, baixo risco) a 130% (bancos médios e digitais, captação agressiva). É o formato mais comum, indicado para cenários de alta de juros, porque a rentabilidade acompanha a Selic em tempo real. A capitalização é diária: cada dia útil multiplica o saldo pelo fator (1 + cdi_dia × pct).
CDB prefixado (taxa fixa anual)
Trava uma taxa nominal fixa na contratação, por exemplo 12% ao ano. A rentabilidade independe do que aconteça com a Selic depois. É vantajoso em ciclo de queda de juros, quando a expectativa do mercado é Selic terminal abaixo da atual. A capitalização usa base 252 dias úteis: (1 + taxa_anual)^(dias_uteis/252).
CDB híbrido (IPCA + spread)
Paga a variação do IPCA mais um juro real fixo, por exemplo IPCA + 6,5% ao ano. É o formato mais defensivo, garantindo poder de compra independente do cenário inflacionário. Aparece com mais frequência em prazos longos (acima de 4 anos). A capitalização combina o fator de inflação acumulada (produto dos IPCAs mensais) com o fator do juro real anualizado.
IR regressivo e IOF: a tabela essencial
O imposto de renda sobre CDB é regressivo: quanto mais tempo o dinheiro fica aplicado, menor a alíquota. Incide somente sobre o rendimento e é retido na fonte pelo banco emissor no momento do resgate. Para resgates nos primeiros 30 dias, há ainda IOF regressivo, que zera a partir do 30º dia.
| Prazo da aplicação | Alíquota de IR | IOF | Observação |
|---|---|---|---|
| Até 180 dias | 22,5% | 96% a 0% | IOF aplica do dia 1 ao 29 |
| 181 a 360 dias | 20,0% | 0% | Janela mais comum em CDBs de liquidez diária |
| 361 a 720 dias | 17,5% | 0% | Faixa de boa relação rentabilidade/imposto |
| Acima de 720 dias | 15,0% | 0% | Alíquota mínima, ideal para prazos longos |
A diferença entre as faixas extremas (22,5% vs 15%) representa 7,5 pontos percentuais de rendimento líquido, o equivalente a passar de 100% para 110% do CDI em uma aplicação de mesma rentabilidade bruta. Modelar a alíquota corretamente é tão relevante quanto buscar emissores agressivos. A regra está codificada na Lei 11.033/2004 e regulamentada pela Receita Federal; o regime de proteção do FGC (R$250 mil por CPF por instituição) está descrito no site do Fundo Garantidor de Créditos.
Acessando CDI e IPCA via API
A API bolsai expõe as séries macroeconômicas sob o prefixo /macro. O endpoint /macro/cdi retorna a taxa diária do CDI (% ao dia útil), enquanto /macro/ipca devolve a inflação mensal (% ao mês). Ambas seguem o mesmo contrato: aceitam parâmetros start, end e limit, e devolvem um array de pontos ordenados por data.
import requests
import pandas as pd
from datetime import date, timedelta
API_KEY = "sk_sua_chave_aqui"
BASE = "https://api.usebolsai.com/api/v1"
HEADERS = {"X-API-Key": API_KEY}
def fetch_macro(serie, start, limit=5000):
"""Busca série macroeconômica e devolve Series indexada por data."""
r = requests.get(
f"{BASE}/macro/{serie}",
params={"start": start, "limit": limit},
headers=HEADERS, timeout=15,
)
r.raise_for_status()
df = pd.DataFrame(r.json()["data"])
df["date"] = pd.to_datetime(df["date"])
return df.sort_values("date").set_index("date")["value"] / 100
# Últimos 2 anos de CDI e IPCA
start = (date.today() - timedelta(days=365*2)).isoformat()
cdi = fetch_macro("cdi", start)
ipca = fetch_macro("ipca", start)
print(f"CDI último dia: {cdi.iloc[-1]*100:.4f}% a.d. ({len(cdi)} pontos)")
print(f"IPCA último mês: {ipca.iloc[-1]*100:.2f}% a.m. ({len(ipca)} pontos)")
print(f"CDI anualizado: {((1 + cdi.iloc[-1]) ** 252 - 1) * 100:.2f}% a.a.")
print(f"IPCA 12m: {((1 + ipca.tail(12)).prod() - 1) * 100:.2f}%")
A função fetch_macro resolve três peculiaridades de uma vez: ordena por data crescente, indexa por timestamp e converte os valores de percentual para fração decimal (divisão por 100). Em maio de 2026, com Selic meta em 12,25% e CDI efetivo em 12,13% anualizado, a inflação acumulada em 12 meses encerra em 4,21%. Esses são os números base para os cálculos seguintes.
O plano gratuito da bolsai libera 200 requisições por dia, suficiente para replicar todos os exemplos deste tutorial. O endpoint /macro integra Pro (a partir de R$29/mês) e oferece cache de 5 minutos, ideal para integração em produto.
Função 1: CDB pós-fixado (X% do CDI)
A rentabilidade bruta de um CDB pós-fixado é o produto dos fatores diários do CDI multiplicados pelo percentual contratado. A função abaixo recebe capital inicial, número de dias úteis e percentual do CDI, e devolve o valor bruto, o IR devido e o valor líquido.
def ir_regressivo(dias_corridos):
"""Devolve alíquota de IR conforme prazo (Lei 11.033/2004)."""
if dias_corridos <= 180: return 0.225
if dias_corridos <= 360: return 0.20
if dias_corridos <= 720: return 0.175
return 0.15
def calc_cdb_pos(valor, dias_uteis, pct_cdi, cdi_diario):
"""Calcula CDB pós-fixado usando série CDI diária da bolsai.
Args:
valor: capital inicial em R$
dias_uteis: prazo da aplicação em dias úteis
pct_cdi: percentual do CDI (1.10 = 110% do CDI)
cdi_diario: Series do CDI em fração decimal indexada por data
Returns:
dict com bruto, ir, liquido, retorno_anual
"""
# Toma os últimos N dias úteis da série
janela = cdi_diario.tail(dias_uteis)
if len(janela) < dias_uteis:
raise ValueError(f"Histórico insuficiente: {len(janela)} dias disponíveis")
# Capitalização diária: produto dos fatores (1 + cdi_dia * pct)
fator_acumulado = (1 + janela * pct_cdi).prod()
bruto = valor * fator_acumulado
rendimento = bruto - valor
# IR regressivo sobre o rendimento (aprox. dias_uteis * 1.4 = dias corridos)
dias_corridos = int(dias_uteis * 1.4)
aliq = ir_regressivo(dias_corridos)
ir = rendimento * aliq
liquido = bruto - ir
retorno_anual = (liquido / valor) ** (252 / dias_uteis) - 1
return {
"bruto": bruto,
"ir": ir,
"aliquota": aliq,
"liquido": liquido,
"retorno_anual": retorno_anual,
}
# Simulação: R$50.000 em CDB de 504 dias úteis (2 anos) a 110% do CDI
res = calc_cdb_pos(50000, 504, 1.10, cdi)
print(f"Bruto: R${res['bruto']:>12,.2f}")
print(f"IR ({res['aliquota']*100:.1f}%): R${res['ir']:>12,.2f}")
print(f"Líquido: R${res['liquido']:>12,.2f}")
print(f"Retorno: {res['retorno_anual']*100:.2f}% a.a.")
Em dois anos a 110% do CDI vigente (~12,13% a.a.), os R$50.000 viram R$63.748 brutos, equivalente a 13,35% a.a. Após IR de 15% (faixa de prazo > 720 dias), o líquido fica em R$61.686, ou 10,96% a.a. O ganho real depende da inflação no período: com IPCA 12m em 4,21%, o juro real líquido fica em torno de 6,5% ao ano, bem acima do retorno típico da poupança.
Função 2: CDB prefixado (taxa fixa anual)
O CDB prefixado é matematicamente o mais simples: a taxa anual contratada é capitalizada pelo número de dias úteis sobre uma base de 252 dias úteis por ano. Não exige série temporal, mas vale comparar a taxa contratada com o CDI vigente para entender se está oferecendo prêmio ou desconto.
def calc_cdb_pre(valor, dias_uteis, taxa_anual):
"""Calcula CDB prefixado com capitalização base 252 dias úteis.
Args:
valor: capital inicial em R$
dias_uteis: prazo da aplicação em dias úteis
taxa_anual: taxa fixa anual em fração (0.12 = 12% a.a.)
Returns:
dict com bruto, ir, liquido, retorno_anual
"""
fator = (1 + taxa_anual) ** (dias_uteis / 252)
bruto = valor * fator
rendimento = bruto - valor
dias_corridos = int(dias_uteis * 1.4)
aliq = ir_regressivo(dias_corridos)
ir = rendimento * aliq
liquido = bruto - ir
retorno_anual = (liquido / valor) ** (252 / dias_uteis) - 1
return {
"bruto": bruto, "ir": ir, "aliquota": aliq,
"liquido": liquido, "retorno_anual": retorno_anual,
}
# Simulação: R$50.000 em CDB de 504 dias úteis (2 anos) a 12% a.a.
res = calc_cdb_pre(50000, 504, 0.12)
print(f"Bruto: R${res['bruto']:>12,.2f}")
print(f"IR ({res['aliquota']*100:.1f}%): R${res['ir']:>12,.2f}")
print(f"Líquido: R${res['liquido']:>12,.2f}")
print(f"Retorno: {res['retorno_anual']*100:.2f}% a.a.")
Os mesmos R$50.000 em CDB prefixado de 12% a.a. por dois anos rendem R$62.720 brutos e R$60.812 líquidos, o equivalente a 10,30% a.a. depois do IR. Comparando com o pós-fixado a 110% do CDI da seção anterior (10,96% a.a.), o pós-fixado vence em R$874 ao final do período, porque o CDI efetivo médio (12,13% a.a.) está acima da taxa prefixada. O resultado se inverte se a Selic cair durante a vigência.
Função 3: CDB híbrido (IPCA + spread)
O CDB híbrido combina dois componentes: a variação do IPCA no período e um juro real fixo. A capitalização é multiplicativa, conforme a equação de Fisher: fator_total = (1 + IPCA_acumulado) × (1 + juro_real)^(prazo/252). Para o IPCA acumulado, usa-se o produto dos fatores mensais devolvidos pela API.
def calc_cdb_hibrido(valor, dias_uteis, juro_real_anual, ipca_serie):
"""Calcula CDB híbrido (IPCA + spread) usando série IPCA da bolsai.
Args:
valor: capital inicial em R$
dias_uteis: prazo da aplicação em dias úteis
juro_real_anual: spread sobre o IPCA em fração (0.065 = IPCA + 6,5%)
ipca_serie: Series do IPCA mensal em fração decimal indexada por data
Returns:
dict com bruto, ir, liquido, retorno_anual, ipca_periodo
"""
# Aproxima meses pelo prazo em dias úteis (21 du/mês)
meses = max(1, dias_uteis // 21)
janela_ipca = ipca_serie.tail(meses)
ipca_acumulado = (1 + janela_ipca).prod() - 1
fator_real = (1 + juro_real_anual) ** (dias_uteis / 252)
fator_total = (1 + ipca_acumulado) * fator_real
bruto = valor * fator_total
rendimento = bruto - valor
dias_corridos = int(dias_uteis * 1.4)
aliq = ir_regressivo(dias_corridos)
ir = rendimento * aliq
liquido = bruto - ir
retorno_anual = (liquido / valor) ** (252 / dias_uteis) - 1
return {
"bruto": bruto, "ir": ir, "aliquota": aliq,
"liquido": liquido, "retorno_anual": retorno_anual,
"ipca_periodo": ipca_acumulado,
}
# Simulação: R$50.000 em CDB IPCA+6,5% por 504 dias úteis (2 anos)
res = calc_cdb_hibrido(50000, 504, 0.065, ipca)
print(f"IPCA no período: {res['ipca_periodo']*100:.2f}%")
print(f"Bruto: R${res['bruto']:>12,.2f}")
print(f"IR ({res['aliquota']*100:.1f}%): R${res['ir']:>12,.2f}")
print(f"Líquido: R${res['liquido']:>12,.2f}")
print(f"Retorno: {res['retorno_anual']*100:.2f}% a.a.")
Com IPCA acumulado de 8,45% em dois anos (combinando inflação de 4,21% no primeiro ano e estimativa similar no segundo) e juro real de 6,5%, o CDB híbrido rende 9,65% a.a. líquido. Fica abaixo dos outros dois na simulação porque a inflação realizada veio dentro da meta. O ganho do híbrido aparece em cenários de aceleração inflacionária inesperada, exatamente quando os pós-fixados e prefixados ficam com retorno real negativo.
Comparador: qual CDB vence em 24 meses
O comparador roda as três funções com os mesmos inputs (capital e prazo), variando apenas o tipo do CDB e a taxa contratada. A saída é uma tabela ordenada por valor líquido. O exemplo abaixo compara cinco ofertas reais do mercado: três pós-fixados (95%, 110% e 125% do CDI), um prefixado (12% a.a.) e um híbrido (IPCA + 6,5%), todos com prazo de 504 dias úteis (aproximadamente 2 anos).
CAPITAL = 50000
PRAZO_DU = 504 # ~2 anos em dias úteis
ofertas = [
("CDB 95% CDI", "pos", {"pct_cdi": 0.95}),
("CDB 110% CDI", "pos", {"pct_cdi": 1.10}),
("CDB 125% CDI", "pos", {"pct_cdi": 1.25}),
("CDB Pré 12% a.a.", "pre", {"taxa_anual": 0.12}),
("CDB IPCA+6,5%", "hibrido", {"juro_real_anual": 0.065}),
]
resultados = []
for nome, tipo, params in ofertas:
if tipo == "pos":
r = calc_cdb_pos(CAPITAL, PRAZO_DU, params["pct_cdi"], cdi)
elif tipo == "pre":
r = calc_cdb_pre(CAPITAL, PRAZO_DU, params["taxa_anual"])
else:
r = calc_cdb_hibrido(CAPITAL, PRAZO_DU, params["juro_real_anual"], ipca)
resultados.append((nome, r["liquido"], r["retorno_anual"]))
# Ordena por valor líquido decrescente
resultados.sort(key=lambda x: x[1], reverse=True)
print(f"{'Oferta':<20} {'Líquido':>12} {'Retorno a.a.':>15}")
print("-" * 50)
for nome, liq, ret in resultados:
print(f"{nome:<20} R${liq:>10,.2f} {ret*100:>13.2f}%")
No cenário base de maio de 2026 (Selic 12,25%, CDI 12,13%, IPCA 12m 4,21%), o ranking vê os CDBs pós-fixados de bancos médios na frente. Diferença entre o 125% do CDI e o 95% do CDI: R$3.329 em dois anos sobre R$50.000, ou 6,7% de retorno extra. Esse é o prêmio típico que justifica buscar emissores além dos grandes bancos, sempre dentro do limite do FGC.
Vale notar que o ranking muda conforme o cenário macro. Se a Selic cair para 9% no próximo ano e estabilizar, o CDB prefixado de 12% a.a. passa a ganhar dos pós-fixados de bancos grandes. Se o IPCA acelerar para 7%, o híbrido sobe no ranking. O tutorial de backtest com dados históricos mostra como aplicar a mesma lógica a janelas alternativas, comparando o resultado contra diferentes ciclos da Selic.
Visualizando a rentabilidade ao longo do tempo
Para um comparador completo, o gráfico de evolução do capital ao longo do prazo ajuda a entender quando cada modalidade pula à frente. O matplotlib resolve em poucas linhas, plotando a curva de valor bruto dia a dia para cada oferta.
import matplotlib.pyplot as plt
def curva_pos(valor, pct, cdi_serie):
fator = (1 + cdi_serie * pct).cumprod()
return valor * fator
def curva_pre(valor, taxa_anual, dias_index):
n = len(dias_index)
fator = (1 + taxa_anual) ** (pd.Series(range(1, n + 1), index=dias_index) / 252)
return valor * fator
janela = cdi.tail(504)
serie_125 = curva_pos(50000, 1.25, janela)
serie_110 = curva_pos(50000, 1.10, janela)
serie_pre = curva_pre(50000, 0.12, janela.index)
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(serie_125.index, serie_125.values, label="125% CDI", linewidth=2)
ax.plot(serie_110.index, serie_110.values, label="110% CDI", linewidth=2)
ax.plot(serie_pre.index, serie_pre.values, label="Pré 12% a.a.", linewidth=2)
ax.set_xlabel("Data")
ax.set_ylabel("Valor bruto (R$)")
ax.set_title("Evolução de R$50.000 em 3 CDBs (24 meses)")
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("cdb_comparacao.png", dpi=120)
O gráfico evidencia o efeito juros compostos: a separação entre as curvas cresce de forma quase linear nos primeiros meses e acelera no final do prazo. A diferença entre 125% e 110% do CDI fica em torno de R$1.700 nos primeiros 12 meses e salta para R$3.300 nos 24 meses completos. Para integrar a um dashboard, o mesmo plot pode ser exportado como JSON e renderizado em Plotly, Chart.js ou Recharts.
Limitações da calculadora e armadilhas comuns
A calculadora cobre o caso geral, mas três pontos merecem atenção em produção. Primeiro, o cálculo assume aporte único no início. Aplicações com aportes mensais exigem capitalizar cada aporte separadamente a partir da sua data, somando os fatores. Segundo, o IR usa aproximação de dias corridos como dias_uteis × 1.4; em produção, o cálculo deve usar a diferença entre a data de aplicação e a data de resgate em dias corridos efetivos. Terceiro, o IOF dos primeiros 30 dias é ignorado, o que afeta resgates antecipados em CDBs com liquidez diária.
Para o cenário híbrido especificamente, a aproximação de 21 dias úteis por mês introduz um pequeno erro para prazos não múltiplos de mês. Em produção, a melhor abordagem é usar a data exata da aplicação e somar fatores mensais até a data de resgate, somando o fator parcial do mês corrente proporcional aos dias decorridos. O risco de crédito do emissor é tratado pelo FGC até R$250 mil por CPF por instituição, mas concentração acima desse limite exige avaliação caso a caso.
Perguntas frequentes
Como calcular a rentabilidade de um CDB pós-fixado em Python?
A rentabilidade bruta de um CDB pós-fixado é o produto dos fatores diários do CDI multiplicados pelo percentual contratado. Em Python, busca-se a série CDI via GET /macro/cdi da API bolsai, converte-se cada taxa diária em fator (1 + cdi_diario × pct), aplica-se cumprod() no período e multiplica-se pelo capital inicial. Sobre o rendimento, desconta-se o IR regressivo conforme prazo.
Qual a alíquota de IR aplicada sobre CDB?
O IR sobre CDB é regressivo conforme prazo da aplicação: 22,5% para resgates em até 180 dias, 20% entre 181 e 360 dias, 17,5% entre 361 e 720 dias e 15% acima de 720 dias. A alíquota incide somente sobre o rendimento, não sobre o capital. Para resgates nos primeiros 30 dias, há também IOF regressivo, que vai de 96% no primeiro dia a 0% no 30º dia.
CDB prefixado ou pós-fixado vale mais a pena?
Depende da trajetória esperada da Selic. Em ciclo de alta de juros, o pós-fixado captura o aumento e tende a vencer o prefixado. Em ciclo de queda, o prefixado trava a taxa atual e ganha conforme os juros caem. O CDB híbrido (IPCA + spread) é o mais defensivo: protege contra inflação e ainda paga juro real. Quem não tem visão clara da curva costuma diversificar entre os três.
O que significa 110% do CDI?
110% do CDI significa que o CDB paga ao investidor 110% da variação diária do CDI durante o período da aplicação. Se o CDI rende 1% no mês, o CDB rende 1,10%. Multiplicando a taxa diária do CDI por 1,10 e acumulando dia útil a dia útil, chega-se à rentabilidade bruta antes do IR. Percentuais acima de 100% são típicos de bancos médios e digitais que pagam mais para captar.
Como construir um comparador de CDBs em Python?
Cria-se uma função genérica que recebe valor, prazo e parâmetros do CDB (tipo, taxa) e retorna o valor líquido ao final. Para pós-fixado, usa-se a série CDI da API bolsai. Para prefixado, capitaliza-se a taxa anual em base 252 dias úteis. Para híbrido, combina-se IPCA acumulado mais juro real. O comparador roda as três funções com os mesmos inputs e ordena pelo valor líquido após IR.
Próximos passos
Construir uma calculadora CDB Python própria substitui simulador opaco de banco por código auditável que aceita qualquer combinação de emissor, taxa e prazo. As três funções deste tutorial (calc_cdb_pos, calc_cdb_pre, calc_cdb_hibrido) cobrem 100% das modalidades disponíveis no mercado brasileiro, e o comparador integra qualquer dashboard pessoal ou produto de fintech. A mesma chave API da bolsai libera, além das séries macro, dados de ações, FIIs e indicadores fundamentalistas. Para outras integrações populares, veja o guia da API gratuita, o tutorial sobre histórico de dividendos via API e o screener de ações em Python.
Leia também
Conteúdo educativo, não constitui recomendação de investimento. Taxas de CDB usadas nos exemplos são ilustrativas; valores reais variam por emissor, valor mínimo, prazo e momento. Decisões de alocação dependem de objetivo, horizonte e tolerância a risco do investidor. Cobertura do FGC limitada a R$250 mil por CPF por instituição, conforme regulamentação vigente.