Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ adheres to [Semantic Versioning](https://semver.org/).

### Changed

- **Resolver docs: Mais Retorno Free limits.** `docs/RESOLVER.md` now
states that the optional cascade step uses the operator's own account and
documents the public Free tier (500 credits/month shared by REST+MCP,
variable per-call cost, 1-year history, 15 req/s, HTTP 429 until renewal or
upgrade), distinguishing REST API key vs MCP OAuth, with dated links to
[maisretorno.com/mcp](https://maisretorno.com/mcp) and
[developers.maisretorno.com](https://developers.maisretorno.com). Also
aligns the cascade wording with runtime behavior: a provider result replaces
the current classification (provider owns ``confidence``/``source``); the
resolver only prepends ``cascade``.
- **Distribution slug renamed `findata-br` → `openfindata`.** The PyPI
distribution name is now `openfindata` (`pip install openfindata`,
`pip install 'openfindata[b3]'`), aligning the package slug with the
Expand Down
51 changes: 44 additions & 7 deletions docs/RESOLVER.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,51 @@ Quando `confidence < ~0.9` ou status `candidate`, é gancho de revisão humana.

1. **openfindata** (primário, offline): seed curado + regras estruturais. Resolve
o test set sem rede.
2. **Mais Retorno MCP** (dados BR de fundo/CNPJ/classe CVM).
2. **Mais Retorno** (dados BR de fundo/CNPJ/classe CVM) — provider externo
opcional via API de dados / MCP; ver limites Free abaixo.
3. **outro provider** (CVM dados abertos / B3).
4. **web_search restrito** a `maisretorno.com`, `b3.com.br`,
`yahoofinance.com.br`, `debentures.com.br`.

Cada degrau preenche o que o anterior não trouxe e **baixa a confidence**;
`source` reflete a origem final; `cascade` loga o caminho. Os degraus 2 a 4 são
um ponto de extensão injetável (`AssetProvider`), consultado só quando o
resultado do núcleo está fraco. No estado atual deste PR, **só o degrau 1 está
ligado** (os externos são stubs a conectar no deploy).
Cada degrau que retorna resultado **substitui** a classificação atual (o
provider controla campos, `source` e `confidence`); o resolver só antepõe o
`cascade` anterior ao `cascade` devolvido. Os degraus 2 a 4 são um ponto de
extensão injetável (`AssetProvider`), consultado só quando o resultado do
núcleo está fraco. Hoje **só o degrau 1 está ligado** (os externos são stubs a
conectar no deploy).

### Mais Retorno: plano Free e cotas

O openfindata **não embute** chave nem cota da Mais Retorno. Quem ligar o
degrau 2 no deploy usa a conta do operador. A API de dados tem dois canais
sobre o **mesmo saldo de créditos**
([developers.maisretorno.com](https://developers.maisretorno.com), conferido em
2026-08-12):

- **REST** (típico para um `AssetProvider` server-side): API key
(`X-Api-Key` / `Authorization: Bearer`) gerada em
[maisretorno.com/app/meu-perfil/api](https://maisretorno.com/app/meu-perfil/api).
- **MCP** (agente de IA): URL
`https://data.maisretorno.com/mr-data/v4/mcp`, autenticação **OAuth** (sem
api-key). Página de produto:
[maisretorno.com/mcp](https://maisretorno.com/mcp).

Limites relevantes do plano **Free** (permanente, sem cartão):

| Item | Free |
|---|---|
| Créditos | 500/mês no mesmo saldo REST+MCP |
| Custo por chamada | variável (ex.: search grátis; `asset-info`/quotes/`fund-class-subclass` = 1; stats/drawdown = 5; `wallet-detail` = 10; compare/backtest = 25) |
| Histórico | até 1 ano (planos pagos: histórico completo) |
| MCP | disponível no Free (mesmas classes/endpoints dos planos pagos) |
| Rate limit | 15 req/s em todos os planos |
| Cota esgotada | HTTP 429 até renovar o ciclo ou fazer upgrade (aviso por email ~80%) |

Não trate 500 créditos como “500 resoluções”: um provider que chame stats ou
carteira consome bem mais por ativo. Fora do escopo dessa API/MCP (não usar
como fallback para esses ativos): CRI, CRA, FIDC, debêntures e ativos offshore.
Volume e profundidade de histórico sobem nos planos pagos; o rate limit por
segundo não.

## Test set (passa 100%, offline)

Expand All @@ -126,7 +161,9 @@ ligado** (os externos são stubs a conectar no deploy).

## Pendências antes de produção

- Conectar os providers externos reais (Mais Retorno MCP, web search restrito).
- Conectar os providers externos reais (Mais Retorno via REST/API key do
operador — Free = 500 créditos/mês no saldo compartilhado com o MCP —, e
web search restrito).
- Confirmação ISIN-level da incentivada (12.431) via ANBIMA/debentures.com.br no
degrau de cascata — hoje fica `candidate`.
- Ampliar o seed curado de ETFs conforme novos ETFs forem listados na B3.
19 changes: 19 additions & 0 deletions docs/SOURCES_WITH_AUTH.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ Quirks da API ANBIMA (já validamos em testes ao vivo):



## Mais Retorno (cascata do resolver): Free com cota

Não é fonte core do openfindata — é um degrau opcional da cascata de
`resolve_asset` (`docs/RESOLVER.md`). O operador traz a própria conta; o
projeto não embute credenciais.

Plano **Free** permanente (sem cartão), conforme
[maisretorno.com/mcp](https://maisretorno.com/mcp) e
[developers.maisretorno.com](https://developers.maisretorno.com) (conferido em
2026-08-12): 500 créditos/mês no mesmo saldo para REST e MCP, histórico de até
1 ano, rate limit 15 req/s. Custo por operação é variável (não 1 crédito por
qualquer chamada). REST autentica com API key; MCP autentica com OAuth.
Cota esgotada → HTTP 429 até renovar o ciclo ou fazer upgrade. Volume e
histórico completo ficam nos planos pagos.

Trate como `free_logged_in` com cota mensal: self-serve, mas não anônimo e
não ilimitado. Detalhes e escopo (o que a API/MCP não cobre) estão em
`docs/RESOLVER.md`.

## Base dos Dados: grátis, mas com login/projeto do usuário

Base dos Dados não entra na mesma categoria da API autenticada da ANBIMA. O
Expand Down
21 changes: 13 additions & 8 deletions src/findata/resolver/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
2. **Structural rules** (this module) — name/ticker patterns that *are*
derivable: COE, debenture, CRA/CRI, bank paper, Tesouro, IE/global,
FII, FIA/Ações, Multimercado, FIDC/FIP, plain tickers.
3. **External providers** (optional, injected) — Mais Retorno MCP, CVM/B3,
3. **External providers** (optional, injected) — Mais Retorno, CVM/B3,
restricted web search. Not bundled here (they are client-side / networked);
the resolver takes a chain of async callbacks so a deployment can wire them.
Each step that fires lowers ``confidence`` and is appended to ``cascade``.
Mais Retorno uses the operator's own account/quota (see
``docs/RESOLVER.md``). A non-``None`` provider result replaces the current
classification (provider owns fields/``source``/``confidence``); the
resolver only prepends the prior ``cascade``.

The seed + rules layers are pure and offline, so the spec's test set resolves
deterministically with no network. ``source`` is ``"openfindata"`` for every
Expand Down Expand Up @@ -101,10 +104,11 @@
class AssetProvider(Protocol):
"""An external cascade step (Mais Retorno, CVM/B3, web search).

Receives the normalized input and the best classification so far; returns an
enriched classification (new ``source``, possibly higher-detail fields) or
``None`` to pass. Implementations live outside the library because they are
networked / client-side; the resolver only orchestrates them.
Receives the normalized input and the best classification so far; returns a
full classification that **replaces** the current result (provider owns
fields, ``source``, and ``confidence``), or ``None`` to pass. The resolver
only prepends the prior ``cascade``. Implementations live outside the
library because they are networked / client-side.
"""

async def __call__(
Expand Down Expand Up @@ -707,8 +711,9 @@ async def resolve_asset(
Runs the deterministic core (curated seed → structural rules), then walks the
optional external provider chain (Mais Retorno → CVM/B3 → restricted web
search) only while the result is still weak (``Indefinido`` or low
confidence). Each provider that fires is appended to ``cascade`` and may lower
confidence; the deepest one to set a field owns ``source``.
confidence). A provider result replaces the current classification; the
resolver prepends the prior ``cascade``. The provider owns ``source`` and
``confidence``.

No PII: callers pass only an asset identifier, never client data.
"""
Expand Down
Loading