Skip to main content

Overview

Three questions before you write a query: does SILO have it, how far back, and how stale can it be. Data inventory is the table-by-table view of the warehouse; this is the view from the API. Every date below is a floor, not a promise about today. The authoritative answer is coverage() and metric_coverage(), generated from the data — ask them first, and use this page to know what to ask for.

Ask the API what it holds

Four date columns meaning four different things. Reading one for another is the most common coverage mistake: Note: a stale landed_at is a pipeline failure. A complete_through that trails today is Brazil’s filing calendar — CVM publishes one to two months in arrears, and that is not an outage. metric_coverage() goes finer: first and last period carrying a non-null value for every (entity_type, metric) pair, plus how many rows filed it.

How far back

Ingest runs once a day at 06:00 UTC. A slice CVM publishes late is healed on a later run — the daily job re-probes a trailing window and re-fetches any month with no successful ingest.

The B3 BDI ratchet

B3 keeps roughly 21 business days of its lending and participation files and publishes no archive. There is no backfill at any price. These five endpoints are exactly as deep as the daily job has been running. A session missed is not expensive to recover — it is impossible.
No deep-history route exists and none is coming: the legacy B3 download API returns HTTP 400 for every BDI table name, and the pesquisapregao archive returns empty zips. run_backfill deliberately offers no lending option. The failure is silent by default — an over-wide request returns HTTP 200 with the window quietly clamped (2024-01-02 through 2026-09-10 returns 18 sessions). A 200 is not evidence the span you asked for was delivered, which is why every ingest reconciles received sessions against requested ones. Treat these five as a live feed with a short tail, not as history. If you need a long series, capture it as it publishes. Always read as_of before assuming a window exists.

Three caveats these endpoints publish as columns

float_basis says which denominator produced pct_float. index_free_float is B3’s real free float and covers index constituents only; shares_outstanding is a larger denominator and therefore a smaller percentage. Do not rank across the two. pct_float and days_to_cover are null — never 0 — when their denominator is missing.
B3 publishes a month-to-date cumulative snapshot; the daily figure is its first difference within a month. Rows whose flow_basis is unknown_opening_snapshot carry null flows on purpose — reporting the cumulative total as one day’s flow would invent a spike.
Not beneficial owners. Around 75% of trades carry the same code on both legs, so a large borrow through a broker is that broker’s client book. Read short_interest through is_total as well: B3 publishes both the per-market rows and its own Total sum, and adding them double-counts.

What is not here

Nothing on this API is interpolated or forward-filled, and exactly one price is adjusted.
  • Quotes are unadjusted, except quote_history’s close_adj. close and the adjusted flag (false on every row) are as traded. close_adj, the default field of quote_history, is continuous across splits, groupings and bonus shares, and a window it cannot adjust is refused with the cause, never served raw. close_total_return, selected in p_fields, adds the cash distributions and is NULL with a reason wherever one cannot be valued. The tape starts on 2019-01-02, and quote_history refuses a window that starts before an instrument’s first session. b3_corporate_event still carries the events as published.
  • A null is a null. Never a guessed last close, a zero, or a carried-forward figure. An unknown ticker returns an empty array.
  • A regime break is not a trend. FIDC delinquency starts in 2013-01 and is on every row only from 2020-11, so a count of reporting funds jumps there. catalog().regime_breaks lists them.
  • No ANBIMA-to-fund mapping exists. ANBIMA rows are industry aggregates carrying no fund id, and CVM’s classe is a different taxonomy. Joining by name would be an invention.

Next

Your first screen

A working screen of real data in four calls.

Paging without losing rows

Two different cursors, and the trap of confusing them.

Coverage reference

The coverage() and metric_coverage() endpoints in full.

Data inventory

Every table, its grain, and what we deliberately do not ingest.