Pular para conteúdo

rtn-fetcher — Resultado do Tesouro Nacional (RTN) Brasileiro

rtn-fetcher é um pacote Python que baixa, extrai e normaliza o Resultado do Tesouro Nacional (RTN) — relatório mensal de resultados fiscais federais do Brasil. Transforma as pastas de trabalho Excel com múltiplas abas do Tesouro em tabelas de formato longo limpo com expansão hierárquica de contas, prontas para análise ou carregamento em warehouse.

Pegadinhas da fonte oficial

  • Headers não estão em linha fixa. Cada uma das 24+ abas tem cabeçalho em linhas diferentes, frequentemente com células mescladas. O leitor detecta dinamicamente; não tente header=0.
  • Hierarquia de contas é implícita. Código 1.2.3 exige a existência de 1 e 1.2 — o rtn-fetcher expande em uma tabela de dimensão separada.
  • Unidades mudam por aba. Abas 1.x em milhões de R$; abas 2.x-A em fração do PIB; aba 1.2-B deflacionada por IPCA. Confira unit antes de somar.
  • Períodos misturados. Mensal, trimestral, anual — em colunas diferentes na mesma planilha. O leitor separa em year/month ou year/quarter.
  • Abas 3.1 e 3.2 não são suportadas. Layout comparativo com headers multi-nível — ainda não normalizado.

O Que É

O Resultado do Tesouro Nacional contém dados fiscais consolidados do Governo Federal Brasileiro: receitas, despesas e resultado primário, em valores correntes e constantes, mensais, trimestrais e anuais, também como percentuais do PIB. O Tesouro publica isso como uma extensa pasta de trabalho Excel com 24+ abas, cada uma com seu próprio layout de header e hierarquia de contas. rtn-fetcher automatiza o pipeline de fetch-and-normalize para você ir da URL oficial a uma tabela de formato longo arrumada em poucas linhas de Python — ou um comando CLI.

Source: Tesouro Nacional — RTN

O Desafio

  • Excel com múltiplas abas com headers variáveis e células mescladas em 24 abas suportadas — linhas de header não estão em posições fixas, requerendo detecção dinâmica.
  • Hierarquia de contas em formato amplo: códigos como 1.2.3 carregam níveis pai implícitos (1, 1.2) que precisam ser expandidos em uma tabela de dimensão separada.
  • Unidades e períodos mistos: valores aparecem como milhões de R\(, R\) constantes, ou % do PIB; períodos misturam mensal, trimestral e anual — cada aba precisa da normalização correta.

Recursos

  • Download automático da pasta de trabalho RTN mais recente com deduplicação baseada em timestamp
  • Lê 24 abas suportadas cobrindo mensal / trimestral / anual; corrente / constante; % do PIB
  • Saída em formato longo com expansão hierárquica de contas
  • Normalização de unidades (milhões de R$ → reais; % do PIB preservado como fração)
  • Período dividido em colunas year / month ou year / quarter
  • Hierarquia de contas retornada como tabela de dimensão separada
  • CLI para fetch e exportação Excel/SQLite

Abas Suportadas

Abas Descrição Período Unidade
1.1, 1.2, 1.3, 1.4, 1.5, 1.6 Série mensal, valores correntes Mensal R$
1.1-A, 1.2-A, 1.3-A, 1.4-A, 1.5-A Série mensal, valores constantes Mensal R$
1.2-B Série mensal, rolling 12-meses, deflacionado pelo IPCA Mensal R$
2.1, 2.2, 2.3, 2.4, 2.5 Série anual, valores correntes Anual R$
2.1-A, 2.2-A, 2.3-A, 2.4-A, 2.5-A Série anual, % do PIB Anual Fração do PIB
4.1, 4.2 Série trimestral, Orçamento do Governo Central Trimestral R$

As abas 3.1 e 3.2 usam um layout comparativo de publicação atual com headers multi-nível e ainda não são normalizadas pelo leitor de série histórica.

Instalação

Requer Python 3.12+.

pip install git+https://github.com/Quantilica/rtn-fetcher.git
# ou
uv add "git+https://github.com/Quantilica/rtn-fetcher.git"

Dependências: httpx, openpyxl, beautifulsoup4.

Interface de Linha de Comando

O pacote instala um comando rtn-fetcher com subcomandos fetch e export:

rtn-fetcher --help

# Operações de fetch
rtn-fetcher fetch metadata          # Construir metadata.json da página de publicações
rtn-fetcher fetch download          # Baixar arquivos listados em metadata.json
rtn-fetcher fetch latest            # Baixar a pasta de trabalho RTN mais recente

# Operações de export
rtn-fetcher export excel            # Exportar para uma pasta de trabalho Excel formatada
rtn-fetcher export sqlite           # Exportar para um banco de dados SQLite

Opções de Buscar

