Skip to content

Instantly share code, notes, and snippets.

@tioback
Created August 21, 2025 02:08
Show Gist options
  • Save tioback/c582223cbb4921bb3d077519f07551d1 to your computer and use it in GitHub Desktop.
Save tioback/c582223cbb4921bb3d077519f07551d1 to your computer and use it in GitHub Desktop.
Buscar dados de títulos do tesouro
const URL_INVESTIR = "https://www.tesourodireto.com.br/documents/d/guest/rendimento-investir-csv?download=true";
const URL_RESGATAR = "https://www.tesourodireto.com.br/documents/d/guest/rendimento-resgatar-csv?download=true";
/**
* Busca um arquivo CSV direto do site do www.tesourodireto.com.br e converte pra um mapa usando nome do título
* convertido pra lower case como chave e as demais propriedades (nome, taxa, pu, vencimento) como valor.
*/
function getData(urlCsv = URL_RESGATAR) {
const resp = UrlFetchApp.fetch(urlCsv, { muteHttpExceptions: true, followRedirects: true });
if (resp.getResponseCode() !== 200) {
throw new Error("HTTP " + resp.getResponseCode() + " ao acessar CSV: " + urlCsv);
}
const text = resp.getContentText("UTF-8");
const rows = Utilities.parseCsv(text, ";");
if (!rows || rows.length < 2) {
throw new Error("CSV vazio ou sem dados.");
}
// descarta linha de títulos da resposta original
return new Map(rows.slice(1).map(row => [row[0].trim().toLowerCase(), {
nome: row[0].trim(),
taxa: row[1],
pu: row[2],
vencimento: row[3]
}]));
}
/**
* Retorna um array com os dados dos títulos do tesouro solicitados, diretamente do arquivo CSV disponibilizado
* no site do www.tesourodireto.com.br.
*
* Faz um distinct nos valores para não devolver dados repetidos.
*
* Modo de uso:
*
* =tesouroDiretoResgate("Tesouro IPCA+ 2029")
* =tesouroDiretoResgate(A3)
* =tesouroDiretoResgate(A3:A99)
* =tesouroDiretoResgate(A3:C10)
*
* @param titulos lista de títulos pra buscar os dados de resgate.
* @param incluirCabecalho (opcional) (padrão = true) retorna o cabeçalho dos dados como o primeiro elemento do
* array de resposta.
*/
function tesouroDiretoResgate(titulos = [], incluirCabecalho = true) {
const titulosDistintos = new Set();
if (!Array.isArray(titulos)) {
titulosDistintos.add(titulo);
} else {
titulos.forEach(titulo => Array.isArray(titulo)
? titulo.forEach(subtitulo => titulosDistintos.add(subtitulo))
: titulosDistintos.add(titulo)
);
}
if (titulos.length === 0) {
throw new Error("Sem dados para pesquisar.");
}
if (Array.isArray(titulos[0])) {
titulos = titulos[0];
}
const data = getData();
const result = [];
if (incluirCabecalho) {
result.push(["Título", "Taxa", "PU", "Vencimento"]);
};
const erros = [];
titulosDistintos.forEach(nomeTitulo => {
const chave = nomeTitulo.toLowerCase();
const row = data.get(chave);
if (!row) {
erros.push(new Error("Título não encontrado: " + nomeTitulo));
return;
}
result.push([
row.nome,
convertePercentualPraDecimal(row.taxa),
Number.parseFloat(row.pu.substring(3).replaceAll(".", "").replaceAll(",", ".")),
row.vencimento
]);
});
if (erros.length > 0 && result.length === incluirCabecalho ? 1 : 0) {
throw erros;
}
return result;
}
function convertePercentualPraDecimal(valor) {
const taxa = valor.replace(/\D*?(-?\d+(\.\d{3})*(,\d+)%?)/, "$1").replaceAll(".", "").replaceAll(",", ".");
if (taxa.indexOf("%") >= 0) {
return Number.parseFloat(taxa.replaceAll("%", "")) / 100;
} else {
return Number.parseFloat(taxa);
}
}
function testarResgateUm() {
tesouroDiretoResgate("Tesouro IPCA+ 2035");
}
function testarResgateLista() {
tesouroDiretoResgate([
["Tesouro Selic 2026"],
["Tesouro IPCA+ 2029"],
["Tesouro IPCA+ 2045"],
["Tesouro IPCA+ com Juros Semestrais 2035"]
]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment