Analyze Brazil CVM Filings with DuckDB
Want DuckDB CVM filings analysis without building a warehouse first? Pull document list JSON from apicvm, load it into DuckDB, and run SQL over ticker / type / year inventories. DuckDB is local analytics; apicvm is the filings HTTP source.
The problem
Analysts often need:
- A quick inventory of DFP/ITR/FRE rows across a watchlist
- Joins between tickers and filing years before downloading PDFs
- Something lighter than standing up Postgres for a one-off study
pandas and Polars work (see pandas and Polars). DuckDB is useful when the rest of the notebook is already SQL-shaped.
Setup
export APICVM_URL='https://apicvm.dev'
export APICVM_KEY='apicvm_...'
pip install duckdb requests
Pull a document page into DuckDB
import os, json, requests, duckdb
BASE = os.environ["APICVM_URL"]
H = {"Authorization": f"Bearer {os.environ['APICVM_KEY']}"}
resp = requests.get(
f"{BASE}/v1/documents",
headers=H,
params={"ticker": "BRFS3", "type": "DFP", "year": 2024, "perPage": 50},
timeout=30,
)
resp.raise_for_status()
payload = resp.json()
con = duckdb.connect()
con.execute("CREATE TABLE docs AS SELECT * FROM read_json_auto(?)", [json.dumps(payload["data"])])
print(con.execute("SELECT id, name, type, year FROM docs LIMIT 10").fetchdf())
If read_json_auto complains about shape, dump payload["data"] to a .json file and read_json('docs.json') instead.
Watchlist inventory
import time
TICKERS = ["BRFS3", "JBSS3", "ABEV3"]
rows = []
for t in TICKERS:
page = 1
while True:
r = requests.get(
f"{BASE}/v1/documents",
headers=H,
params={"ticker": t, "type": "FRE", "year": 2024, "page": page, "perPage": 50},
timeout=30,
)
r.raise_for_status()
body = r.json()
for d in body["data"]:
rows.append({**d, "tickerQuery": t})
if page >= body["meta"]["lastPage"]:
break
page += 1
time.sleep(0.2) # stay under rate limits
con.execute("CREATE OR REPLACE TABLE fre AS SELECT * FROM read_json_auto(?)", [json.dumps(rows)])
print(
con.execute(
"""
SELECT tickerQuery, COUNT(*) AS n
FROM fre
GROUP BY 1
ORDER BY 1
"""
).fetchdf()
)
Respect X-RateLimit-* headers when looping. See Handle errors and rate limits.
From inventory to PDF
DuckDB helps you choose which id to download — it does not fetch the PDF itself:
curl -OJ -H "Authorization: Bearer $APICVM_KEY" \
"$APICVM_URL/v1/documents/<document-id>/file"
Current limitations
- apicvm returns filing metadata and files; it is not a DuckDB-hosted warehouse.
- List endpoints max
perPage50 — paginate for full coverage. - Do not invent document counts offline; query the API for the current inventory.
- Markdown extraction is a separate async Pro flow, not a DuckDB table.
Next steps
Ready to integrate?
Get an API key and start querying Brazilian CVM filings programmatically.