Skip to content

Add ANBIMA Títulos Públicos (TPF) secondary-market source#22

Merged
robertoecf merged 4 commits into
mainfrom
feat/anbima-tpf
Jun 17, 2026
Merged

Add ANBIMA Títulos Públicos (TPF) secondary-market source#22
robertoecf merged 4 commits into
mainfrom
feat/anbima-tpf

Conversation

@robertoecf

@robertoecf robertoecf commented Jun 16, 2026

Copy link
Copy Markdown
Owner

What

Adds get_tpf() — daily secondary-market reference rates for outstanding federal government bonds (LTN, LFT, NTN-B, NTN-C, NTN-F) from ANBIMA's public file www.anbima.com.br/informacoes/merc-sec/arqs/ms{ymd}.txt. No API key, no auth — same @-separated layout as the existing debêntures feed.

Wired through the full stack mirroring get_debentures:

  • TPFQuote model + get_tpf() in sources/anbima/indices.py (compact YYYYMMDD date handling, BR-decimal rates incl. negatives)
  • GET /anbima/tpf — filter by titulo (bond type), limit
  • findata anbima tpf CLI command
  • parse + endpoint tests, CHANGELOG entry

Why

Closes the one clean key-free gap among the data.anbima.com.br datasets. The portal's fund datasets (e.g. the admin-vs-gestão fee split) are free but reCAPTCHA-gated at the API layer (g-google-authorization header on every request), so they're intentionally not automated here.

Verification

  • pytest — 235 passed (3 new), 16 deselected
  • ruff + mypy clean on changed modules
  • Live fetch confirmed: real NTN-B rates returned via the CLI

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added ANBIMA federal government bonds (TPF) secondary-market reference rates (public, daily). Available via /anbima/tpf, a findata anbima tpf CLI command, and the associated data function, with optional date and bond-type (titulo) filtering and result limiting.
  • Bug Fixes
    • Improved robustness when reference files are unavailable (weekend/holiday 404 now returns an empty result) and tightened/clarified parsing and input validation, including tolerant header handling.
  • Tests
    • Added parsing and API coverage for TPF, including filters and empty-results scenarios.
  • Documentation
    • Updated release notes/changelog and source listing to include TPF.

New get_tpf() fetches daily reference rates for outstanding federal
government bonds (LTN, LFT, NTN-B, NTN-C, NTN-F) from ANBIMA's public
file www.anbima.com.br/informacoes/merc-sec/arqs/ms{ymd}.txt — no key,
no auth, same @-separated layout as the existing debêntures feed.

Wired through the stack mirroring get_debentures:
- TPFQuote model + get_tpf() in sources/anbima/indices.py
- GET /anbima/tpf (filter by titulo, limit)
- findata anbima tpf CLI command
- parse + endpoint tests; CHANGELOG entry

Closes the one clean open gap on data.anbima.com.br's datasets that has
a key-free equivalent. The portal's fund datasets remain reCAPTCHA-gated
and are intentionally not automated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@robertoecf, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 19 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4bbbee88-e9e9-4c6a-bd8f-a633753049e5

📥 Commits

Reviewing files that changed from the base of the PR and between 3222ec5 and 8507f3f.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • src/findata/sources/anbima/indices.py
📝 Walkthrough

Walkthrough

Adds end-to-end support for ANBIMA's daily TPF (federal public bond) secondary-market reference data. A new TPFQuote Pydantic model, _compact_to_iso and _norm_header helpers, and get_tpf parser are added to indices.py alongside a refactored shared TXT-fetch helper. These are exported via the anbima package, surfaced as GET /anbima/tpf (FastAPI) and findata anbima tpf (CLI), covered by mocked unit and API tests, and documented in the changelog.

Changes

ANBIMA TPF Data Source

