CommunityPesquisa e Análise de Dadosgithub.com

AdhishaInd/extração-de-demonstrações-financeiras

Extraia valores de demonstrações de resultados, balanços patrimoniais e fluxos de caixa de PDFs de relatórios financeiros de empresas (relatórios anuais, trimestrais e digitalizados) para um banco de dados relacional, com verificações aritméticas que garantem que apenas números confiáveis sejam carregados.

O que é extração-de-demonstrações-financeiras?

Esta skill automatiza a extração de dados financeiros de relatórios corporativos em PDF (como demonstrações de resultados, balanços patrimoniais e fluxos de caixa) diretamente para um banco de dados relacional. Desenvolvida e comprovada com mais de 2.700 relatórios da Bolsa de Valores de Colombo (Sri Lanka), totalizando 720.000 valores com 99,4% de sucesso de carregamento, ela se destaca por sua abordagem robusta de validação. O princípio central é que um valor só é carregado se sua coluna passar por verificações aritméticas rigorosas (por exemplo, ativos = passivos + patrimônio líquido; lucro antes dos impostos - impostos = lucro líquido). Nenhum ajuste é feito para forçar a validação; o sistema aceita apenas diferenças de arredondamento dentro de limites predefinidos (2 unidades para dois termos, 3 para três, 5 para mais). Isso garante que erros de leitura ou impressão sejam detectados e que apenas dados confiáveis entrem no banco de dados. A skill suporta parsing automático para a maioria dos relatórios, OCR para digitalizações e transcrição por imagem para casos complexos, com um fluxo de trabalho em lote que inclui triagem para identificar exatamente por que cada demonstração falhou e subagentes para processar revisões em paralelo. É ideal para extrair, carregar, recuperar ou auditar demonstrações financeiras de PDFs, construir ou expandir bancos de dados financeiros a partir de arquivos de bolsas de valores e diagnosticar por que um relatório não foi carregado.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/AdhishaInd/agent-skills/tree/HEAD/skills/financial-statement-extraction

Installed? Explore more Pesquisa e Análise de Dados skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Financial statement extraction

Turns report PDFs into checked facts: financial_fact(document, period, label, scope, value, unit, audit status). Built and proven on two years of Colombo Stock Exchange filings (2,707 reports, 720k figures, 99.4% fully loaded). The method is what makes it fast: an automatic parser does most reports, arithmetic checks decide what is trusted, a triage step says exactly why each remaining statement failed, and only those statements are read from page images, in batches, by subagents. Every change reaches the published database only through a staged load and an audit.

The one rule everything rests on

A figure loads only if its column passes arithmetic checks (assets = equity + liabilities; profit before tax - tax = profit; owners + NCI = profit; cash flow sections sum to the net change; opening + change = closing). Nothing is adjusted to make a check pass. Checks allow only printed rounding (a few units of the last printed digit: 2 for two terms, 3 for three, 5 for more), so a total 1-2 units off its parts passes and more is a reading or print error. This is why a parser, an OCR engine, a vision transcription and a human can all feed the same database: the checks, not the source, decide. When a check fails, either the reading is wrong (re-read) or the print is wrong (record why, leave it out).

Corollaries that matter in practice:

  • Labels stay exactly as printed and map to standard line items only through exact aliases (label_alias), never fuzzy matching. A misprinted label makes a statement unloadable rather than silently wrong.
  • A total printed with no label may get a bracketed label ([Total assets]) because its position defines it.
  • "UNCHECKED" (no check possible) is not "FAIL". It usually means a layout the checker does not know yet - fix the checker once, and every report with that layout loads (see references/checks.md).