rtn-fetcher fetch metadata --dest data --force
rtn-fetcher fetch download --metadata data/metadata.json --concurrency 8
rtn-fetcher fetch latest   --dest data

Opções de Export

rtn-fetcher export excel  --data-dir data --output rtn_data.xlsx
rtn-fetcher export sqlite --data-dir data --output rtn_data.db

Ambos os comandos export baixam a pasta de trabalho mais recente e escrevem todas as abas suportadas junto com a dimensão de hierarquia de contas.

API Python

Baixar

from pathlib import Path
from rtn_fetcher import download_latest_file

filepath = download_latest_file(Path("data"))
print(f"Baixado: {filepath}")

download_latest_file retorna o Path do arquivo baixado, ou None se uma cópia atual já existe no destino.

Ler uma aba única

from pathlib import Path
from rtn_fetcher import read_sheet, write_table_to_csv

filepath = Path("data/rtn_202412301200.xlsx")
data, accounts = read_sheet(filepath, "1.2")

print(f"Dados:     {data.nrows} linhas x {data.ncols} colunas")
print(f"Contas:    {accounts.nrows} linhas x {accounts.ncols} colunas")

write_table_to_csv(data,     Path("output/rtn_1_2_data.csv"))
write_table_to_csv(accounts, Path("output/rtn_1_2_accounts.csv"))

read_sheet(filepath, sheet_name) retorna uma tupla (data, accounts) de instâncias Tbl — a tabela de fatos em formato longo e a dimensão de hierarquia de contas.

Gravar Parquet com proveniência

Para saída tipada e com manifesto embutido no header, use write_table_to_parquet. Ele aplica o DataContract da planilha (via build_contract) e escreve via quantilica-io:

from pathlib import Path
from quantilica_core.manifests import DownloadManifest
from rtn_fetcher import read_sheet, write_table_to_parquet

filepath = Path("data/rtn_202412301200.xlsx")
data, _ = read_sheet(filepath, "2.1")

manifest = DownloadManifest.from_file(
    source_id="tesouro-nacional",
    dataset_id="rtn",
    url="http://sisweb.tesouro.gov.br/apex/cosis/thot/link/rtn/serie-historica",
    file_path=filepath,
    producer="rtn-fetcher",
)
write_table_to_parquet(data, Path("output/rtn_2_1.parquet"), "2.1",
                      manifest=manifest)

O contrato é derivado de SHEET_CONFIGS[sheet]: year para anuais, year/month para mensais, year/quarter para trimestrais. Veja Data Contracts.

Ler cada aba suportada

from rtn_fetcher import read_all_sheets

results = read_all_sheets(filepath)

for sheet_name, (data, accounts) in results.items():
    print(f"{sheet_name}: {data.nrows} data rows")

Publication metadata

from rtn_fetcher import fetch_publications_metadata

publications = fetch_publications_metadata()
print(publications[0])

Estrutura de Dados

Tabela de fatos (formato longo)

Coluna Tipo Descrição
year int Ano de referência
month int Mês de referência (abas mensais)
quarter int Trimestre de referência (abas trimestrais)
account str Código hierárquico da conta
value int/float Reais para abas de moeda; fração para % do PIB

Hierarquia de contas (dimensão)

Coluna Tipo Descrição
account_code str Código hierárquico (ex: 1.2.3)
account_name str Nome completo da conta
account_level int Profundidade da hierarquia
P_1, P_2, ... str Nome em cada nível da hierarquia

Exemplo

# Linhas de fatos
year  month  account  value
2024  1      1.1      1500000000
2024  1      1.2      2300000000
2024  2      1.1      1600000000

# Linhas de hierarquia
account_code  account_name             account_level  P_1       P_2
1.1           1.1 Receitas Correntes   2              Receitas  Receitas Correntes
1.2           1.2 Receitas de Capital  2              Receitas  Receitas de Capital

A Classe Tbl

O rtn-fetcher vem com a Tbl, uma pequena tabela orientada a colunas — os dados são armazenados como uma lista de colunas em vez de linhas. Não há dependência de Polars ou Pandas; a Tbl é a única estrutura de dados que você precisa aprender.

from rtn_fetcher import Tbl

t = Tbl([
    ["name", "Alice", "Bob"],
    ["age",  25,      30   ],
])

t["name"]                       # ["name", "Alice", "Bob"]
t.select("name")                # subconjunto
t.assign(city=["SP", "RJ"])     # adicionar/sobrescrever uma coluna
t.melt(id_cols=["name"])        # wide -> long
t.rename(name="full_name")      # renomear colunas

for row in t.iter_rows():
    print(row)

Principais métodos: select, assign, melt, transpose, insert, drop_rows, drop_cols, rename, iter_rows, get_header. Atributos: data, nrows, ncols. Todas as transformações retornam novas tabelas — as operações não são mutáveis.

Saiba Mais