Skip to main content
Parameters, response columns and types are generated from the SQL catalog and render under Endpoints → Quotes in the sidebar. This page carries what a schema cannot: the conventions, the nulls that are deliberate, and the traps.

Overview

B3 COTAHIST cash-market prints (tpmerc = 010), exactly as published. Nothing is split- or dividend-adjusted, and every row carries adjusted: false. The grain is (ticker, trade_date, board, term_days). A ticker can print on more than one board on the same day, so a query that does not pin board can return several rows per session. codbdi varies by instrument type (02 common equities, 12 FIIs, 14 ETFs, 34 BDRs). quote_history follows the instrument (its ISIN) across boards unless you pass one; quote_latest reads every board. asset_class is derived conservatively from B3’s published tpmerc and especi: equity, unit, bdr, fund_quota, index, right, bonus, or cash_security. To split fund_quota into ETF vs FII vs FIAGRO, use fund_quotas’ fund_type column, which comes from B3’s published CODBDI board code.
close is the price of quotation_factor units, not always one. close_unit = close / quotation_factor is served for you. The factor is 1 for almost everything (13 tickers on the whole 2019–2026 tape carry another value), but a paper quoted per lot reads 1000× its unit price in close.Neither is corporate-action adjusted. close_unit divides by a published field; it does not account for splits, groupings or bonuses. A split still appears as a jump in the price. panel’s close_return is null across a factor change and, across a split, grouping or bonus between the two prints, divides the previous close by the event’s share ratio.

GET /quotes

The view — full column set, arbitrary filters and sort. Use it for cross-sectional slices (a whole session, a set of tickers) rather than one instrument’s series.
This view has no built-in cap — always send limit. An unbounded read is cut at 1,000 rows server-side, and Content-Range is the only thing that tells you.

POST /rpc/quote_history

One ticker’s daily series over a window, ordered by trade_date ascending, one JSON object per session holding only the fields you select.
Default: ticker, trade_date, close_adj. close_adj is the close per single share, backward-adjusted for splits (DESDOBRAMENTO), groupings (GRUPAMENTO) and bonus shares (BONIFICACAO) by B3’s rule (1 + factor/100 for splits and bonuses, factor for groupings, events on one date multiplied), anchored to the instrument’s latest session and rounded to 6 decimal places. Past levels change when an event lands; returns do not. Dividends, JCP and subscription rights are not adjusted: they move value to holders and change no share count, so they belong to a total-return series, not this one. Shares (ISIN code ACN) and units (CDA/UNT, ticker ending 11) only. The raw close is an explicit selection: p_fields: ["close"], or any of open, high, low, average, bid, ask, close_unit, trades, quantity, volume, quotation_factor, board, isin, short_name, spec, currency, asset_class, source, coverage_start, coverage_end, prior_no_trade_sessions, events_proven_at, data_revision (types in catalog().defaults.quote_history.available). Keep the same p_fields on every page. Additional preserved fields are opt-in: market, term_days, contract_price, contract_expiry, contract_correction, contract_points, contract_points_raw, distribution_number and fetched_at. The last is warehouse time, not original publication time. See catalog().cotahist for the source aliases and dated code reference. No change to the default adjusted-price selection.
A ticker’s history follows the company across an ISIN change. When a company changes its trading code or B3 issues a new ISIN (VIIA3 BRVIIAACNOR7 until 2023-09-19, then BHIA3 BRBHIAACNOR1 from 2023-09-20), a window that reaches back runs through the older instrument. Each row keeps its own ticker and isin, close_adj stays continuous across the seam, and close_total_return is null before it. The splice needs the same company in CVM’s FCA, the same share class, adjacent sessions with no overlap, no stock event at the seam and exactly one candidate (docs/adr/0002-ticker-activity-and-lineage.md); otherwise the window is refused. What it refuses (22023, with details starting reason=) rather than serve a partial or substituted series: Inside the coverage a missing session is a session with no trade (COTAHIST lists only papers that traded; prior_no_trade_sessions counts them) and holidays are not sessions. A field with no value is a JSON null. Data revision. Every response carries the header X-Silo-Data-Revision (and the data_revision field when selected): the newest load of the tape, the corporate events or their proof. close_adj levels move when it changes, so never combine pages or calls with different revisions; the SDK restarts instead.
One 1,000-row page, and it refuses above it (22023) — you never receive a truncated series that looks complete. Roughly four years of one ticker fits in a page.Page it with p_after: "" then the last row’s trade_date, or narrow the window:
The SDK walks it: silo.iter_quote_history("PETR4", start="2019-01-02").

POST /rpc/quote_latest

The most recent stored session for one ticker. At most one row, same columns as quote_history.
p_board null means “latest across all boards”.
Note: “latest” means the latest session stored, not today — whatever the last successful COTAHIST ingest loaded. Check trade_date on the row and coverage for the dataset. A stale close is never advanced to today’s date to make it look current.

Empty and error behavior

  • Unknown ticker → 200 []. Not a 404, and never a fabricated last close.
  • Known ticker, no sessions in the window (a holiday range, or a window before the paper listed) → also 200 []. The two cases are indistinguishable from the response; use lookup to confirm the ticker exists.
  • Wrong board is a common cause of a surprising empty result. Some papers do not print on 02 — retry with "p_board": null.
  • A malformed date or filter returns 400.