Where things are

  • scripts/pipeline/ - the pipeline: parse_report.py (PDF -> JSON tables), segment.py, columns.py, tokens.py, checks.py, ocr_words.py (OCR as fake text layer), load_facts.py (JSON -> DB, only passing columns), vision_tables.py (image transcriptions -> JSON tables), extract_all.py, normalize.py. Map, data shapes and how to adapt it to another market: references/pipeline.md.
  • scripts/triage.py, scripts/make_batches.py, scripts/render.py, scripts/stage_publish.py - the helpers for the steps below.
  • assets/schema.sql (database), assets/dictionary.sql (252 standard line items + 471 exact label aliases), assets/worker_brief.md (brief for transcription workers), assets/examples/ (transcription files).
  • The project directory: where the database, PDFs and outputs live. The user names it in CLAUDE.md / AGENTS.md (e.g. "Financials project: ~/stocks/cse_financials"); ask if it is not there. Layout: db/<name>.db, reports/<SYMBOL>/<doc>.pdf, parser output extracted_final/, published source extracted_final_v/, transcriptions reviewed/vision/, notes docs/. If the project has its own pipeline/, treat it as the current code (this skill's copy may be older).

Always run Python with -I (isolated) and CSE_OCR=0 unless OCR is wanted (the CSE_ prefix is historical). A report's PDF: select local_path from report_document where document_id=? (relative to the project dir), then python -I scripts/render.py <pdf> <pages> <out_dir> --text to dump the text layer and render the pages.

Workflow

1. Scope and download

Pick the period range; take period ends from report titles (exchange filing dates are unreliable). Fill report_document rows (one per report: company, category ANNUAL/INTERIM, title, period end, source URL), then download in parallel and resumably. The exchange-specific part (API, URLs, quirks) belongs in a companion skill - cse-financials for Colombo. Keep each block of years as its own run of these steps. Before a new market or new years, read references/traps.md: it lists the data traps that cost the most time.

2. Parse everything with one parser version

python -I scripts/pipeline/extract_all.py <db> <out_dir> --workers N with CSE_OCR=0 (about 9 min for 2,700 reports), then a separate OCR pass for scans (GPU if available; see traps). After any parser change re-parse all reports and compare per report - partial re-parses make the database unreproducible.

3. Load and read the status

load_facts.py (through stage_publish.py, step 6) gives each report EXTRACTED (IS and BS loaded), PARTIAL or FAILED. Expect roughly 80% EXTRACTED from the parser alone.

4. Triage what is left - before looking at any page

python -I scripts/triage.py <db> <extracted_dir> triage.json --pdf-hints
python -I scripts/make_batches.py triage.json batches/ --target=12

Triage gives each missing statement's reason (not_found, UNCHECKED, FAIL, no_columns, no_months, unit_unproven, pass_refused...) and where to look. Read the counts: a big cluster with one reason (e.g. 100 UNCHECKED) often means a checker gap or a loader rule - fixing code beats transcribing hundreds of pages. Also check whether FAILED reports are statements at all: notices, shareholder lists and errata are common and need only a recorded reason.

5. Transcribe from images, in batches

Each worker gets one batch file and assets/worker_brief.md (fill in the paths). It finds the statement page, reads it (text layer first, image for layout and anything doubtful), writes reviewed/vision/<doc>.txt, runs vision_tables.py on its docs until every column PASSes, and writes bNN.result.json. The worker needs a model that can read images. Format and rules: references/vision-format.md. Running workers in parallel, usage limits, resuming and reviewing results: references/orchestration.md. Without subagents, work through the batches one after another with the same brief.

While batches run, read each result summary as it arrives:

  • Recurring "UNCHECKED because the checker does not recognise X" -> extend checks.py (references/checks.md), retest the affected files with vision_tables.py, append the rule to the brief so later batches know. Tables already written then pass without re-transcription.
  • Judgement calls (audit status, restated columns, odd period lengths, supplied labels) -> check they follow the brief; correct centrally (e.g. a sed over COLS lines) rather than re-running a worker.

6. Stage, audit, publish

python -I scripts/stage_publish.py --project <dir>            # stage + audit only
python -I scripts/stage_publish.py --project <dir> --publish  # after reading the audit

Publishing is refused if the audit shows reports leaving EXTRACTED, reports becoming empty, integrity/FK errors, new unit outliers, or facts lost/changed in reports that have no transcription file (that means a code change touched data nobody re-read). Gains outside vision reports are normal (a resolved conflict frees another report's column) but look at each one. Publish in stages (finished batches first) so work survives interruptions; then run the project's tests if it has any.

7. Close out every statement

The goal is: every missing statement is either loaded or has a stated reason. Build the per-statement outcome table (loaded / not loaded + reason from the MISSING lines and result files). For each not-loaded statement, check whether the same figures are already loaded from another report (next year's comparatives, the matching interim) - usually they are, and that turns a "gap" into "covered". Record outcomes in the project docs.

Token and time economy

  • Triage first; never send a worker to "find what is wrong" without the reason and page hints.
  • Text layer before image: a clean text layer confirms digits for free; the image settles layout. Render 1500 px; crop (render.py --clip) instead of rendering whole pages larger. Scans with junk text layers ("9,O4349L") need images.
  • Batch by company: one layout, many quarters. ~10 reports or ~12 cost units per batch, about 6 workers at once.
  • Workers write the full table even when a check stays UNCHECKED, plus a MISSING line: if the checker is extended later, the table loads without another read.
  • Fix systematic issues in code (checker, loader) once, centrally; re-run vision_tables.py (seconds) instead of re-reading pages.
  • The orchestrator does not view page images except to settle a dispute; it reads summaries, runs checks and audits.
  • Keep worker summaries to 3-6 lines; details belong in file comments.

Definition of done

Per report: EXTRACTED, or PARTIAL/FAILED with a reason per missing statement that names the printed evidence (e.g. "printed total 3,115,995,977 vs equity + liabilities 3,115,995,968"), or "covered by report N". Published only through stage_publish.py, with a backup, audit clean (or every flag explained), tests passing, and the outcome table plus a dated note in the project docs.

Habilidades Relacionadas