-
-
Save danperrout/b27197056fa38d0d669332647ab89d7a to your computer and use it in GitHub Desktop.
| /* | |
| * @return Acesse radaropcoes.com Retorna a cotação atual de um título específico do Tesouro Direto. | |
| * API: https://radaropcoes.com/ | |
| * Fonte: https://www.tesourodireto.com.br/titulos/precos-e-taxas.htm | |
| **/ | |
| function TESOURODIRETO(bondName, argumento="r") { | |
| let srcURL = "https://api.radaropcoes.com/bonds.json"; | |
| let jsondata = UrlFetchApp.fetch(srcURL); | |
| let parsedData = JSON.parse(jsondata.getContentText()).response; | |
| for(let bond of parsedData.TrsrBdTradgList) { | |
| let currBondName = bond.TrsrBd.nm; | |
| if (currBondName.toLowerCase() === bondName.toLowerCase()) | |
| if(argumento == "r") | |
| return bond.TrsrBd.untrRedVal; | |
| else | |
| return bond.TrsrBd.untrInvstmtVal; | |
| } | |
| throw new Error("Título não encontrado."); | |
| } |
Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes.
Essa api ai de cima eu implementei com Golang usando uma lib que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo.
Consegui puxar o valor (do IPCA+ 2040) no Google Sheets usando:
=VALUE(SUBSTITUTE(REGEXREPLACE(IMPORTXML("https://taxas-tesouro.com/resgatar/tesouro-ipca+-2040/"; "(//span[contains(.,'R$')])[1]");"[^\d.,]";"");".";","))
Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes.
Essa api ai de cima eu implementei com Golang usando uma lib que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo.
Excelente, meu caro! Muito obrigado
Consegui puxar o valor (do IPCA+ 2040) no Google Sheets usando: =VALUE(SUBSTITUTE(REGEXREPLACE(IMPORTXML("https://taxas-tesouro.com/resgatar/tesouro-ipca+-2040/"; "(//span[contains(.,'R$')])[1]");"[^\d.,]";"");".";","))
Funcionou aqui para pegar o valor do título, obrigado.
Alguém saberia informar como pegar a taxa?
consegui pegar a taxa assim
=VALUE(SUBSTITUTE(REGEXREPLACE(IMPORTXML("https://taxas-tesouro.com/resgatar/tesouro-ipca+-2035/"; "(//span[contains(.,'%')])[1]");"[^\d.,]";"");".";""))/100
minha dúvida é qual a frequencia com que o site taxas-tesouro,com atualiza, pois depende desta atualização. hoje 8/set está indicando que a última atualização foi em 4/set
Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes.
Essa api ai de cima eu implementei com Golang usando uma lib que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo.
Quão difícil é isso para alguém que não tem esse conhecimento técnico todo?
Eu estou frustrado com toda esse mudança do site do Tesouro Direto pois o script que eu usava funcionou muito bem por muitos anos.
Ficarei muito grato se puder me dar orientações ou referências para que eu consiga implementar isso na minha planilha.
Sei que estou pedindo muito e entenderei caso não consiga.
Muito obrigado por toda informação compartilhada até agora.
Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes.
Essa api ai de cima eu implementei com Golang usando uma lib que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo.
Sempre uso o CURL por padrão em minhas requisições e não consegui nem por reza, mesmo simulando o browser, montando o header bonitinho... nada!
Quando tentei com o WGET funcionou.
wget --compression=auto --header='Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' --header='Accept-Language: en-US,en;q=0.9,pt-BR;q=0.8,pt;q=0.7,nl;q=0.6' --header='Priority: u=0, i' --header='Sec-Ch-Ua: "Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"' --header='Sec-Ch-Ua-Mobile: ?0' --header='Sec-Ch-Ua-Platform: "macOS"' --header='Sec-Fetch-Dest: document' --header='Sec-Fetch-Mode: navigate' --header='Sec-Fetch-Site: none' --header='Sec-Fetch-User: ?1' --header='Upgrade-Insecure-Requests: 1' --header='User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' -O rendimento.csv 'https://www.tesourodireto.com.br/documents/d/guest/rendimento-resgatar-csv?download=true'
Thiago, se quiser usar, essa é a função que criei na minha Google Sheets, ela deixa cacheado também por um tempo, pra não ficar batendo direto na api (estou usando a api do gabriel hahaha), só adicionar um script com o código abaixo, aí você chama na célula =TESOURODIRETO("nome do titulo") /* * @return Retorna a cotação atual de um título específico do Tesouro Direto. / var cache = CacheService.getScriptCache(); function TESOURODIRETO(bondName) { var tesouro = getCachedTesouro(); if (!tesouro) { Logger.log("No cached tesouro info found"); updateTesouroCache(); } tesouro = getCachedTesouro(); console.log(tesouro); for (let bond of tesouro.bonds) { console.log(bond); if (bond.name.toLowerCase() === bondName.toLowerCase()) return bond.unitary_redemption_value; } return 0; } function getCachedTesouro() { var cached = cache.get("tesouro"); if (cached) { try { var tesouro = JSON.parse(cached); return tesouro; } catch (e) { Logger.log("Error while parsing tesouro from cache"); } } } function updateTesouroCache() { Logger.log("Updating tesouro cached information"); var url = "https://tesouro.gabrielgaspar.com.br/bonds"; var response = UrlFetchApp.fetch(url); console.log(JSON.parse(response.getContentText())); var content = response.getContentText(); try { var data = JSON.parse(content); cache.put("tesouro", JSON.stringify(data),21600); } catch (e) { Logger.log("Error while parsing response from tesouro: " + content); } } https://about.me/andreluistosato?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=edit_panel&utm_content=thumb André Luis Tosato Cruz about.me/andreluistosato https://about.me/andreluistosato?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=edit_panel&utm_content=thumb
…
On Mon, Sep 8, 2025 at 12:11 PM Thiago Chaim @.> wrote: @.*** commented on this gist. ------------------------------ Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes. Essa api ai de cima eu implementei com Golang usando uma lib https://github.com/imroc/req que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo. Quão difícil é isso para alguém que não tem esse conhecimento técnico todo? Eu estou frustrado com toda esse mudança do site do Tesouro Direto pois o script que eu usava funcionou muito bem por muitos anos. Ficarei muito grato se puder me dar orientações ou referências para que eu consiga implementar isso na minha planilha. Sei que estou pedindo muito e entenderei caso não consiga. Muito obrigado por toda informação compartilhada até agora. — Reply to this email directly, view it on GitHub https://gist.github.com/danperrout/b27197056fa38d0d669332647ab89d7a#gistcomment-5751425 or unsubscribe https://github.com/notifications/unsubscribe-auth/AAF2NKNMPBNGPRMTWCG2VMT3RWMBVBFHORZGSZ3HMVZKMY3SMVQXIZNMON2WE2TFMN2F65DZOBS2WR3JON2EG33NNVSW45FGORXXA2LDOOIYFJDUPFYGLJDHNFZXJJLWMFWHKZNJGEYDIMZVHA3DIM5KMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DF . You are receiving this email because you are subscribed to this thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .
Sua solução funcionou lindamente.
Muito obrigado. Vocês são muito feras.
Thiago, se quiser usar, essa é a função que criei na minha Google Sheets, ela deixa cacheado também por um tempo, pra não ficar batendo direto na api (estou usando a api do gabriel hahaha), só adicionar um script com o código abaixo, aí você chama na célula =TESOURODIRETO("nome do titulo") /* * @return Retorna a cotação atual de um título específico do Tesouro Direto. / var cache = CacheService.getScriptCache(); function TESOURODIRETO(bondName) { var tesouro = getCachedTesouro(); if (!tesouro) { Logger.log("No cached tesouro info found"); updateTesouroCache(); } tesouro = getCachedTesouro(); console.log(tesouro); for (let bond of tesouro.bonds) { console.log(bond); if (bond.name.toLowerCase() === bondName.toLowerCase()) return bond.unitary_redemption_value; } return 0; } function getCachedTesouro() { var cached = cache.get("tesouro"); if (cached) { try { var tesouro = JSON.parse(cached); return tesouro; } catch (e) { Logger.log("Error while parsing tesouro from cache"); } } } function updateTesouroCache() { Logger.log("Updating tesouro cached information"); var url = "https://tesouro.gabrielgaspar.com.br/bonds"; var response = UrlFetchApp.fetch(url); console.log(JSON.parse(response.getContentText())); var content = response.getContentText(); try { var data = JSON.parse(content); cache.put("tesouro", JSON.stringify(data),21600); } catch (e) { Logger.log("Error while parsing response from tesouro: " + content); } } https://about.me/andreluistosato?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=edit_panel&utm_content=thumb André Luis Tosato Cruz about.me/andreluistosato https://about.me/andreluistosato?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=edit_panel&utm_content=thumb
…
On Mon, Sep 8, 2025 at 12:11 PM Thiago Chaim @.> wrote: @.*** commented on this gist. ------------------------------ Pra quem quer tentar uma implementação própria pra puxar os dados, a dica que eu posso dar é tentar achar uma forma de fazer a requisição que simule um browser. Pelos meus testes, quando você tenta fazer um fetch direto ou até mesmo um wget, eles conseguem detectar e bloquear (403), mas quando eles acham que o acesso está vindo de um browser tipo chrome eles deixa passar na maioria das vezes. Essa api ai de cima eu implementei com Golang usando uma lib https://github.com/imroc/req que consegue fazer o request impersonando o Chrome. Por enquanto tá dando certo. Quão difícil é isso para alguém que não tem esse conhecimento técnico todo? Eu estou frustrado com toda esse mudança do site do Tesouro Direto pois o script que eu usava funcionou muito bem por muitos anos. Ficarei muito grato se puder me dar orientações ou referências para que eu consiga implementar isso na minha planilha. Sei que estou pedindo muito e entenderei caso não consiga. Muito obrigado por toda informação compartilhada até agora. — Reply to this email directly, view it on GitHub https://gist.github.com/danperrout/b27197056fa38d0d669332647ab89d7a#gistcomment-5751425 or unsubscribe https://github.com/notifications/unsubscribe-auth/AAF2NKNMPBNGPRMTWCG2VMT3RWMBVBFHORZGSZ3HMVZKMY3SMVQXIZNMON2WE2TFMN2F65DZOBS2WR3JON2EG33NNVSW45FGORXXA2LDOOIYFJDUPFYGLJDHNFZXJJLWMFWHKZNJGEYDIMZVHA3DIM5KMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DF . You are receiving this email because you are subscribed to this thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .
Enormemente agradecido meu caro @andreluistosato.
Fiz alguma pequenas adaptacoes consegui ter o funcionamento normal que tinha antes.
Grato!!
Eu normalmente não costumo criar contas em fóruns, mas fiz questão de criar uma aqui apenas para agradecer ao colega @gabrielgasp pela disponibilização da API. Muito obrigado mesmo, sua ajuda foi fundamental para a resolução do problema. Fazia dias que eu vinha quebrando a cabeça tentando encontrar uma solução, e sua contribuição veio em ótima hora.
@andreluistosato agradeço por ter compartilhado seu conhecimento. Resolveu aqui. Vida longa a você.
Era o que eu precisava. Um tanto básico, peguei a API do @gabrielgasp e importei pelo Excel > Power Query
Converter a Lista para tabela, Renomear coluna, Expandir para diversas colunas.
let Source = Json.Document(Web.Contents("https://tesouro.gabrielgaspar.com.br/bonds")), bonds1 = Source[bonds], #"Converted to Table" = Table.FromList(bonds1, Splitter.SplitByNothing(), null, null, ExtraValues.Error), #"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "TD"}}), #"Expanded TD" = Table.ExpandRecordColumn(#"Renamed Columns", "TD", {"name", "investable", "annual_investment_rate", "unitary_investment_value", "minimum_investment_amount", "annual_redemption_rate", "unitary_redemption_value", "maturity"}, {"TD.name", "TD.investable", "TD.annual_investment_rate", "TD.unitary_investment_value", "TD.minimum_investment_amount", "TD.annual_redemption_rate", "TD.unitary_redemption_value", "TD.maturity"}) in #"Expanded TD"
Pessoal, funcionou perfeitamente! Muitíssimo obrigado @gabrielgasp
Fiz um pequeno ajuste pra retornar somente o Juros pós-fixado, sem o texto "Selic" ou "IPCA".
Assim:
function GET_TITULO_TESOURO(bondName) {
const srcURL = `https://tesouro.gabrielgaspar.com.br/bonds/${bondName}`;
const jsondata = UrlFetchApp.fetch(srcURL);
if (jsondata.getResponseCode() !== 200) {
throw new Error("Erro ao buscar título");
}
const parsedData = JSON.parse(jsondata.getContentText());
const rate = parsedData.bond.annual_investment_rate; // Ex: "SELIC + 0,05%"
// Extrai o primeiro número com sinal de % da string
const match = rate.match(/-?\d+,\d+%/);
return match ? match[0] : "";
}
Abraços!
Fala, pessoal!
Fiz adaptações para incluir algumas funções que eu uso na minha planilha e vou disponibilizar para vocês aqui:
txcompra(bondName) → taxa de compra (annual_investment_rate)
txvenda(bondName) → taxa de venda (annual_redemption_rate)
pucompra(bondName) → preço de compra (unitary_investment_value)
puvenda(bondName) → preço de venda (unitary_redemption_value)
function txcompra(bondName) {
var tesouro = getCachedTesouro();
if (!tesouro) updateTesouroCache();
tesouro = getCachedTesouro();
for (let bond of tesouro.bonds) {
if (bond.name.toLowerCase() === bondName.toLowerCase()) {
return extrairTaxaNumerica(bond.annual_investment_rate);
}
}
return "Título não encontrado";
}
function txvenda(bondName) {
var tesouro = getCachedTesouro();
if (!tesouro) updateTesouroCache();
tesouro = getCachedTesouro();
for (let bond of tesouro.bonds) {
if (bond.name.toLowerCase() === bondName.toLowerCase()) {
return extrairTaxaNumerica(bond.annual_redemption_rate);
}
}
return "Título não encontrado";
}
/**
* Extrai apenas a parte numérica da taxa"
*/
function extrairTaxaNumerica(taxa) {
if (!taxa) return "";
var partes = taxa.split("+");
return partes.length > 1 ? partes[1].trim() : taxa.trim();
}
function puvenda(bondName) {
var tesouro = getCachedTesouro();
if (!tesouro) {
Logger.log("No cached tesouro info found");
updateTesouroCache();
}
tesouro = getCachedTesouro();
console.log(tesouro);
for (let bond of tesouro.bonds) {
console.log(bond);
if (bond.name.toLowerCase() === bondName.toLowerCase())
return bond.unitary_redemption_value;
}
return 0;
}
function pucompra(bondName) {
var tesouro = getCachedTesouro();
if (!tesouro) {
Logger.log("No cached tesouro info found");
updateTesouroCache();
}
tesouro = getCachedTesouro();
console.log(tesouro);
for (let bond of tesouro.bonds) {
console.log(bond);
if (bond.name.toLowerCase() === bondName.toLowerCase())
return bond.unitary_investment_value;
}
return 0;
}
/**
* Função para buscar o tesouro armazenado em cache.
* @return {Object} O objeto do tesouro armazenado.
*/
function getCachedTesouro() {
var cached = cache.get("tesouro");
if (cached) {
try {
var tesouro = JSON.parse(cached);
return tesouro;
} catch (e) {
Logger.log("Error while parsing tesouro from cache");
}
}
return null;
}
/**
* Função para atualizar o cache com as informações mais recentes do Tesouro Direto.
*/
function updateTesouroCache() {
Logger.log("Updating tesouro cached information");
var url = "https://tesouro.gabrielgaspar.com.br/bonds";
var response = UrlFetchApp.fetch(url);
console.log(JSON.parse(response.getContentText()));
var content = response.getContentText();
try {
var data = JSON.parse(content);
cache.put("tesouro", JSON.stringify(data), 21600);
} catch (e) {
Logger.log("Error while parsing response from tesouro: " + content);
}
}
Criei essa versão que busca só o preço. Demora um pouco por conta do tamanho do arquivo mas funciona.
/**
* Função auxiliar para converter data DD/MM/AAAA para um formato comparável (AAAA-MM-DD).
* @param {string} dateString Data no formato DD/MM/AAAA.
* @return {string} Data no formato AAAA-MM-DD.
*/
function parseDateForComparison(dateString) {
if (!dateString) return '';
const parts = dateString.split('/');
if (parts.length === 3) {
// Retorna YYYY-MM-DD, que pode ser comparado como string
return `${parts[2]}-${parts[1]}-${parts[0]}`;
}
return '';
}
/**
* Busca o preço de um título do Tesouro.
*
* @param {string} nomeDoTitulo O nome do título a ser buscado (Ex: "Tesouro IPCA+ 2029").
* @return {number|string} O preço de investimento do título ou uma mensagem de erro.
* @customfunction
*/
function TESOURODIRETO(nomeDoTitulo) {
const URL_CSV =
"https://www.tesourotransparente.gov.br/ckan/dataset/df56aa42-484a-4a59-8184-7676580c81e3/resource/796d2059-14e9-44e3-80c9-2d9e30b405c1/download/precotaxatesourodireto.csv";
const options = {
muteHttpExceptions: true
};
const termoBuscado = nomeDoTitulo.trim().toLowerCase();
let latestMatch = null; // Armazenará {dateSortable: string, columns: array}
try {
const response = UrlFetchApp.fetch(URL_CSV, options);
const csvContent = response.getContentText();
if (response.getResponseCode() !== 200) {
return "ERRO: Não foi possível baixar o CSV. Código: " + response.getResponseCode();
}
const linhas = csvContent.split('\n');
for (let i = 1; i < linhas.length; i++) {
const linha = linhas[i];
if (linha.trim() === "") continue;
const colunas = linha.split(';');
if (colunas.length < 8) continue;
// Colunas: [0]Tipo Titulo, [1]Data Vencimento, [2]Data Base, [5]PU Compra Manha
const tipoTitulo = colunas[0].trim();
const dataVencimento = colunas[1].trim();
const dataBase = colunas[2].trim();
const anoVencimento = dataVencimento.slice(-4);
const nomeCompletoNoArquivo = `${tipoTitulo} ${anoVencimento}`.trim().toLowerCase();
if (nomeCompletoNoArquivo === termoBuscado) {
const sortableDate = parseDateForComparison(dataBase);
if (sortableDate) {
if (!latestMatch || sortableDate > latestMatch.dateSortable) {
latestMatch = {
dateSortable: sortableDate,
columns: colunas
};
}
}
}
}
if (latestMatch) {
let precoTexto = latestMatch.columns[5].trim();
// Limpa e converte o preço para número
precoTexto = precoTexto
.replace("R$", "")
.replace(/\./g, "")
.replace(",", ".")
.trim();
return parseFloat(precoTexto);
}
return `Título "${nomeDoTitulo}" não encontrado. Verifique o Tipo Título e o Ano de Vencimento.`;
} catch (e) {
return "ERRO: " + e.toString();
}
}Criei essa versão que busca só o preço. Demora um pouco por conta do tamanho do arquivo mas funciona.
/** * Função auxiliar para converter data DD/MM/AAAA para um formato comparável (AAAA-MM-DD). * @param {string} dateString Data no formato DD/MM/AAAA. * @return {string} Data no formato AAAA-MM-DD. */ function parseDateForComparison(dateString) { if (!dateString) return ''; const parts = dateString.split('/'); if (parts.length === 3) { // Retorna YYYY-MM-DD, que pode ser comparado como string return `${parts[2]}-${parts[1]}-${parts[0]}`; } return ''; } /** * Busca o preço de um título do Tesouro. * * @param {string} nomeDoTitulo O nome do título a ser buscado (Ex: "Tesouro IPCA+ 2029"). * @return {number|string} O preço de investimento do título ou uma mensagem de erro. * @customfunction */ function TESOURODIRETO(nomeDoTitulo) { const URL_CSV = "https://www.tesourotransparente.gov.br/ckan/dataset/df56aa42-484a-4a59-8184-7676580c81e3/resource/796d2059-14e9-44e3-80c9-2d9e30b405c1/download/precotaxatesourodireto.csv"; const options = { muteHttpExceptions: true }; const termoBuscado = nomeDoTitulo.trim().toLowerCase(); let latestMatch = null; // Armazenará {dateSortable: string, columns: array} try { const response = UrlFetchApp.fetch(URL_CSV, options); const csvContent = response.getContentText(); if (response.getResponseCode() !== 200) { return "ERRO: Não foi possível baixar o CSV. Código: " + response.getResponseCode(); } const linhas = csvContent.split('\n'); for (let i = 1; i < linhas.length; i++) { const linha = linhas[i]; if (linha.trim() === "") continue; const colunas = linha.split(';'); if (colunas.length < 8) continue; // Colunas: [0]Tipo Titulo, [1]Data Vencimento, [2]Data Base, [5]PU Compra Manha const tipoTitulo = colunas[0].trim(); const dataVencimento = colunas[1].trim(); const dataBase = colunas[2].trim(); const anoVencimento = dataVencimento.slice(-4); const nomeCompletoNoArquivo = `${tipoTitulo} ${anoVencimento}`.trim().toLowerCase(); if (nomeCompletoNoArquivo === termoBuscado) { const sortableDate = parseDateForComparison(dataBase); if (sortableDate) { if (!latestMatch || sortableDate > latestMatch.dateSortable) { latestMatch = { dateSortable: sortableDate, columns: colunas }; } } } } if (latestMatch) { let precoTexto = latestMatch.columns[5].trim(); // Limpa e converte o preço para número precoTexto = precoTexto .replace("R$", "") .replace(/\./g, "") .replace(",", ".") .trim(); return parseFloat(precoTexto); } return `Título "${nomeDoTitulo}" não encontrado. Verifique o Tipo Título e o Ano de Vencimento.`; } catch (e) { return "ERRO: " + e.toString(); } }
Sensacional, funcionou perfeitamente, muito obrigado @hugobrilhante! e creio que sua solução vai ser duradoura. E pra quem quiser buscar outros valores é só trocar o 5 no "let precoTexto = latestMatch.columns[5].trim();" que voce vai ter outros resultados, o 5 por padrão é o valor de compra, como está comentado " [0]Tipo Titulo, [1]Data Vencimento, [2]Data Base, [5]PU Compra Manha" e acrescento que o 6 é o valor de venda. Não testei, mas creio que 3 e 4 são as taxas de compra e venda, respectivamente, vale o teste para quem quiser.
Ajustei uma API que eu uso para consumir os CSVs como fonte de dados. Estou deixando ela pública para quem tiver interesse.
Observações
investablefoi adicionado por mim para indicar se o título ainda está disponível para investimento atualmente na plataforma do Tesouro.updated_atrepresenta a última vez que a api conseguiu baixar os CSVs para atualizar as informações. Isso não garante que os CSVs na fonte estejam atualizados, pois isso foge do meu controle.Exemplos de uso