O CDI é o benchmark de quase tudo em renda fixa brasileira: CDB, LCI/LCA, fundos DI, debêntures pós-fixadas. Mas a série bruta do BCB vem em % ao dia, em uma escala que confunde quem espera "% ao ano". Este post mostra como acessar o histórico completo via API e anualizar corretamente com 252 dias úteis.
Em 2026, com Selic a 14,5%, o CDI fica em torno de 0,054267% ao dia — um número aparentemente minúsculo, mas que anualizado dá ~14,4% a.a. Essa diferença numérica é uma das fontes mais comuns de erro em calculadoras caseiras de rendimento.
Aqui você aprende a acessar a série completa via brapi.dev, anualizar com a fórmula correta, comparar com a Selic e construir um simulador de CDB 100% CDI sem cair em armadilhas.
CDI: o que é e por que importa
CDI (Certificado de Depósito Interbancário) é a taxa praticada nos empréstimos diários entre bancos. Ela existe porque o regulador (BCB) proíbe bancos de fechar o dia com caixa negativo — quem está com sobra empresta para quem está em falta, e a taxa média dessas operações é o CDI.
Por que ele é o benchmark da renda fixa? Porque é a taxa de risco quase zero do mercado financeiro privado — o equivalente da Selic Meta no universo bancário. Quase todo produto pós-fixado é precificado como X% do CDI (90%, 100%, 110%, etc.).
| Comparativo | Selic Meta | CDI |
|---|---|---|
| Quem define | COPOM (BCB) | Operações entre bancos (B3 calcula) |
| Frequência | A cada 45 dias (reuniões COPOM) | Diária |
| Unidade no BCB | % ao ano | % ao dia |
| Diferença típica | — | Selic - 0,10 p.p. |
Por que o CDI é ~0,10 p.p. abaixo da Selic
A Selic Meta é a taxa-alvo dos títulos públicos federais (risco soberano, considerado o menor possível no Brasil). O CDI envolve operações entre bancos (risco bancário, ligeiramente maior). Esse pequeno spread (~0,10 p.p.) é o prêmio de risco bancário sobre o soberano.
A série cdi no /api/v2/macro
A API da brapi.dev expõe o CDI como uma série de primeira classe (slug
cdi), com dados desde 1986-03-06:
# Valor mais recente
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://brapi.dev/api/v2/macro/latest?symbols=cdi"Resposta:
{
"results": [
{
"series": {
"slug": "cdi",
"name": "CDI",
"description": "Certificado de Depósito Interbancário...",
"unit": "percentPerDay",
"frequency": "daily",
"category": "interestRate",
"startDate": "1986-03-06"
},
"latest": { "date": "2026-04-30", "value": 0.054267 }
}
],
"requestedAt": "2026-04-30T12:00:00.000Z",
"took": 12
}A unit é percentPerDay — o número 0.054267 significa "0,054267% por
dia útil", não 0,054267% ao ano.
A regra de ouro: 252 dias úteis
A anualização correta do CDI usa 252 dias úteis, que é a convenção brasileira para taxas pós-fixadas.
cdi_anual = (1 + cdi_diario / 100) ** 252 - 1Em código:
function anualizarCDI(cdiDiarioPct: number): number {
// Entrada: 0.054267 (% ao dia)
// Saída: 14.40 (% ao ano)
return (Math.pow(1 + cdiDiarioPct / 100, 252) - 1) * 100;
}
anualizarCDI(0.054267); // ~14.40Não use 365 dias
Anualizar com 365 dias dá um número errado (~21%). Bancos, B3 e a CVM usam 252 — a quantidade média de dias úteis no ano. Isso é convenção: na prática, o CDI só é divulgado em dias úteis (sem fim de semana ou feriado), então 252 é o número que faz a multiplicação composta dar certo.
Por que 252 e não 250 ou 254?
Porque é a média que torna a fórmula consistente com como os produtos são calculados. CDBs, LCIs, fundos DI: todos usam 252. Sua planilha precisa seguir o mesmo padrão.
Histórico completo do CDI
Para baixar todo o histórico desde 1986:
curl -H "Authorization: Bearer SEU_TOKEN" \
"https://brapi.dev/api/v2/macro?symbols=cdi&startDate=1986-03-06&endDate=2026-04-30&sortOrder=asc&limit=10000"Você recebe ~10.000 observações diárias (uma por dia útil). Para gráfico de longo prazo, anualize cada ponto:
TypeScript
type Observation = { date: string; value: number };
async function fetchCdiHistory(years: number): Promise<Observation[]> {
const today = new Date().toISOString().slice(0, 10);
const start = new Date();
start.setFullYear(start.getFullYear() - years);
const startDate = start.toISOString().slice(0, 10);
const url = new URL('https://brapi.dev/api/v2/macro');
url.searchParams.set('symbols', 'cdi');
url.searchParams.set('startDate', startDate);
url.searchParams.set('endDate', today);
url.searchParams.set('sortOrder', 'asc');
url.searchParams.set('limit', '10000');
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.BRAPI_TOKEN}` },
});
const { results } = await res.json();
return results[0]?.observations ?? [];
}
const series = await fetchCdiHistory(10);
const cdiAnualizado = series.map((o) => ({
date: o.date,
cdiDiario: o.value,
cdiAnual: (Math.pow(1 + o.value / 100, 252) - 1) * 100,
}));Python
import os
from datetime import date, timedelta
import requests
def cdi_history(years: int) -> list[dict]:
end = date.today().isoformat()
start = (date.today() - timedelta(days=365 * years)).isoformat()
response = requests.get(
'https://brapi.dev/api/v2/macro',
params={
'symbols': 'cdi',
'startDate': start,
'endDate': end,
'sortOrder': 'asc',
'limit': 10000,
},
headers={'Authorization': f"Bearer {os.environ['BRAPI_TOKEN']}"},
)
response.raise_for_status()
obs = response.json()['results'][0]['observations']
return [
{
'date': o['date'],
'cdi_diario': o['value'],
'cdi_anual': ((1 + o['value'] / 100) ** 252 - 1) * 100,
}
for o in obs
]Acumulação no período
Para calcular quanto rendeu R$ 1.000 a 100% do CDI no último ano, não basta pegar o CDI atual e multiplicar — é preciso compor diariamente:
async function rendimento100CDI(capital: number, days: number) {
const today = new Date().toISOString().slice(0, 10);
const from = new Date();
from.setDate(from.getDate() - days);
const startDate = from.toISOString().slice(0, 10);
const res = await fetch(
`https://brapi.dev/api/v2/macro?symbols=cdi&startDate=${startDate}&endDate=${today}&sortOrder=asc&limit=10000`,
{ headers: { Authorization: `Bearer ${process.env.BRAPI_TOKEN}` } },
);
const { results } = await res.json();
const obs = results[0]?.observations ?? [];
const fatorAcumulado = obs.reduce(
(acc, o) => acc * (1 + o.value / 100),
1,
);
return {
capitalInicial: capital,
capitalFinal: capital * fatorAcumulado,
rendimentoBruto: capital * (fatorAcumulado - 1),
pctNoPeriodo: (fatorAcumulado - 1) * 100,
diasUteis: obs.length,
};
}
await rendimento100CDI(1000, 365);
// { capitalInicial: 1000, capitalFinal: 1144, rendimentoBruto: 144, pctNoPeriodo: 14.4, diasUteis: 252 }Para CDB 110% CDI, ajuste o fator diário:
const pctCdi = 1.10;
const fatorAcumulado = obs.reduce(
(acc, o) => acc * (1 + (o.value * pctCdi) / 100),
1,
);Comparativo: Selic vs. CDI
async function compararSelicVsCdi() {
const res = await fetch(
'https://brapi.dev/api/v2/macro/latest?symbols=selic,cdi',
{ headers: { Authorization: `Bearer ${process.env.BRAPI_TOKEN}` } },
);
const { results } = await res.json();
const selic = results.find((r) => r.series.slug === 'selic')?.latest.value;
const cdiDiario = results.find((r) => r.series.slug === 'cdi')?.latest.value;
const cdiAnual = (Math.pow(1 + cdiDiario / 100, 252) - 1) * 100;
return {
selicMeta: selic, // Ex: 14.5
cdiDiario, // Ex: 0.054267
cdiAnualizado: cdiAnual, // Ex: 14.40
spreadCdiSelic: cdiAnual - selic, // Ex: -0.10
};
}Esse "spread" é o prêmio de risco bancário sobre o soberano que mencionamos no início. Historicamente fica em -0,10 p.p., mas em períodos de estresse (2020 COVID, 2022 fim de ciclo) pode variar.
Aplicações práticas
Calculadora "quanto rende R$ X em Y dias"
Use a função rendimento100CDI acima. É o que toda fintech precisa para
mostrar simulações na tela do CDB.
Backtesting de fundos DI
Compare o desempenho real do fundo (cota líquida) com o CDI acumulado no mesmo período. Se o fundo entregou 95% do CDI, há taxa de administração ou ineficiência consumindo o resto.
Validação de extrato
Multiplique o saldo inicial pelo fator CDI acumulado no período × o percentual contratado (100%, 110%, etc.) e compare com o saldo final do extrato. Se houver discrepância maior que 0,01%, há problema.
Estimativa de rendimento líquido (CDB)
function rendimentoLiquidoCDB(
capital: number,
pctCdi: number, // ex: 1.10 para 110% CDI
diasUteis: number,
cdiAnualEstimado: number, // ex: 14.40
) {
const cdiDiarioEstimado = Math.pow(1 + cdiAnualEstimado / 100, 1 / 252) - 1;
const fator = Math.pow(1 + cdiDiarioEstimado * pctCdi, diasUteis);
const rendimentoBruto = capital * (fator - 1);
// IR regressivo
const dias = (diasUteis * 365) / 252;
const ir =
dias <= 180 ? 0.225 :
dias <= 360 ? 0.20 :
dias <= 720 ? 0.175 : 0.15;
return {
rendimentoBruto,
ir: rendimentoBruto * ir,
rendimentoLiquido: rendimentoBruto * (1 - ir),
aliquotaIR: ir * 100,
};
}Erros comuns
- Anualizar com 365 dias. Use 252 — convenção brasileira para taxas pós-fixadas.
- Confundir CDI Over com CDI taxa. A série
cdida brapi é a CDI taxa (a oficial, divulgada pela B3). Em alguns sistemas você verá "CDI Over", que é a operação overnight em si — referencia o mesmo conceito. - Comparar CDI com IPCA mensal. Não dá: CDI é diário-anualizado, IPCA é mensal. Para compor real vs. nominal, anualize ambos primeiro.
- Esquecer dias úteis. Sábados, domingos e feriados não têm CDI. Sua série terá ~252 pontos por ano, não 365.
- Aplicar IR sobre o capital inicial. O IR só incide sobre o rendimento, nunca sobre o principal.
Endpoints relacionados
- 📊 Documentação completa do
/api/v2/macro - 🧮 Como calcular juro real (Selic - IPCA)
- 📚 O que é CDI: Guia para iniciantes
- 🇧🇷 API de Macroeconomia: 15 indicadores BCB
CDI é o benchmark mais usado em calculadoras de renda fixa brasileira.
Acertar a anualização (252 dias) e a composição diária é a diferença entre
um simulador profissional e um amador. Crie sua conta em
brapi.dev, use a série cdi e pare de chutar.