Layer / File(s) Summary
TPFQuote model, URL constant, parsing helpers, and get_tpf function
src/findata/sources/anbima/indices.py, src/findata/sources/anbima/__init__.py
Adds unicodedata import, TPF_URL template, TPFQuote Pydantic model with compact-date and Brazilian-formatted rate fields, _norm_header and _compact_to_iso normalizers, shared _fetch_anbima_txt refactoring for capped downloads and 404 handling, and get_tpf function that downloads and parses the @-delimited TPF TXT file. Exports TPFQuote and get_tpf in the package __all__.
API endpoint, CLI command, and source advertisement
src/findata/api/routers/anbima.py, src/findata/cli.py, src/findata/api/app.py
Adds GET /anbima/tpf FastAPI route with data, titulo (case-insensitive substring filter), and limit query parameters. Adds findata anbima tpf CLI subcommand with --date, --titulo, and --last options rendering a Rich table of rate/PU fields. Updates ADVERTISED_SOURCES to include TPF in the ANBIMA dataset listing.
Parser tests, API tests, and changelog
tests/test_anbima.py, CHANGELOG.md
Adds test imports for TPF_URL and get_tpf. Adds mocked parser test asserting ISO date normalization, negative rate preservation, and criterio field. Adds robustness tests for _compact_to_iso validation and accented header tolerance. Adds API smoke tests for the unfiltered endpoint, 404-to-empty behavior, and titulo filtering. Adds Unreleased changelog entry documenting the new TPF data source, access surfaces, public status, source file pattern, and hardening behaviors.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop hop, a new bond has been found,
TPF rates from ANBIMA abound!
The @-delimited file parsed with care,
Compact dates to ISO—fresh as spring air.
findata anbima tpf—type it and see,
Daily reference rates, public and free! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main feature added: ANBIMA Títulos Públicos (TPF) secondary-market source support across parsing, API, and CLI layers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/anbima-tpf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for the ANBIMA Títulos Pùblicos (TPF) secondary market, introducing a new API endpoint /anbima/tpf, a CLI command findata anbima tpf, and the corresponding parser and data models. The review feedback highlights a potential parsing issue where the header check for "titulo" might fail if the source file contains the accented word "título", and suggests a more robust prefix-based check.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/findata/sources/anbima/indices.py
robertoecf and others added 2 commits June 16, 2026 21:03
…eview

Adversarial review (grok-composer-2.5 external + host cross-validation)
flagged that get_tpf shipped without the resilience get_ima_history already
has. Fixes, all additive:

- Weekend/holiday HTTP 404 now returns [] instead of surfacing as a 500.
  Shared helper _fetch_anbima_txt() catches HTTPStatusError, maps 404 -> []
  (debug log), logs+re-raises other HTTP errors. Applied to get_debentures
  too, since it shared the same wart.
- Download size capped (max_bytes=8 MiB) to bound pathological upstream bodies.
- Header detection tolerates an accented "Título" via _norm_header()
  (NFKD accent strip); previously the exact == "titulo" gate would silently
  return [] on any accent drift.
- _compact_to_iso() validates the YYYYMMDD it builds with date.fromisoformat;
  a shape-valid-but-impossible date (e.g. 20261399) keeps the raw token
  rather than fabricating "2026-13-99".
- Warn-log when a file yields no recognisable header row.

Tests: +5 negative-path cases (404->[] at lib and API layer, accented
header, compact-date validation). 224 -> 229 tests; ruff + mypy clean.

Deferred (whole-codebase, not TPF-specific; tracked separately): server-local
date.today() default, shared-LRU cache namespacing, float->Decimal for PU.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/findata/sources/anbima/indices.py`:
- Around line 628-632: Remove the duplicate `if not header_seen:` conditional on
line 629 that creates redundant nesting. Replace the current header detection
logic that uses `cells[0].strip().lower().startswith("tit")` with a call to the
`_norm_header` helper function, which properly handles accented characters.
Apply `_norm_header` to the header text being checked so that accented "Título"
headers are correctly recognized, as the current string method comparison fails
when the second character is an accent (í instead of i). This aligns with the
test expectations and PR objectives for accent-tolerant header detection.

In `@tests/test_anbima.py`:
- Around line 167-177: The implementation in the indices.py file at line 630
checks header names using `.lower().startswith("tit")` without accent
normalization, which fails for accented "Título" since the accented character
"í" differs from "i". To fix this, apply the `_norm_header` function to
normalize accented characters before performing the startswith comparison,
ensuring both "Titulo" and "Título" are recognized as the same header regardless
of accents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7558ed4e-43f7-430c-b6be-ecd5c46787ad

📥 Commits

Reviewing files that changed from the base of the PR and between ee933c4 and 3222ec5.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • src/findata/api/app.py
  • src/findata/sources/anbima/indices.py
  • tests/test_anbima.py
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

Comment thread src/findata/sources/anbima/indices.py
Comment thread tests/test_anbima.py
…eader check

Conflict was confined to the [Unreleased] section of CHANGELOG.md: the
feat branch added an `### Added` (TPF) block while main added a `### Fixed`
(cvm holdings) block. Both kept, ordered Added before Fixed per Keep a
Changelog.

Also fixes a syntax error on the PR head (commit 3222ec5): a GitHub web
"commit suggestion" duplicated `if not header_seen:` and replaced the
accent-tolerant header check with `.lower().startswith("tit")`, which an
IndentationError aside would have stopped matching the accented "Título"
header and broken the documented "accented header tolerated" behavior.
Restored `_norm_header(...).startswith("titul")`.

Verified on the merged tree: 231 passed, 15 deselected; ruff + mypy clean
on the changed module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@robertoecf robertoecf merged commit e1f36b6 into main Jun 17, 2026
6 checks passed
@robertoecf robertoecf deleted the feat/anbima-tpf branch June 17, 2026 01:38
robertoecf added a commit that referenced this pull request Jun 26, 2026
* Add ANBIMA Títulos Públicos (TPF) secondary-market source

New get_tpf() fetches daily reference rates for outstanding federal
government bonds (LTN, LFT, NTN-B, NTN-C, NTN-F) from ANBIMA's public
file www.anbima.com.br/informacoes/merc-sec/arqs/ms{ymd}.txt — no key,
no auth, same @-separated layout as the existing debêntures feed.

Wired through the stack mirroring get_debentures:
- TPFQuote model + get_tpf() in sources/anbima/indices.py
- GET /anbima/tpf (filter by titulo, limit)
- findata anbima tpf CLI command
- parse + endpoint tests; CHANGELOG entry

Closes the one clean open gap on data.anbima.com.br's datasets that has
a key-free equivalent. The portal's fund datasets remain reCAPTCHA-gated
and are intentionally not automated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* harden(anbima): make TPF/debêntures fetch resilient per adversarial review

Adversarial review (grok-composer-2.5 external + host cross-validation)
flagged that get_tpf shipped without the resilience get_ima_history already
has. Fixes, all additive:

- Weekend/holiday HTTP 404 now returns [] instead of surfacing as a 500.
  Shared helper _fetch_anbima_txt() catches HTTPStatusError, maps 404 -> []
  (debug log), logs+re-raises other HTTP errors. Applied to get_debentures
  too, since it shared the same wart.
- Download size capped (max_bytes=8 MiB) to bound pathological upstream bodies.
- Header detection tolerates an accented "Título" via _norm_header()
  (NFKD accent strip); previously the exact == "titulo" gate would silently
  return [] on any accent drift.
- _compact_to_iso() validates the YYYYMMDD it builds with date.fromisoformat;
  a shape-valid-but-impossible date (e.g. 20261399) keeps the raw token
  rather than fabricating "2026-13-99".
- Warn-log when a file yields no recognisable header row.

Tests: +5 negative-path cases (404->[] at lib and API layer, accented
header, compact-date validation). 224 -> 229 tests; ruff + mypy clean.

Deferred (whole-codebase, not TPF-specific; tracked separately): server-local
date.today() default, shared-LRU cache namespacing, float->Decimal for PU.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Update src/findata/sources/anbima/indices.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: Roberto <robertoecf@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant