Dados B3 › Transparency
Transparency
Transparency — how you check the numbers yourself
Data version 2026-11-09-ancora-do-fre · page generated 2026-11-12 08:09 UTC. If these do not match /saude, you are reading a cached copy.
What is checked, before every publication — 1298 automated tests, collected live
13 are DATA invariants (does the number tie out?) and 131 are product tests — access gate, navigation, language, AI connector. Calling all 1298 'invariants' would be inflating it: the split is checkable in the list itself. Not a hand-picked highlight reel: every test below was found by introspecting the actual test files just now, the same way pytest --collect-only would. Grouped by what it protects against, not by which file it lives in.
Level 1 — Integrity: does the data tie out? (6)
TL01— The recorded Anatel file (one row per tax ID and product, one column per month) becomes the sum per operator and month: Vivo in August 2026 has 85,818,766 mobile accesses WITHOUT M2M and service points (which go to the other column: 20,141,773), and the August TOTAL adds up to 220,921,381, equal to Anatel's official total; an operator under 100 thousand accesses stays out (only in the TOTAL); an empty file, one without the checked fields or without month columns returns nothing and the reason; an empty cell is "no data", not zero; a malformed tax ID drops the row.TL02— The Anatel ZIP is read by byte range: the central directory comes from the end of the file and only the requested member is downloaded and decompressed as a stream; a missing member returns None; ZIP64, an unknown compression method, a file that is not a ZIP and a server that answers HTTP 200 instead of 206 all stop with an error instead of downloading gigabytes.TL03— The collection writes both services, checks the TOTAL against Anatel's official total month by month (0.0% difference) and stores the result in the telecom collection record; a source that is down, a file without the checked fields, a value outside the plausible range, a summed total more than 5% away from the official one or an exception writes nothing for that service, deletes nothing, never raises, lets the other service go on and leaves the reason in the record; repeating the collection does not duplicate rows.TL04— The batch of files: the history reads from 2023 (mobile by semester, broadband by year), the recent run reads the current period (broadband also reads the previous year in January and February); the night only collects again when it never collected, the last run had an error or it is more than 6 days old.TL05— The telecom accesses table is part of the inheritance of external series: in a from scratch build where the source failed the rows of the previous database come back, the fresh row wins over the old one, and the shrink guard counts the table.TL09— With no telecom accesses table in the database the filtered JSON route answers 503 with Retry-After, the unfiltered one answers 200 with a notice, the page answers 200 in both languages with the series being collected notice, noindex, the licence and the agreed use but no number, no table and no link to the JSON route, the health route does not fail and shows the telecom block as null, and the sitemap does not announce the page.
Level 2 — Semantics: does the account mean what the calculation assumes? (7)
TL06— The ranking uses the consolidated month (the one before the newest): TOTAL first, then Vivo 85,818,766 (38.85% of 220,921,381; +1.60% against 84,463,402 a year earlier), Claro, TIM (-2.60%), Surf; the preliminary month comes apart and is not in the calculation; broadband falls in September (as in the official total) so the ranking stays in August; the monthly series flags the newest month as preliminary.TL07— The link to a stock exists only when the full tax ID of the operator is the one of a company with a ticker: Telefonica Brasil links to VIVT3 from the register, TIM S.A. links to TIMS3 from the main row of the ticker table, Claro never links, and a company with the same name, the same 8 digit root (another branch) or no ticker never links; with no register row nothing is invented.TL08— The accesses route returns the ranking of both services with source, the CC BY-ND 3.0 licence (never CC BY), the use arranged with Anatel, the required attribution and a citation line, with no municipality, technology or product rows; with a service and a tax ID (with or without punctuation, or TOTAL) it returns the monthly series cut by from and to months; CSV has a fixed header; bad parameters give 400 and an unknown operator 404.TL10— The telecom page in Portuguese and English opens with the sentence of totals and leaders, the attribution to Anatel at the top, the two tables with the Vivo line (85,818,766, 38.85%, +1.60%), the preliminary month apart, the notice that M2M and service points are left out, that the sums, the TOTAL, the share and the change are our calculations and that an operator is not the stock, the source with both files, the CC BY-ND 3.0 licence, the use arranged with Anatel, the citation line, the canonical link and a JSON-LD dataset; only Vivo and TIM link to a stock and only with the identical tax ID; no browser script other than JSON-LD.TL11— Without a register row with a ticker and an identical tax ID the page links to no stock at all, neither by the name Vivo or TIM nor by the group.TL12— The health route carries the telecom block (newest month, age per service, 75 day limit, last collection) and raises attention only past the limit, not at it; the Macro hub in both languages and the API hub carry the page and route cards; the sitemap announces the page with the first day of the newest month as last modified and never in the future; llms.txt cites page, route, licence and the agreed use; the methodology pages exist in both languages with the source, the CC BY-ND 3.0 licence (never CC BY), the agreed use and the attribution.TL13— The telecom connector tool calls the same route as the page: with no argument it returns the ranking with source, licence and attribution, with a service and a tax ID it returns the monthly series, and a bad request comes back as an error field and never as an exception.
Level 3 — Economic: is the result possible in the real world? (0)
Other product tests (0)
Access gate, navigation and the MCP connector — they test whether the product works, not whether a number is right, so they don't fit the 3 levels above by design. Still counted, still listed:
Reconstruct it yourself — net margin across 5 companies, 4 sectors
We don't ask you to trust the numbers. Here's the net margin of five companies in four different sectors, each rebuilt straight from its annual report (DFP) at the CVM — net income ÷ revenue, matching the published figure exactly. For ANY indicator, of any company, the whole chain down to the line in CVM's file is at /linhagem:
| Company · sector | Net income (CVM acct) | Revenue (CVM acct) | Margin =÷ |
|---|---|---|---|
| WEGE3 · industrial | R$ 6.78 bn DRE:3.11 | R$ 40.80 bn DRE:3.01 | 16.6% |
| VALE3 · mining | R$ 11.81 bn DRE:3.11 | R$ 213.59 bn DRE:3.01 | 5.5% |
| PETR4 · oil & gas | R$ 110.61 bn DRE:3.11 | R$ 497.55 bn DRE:3.01 | 22.2% |
| ITUB4 · bank | R$ 45.85 bn DRE:3.09 | R$ 387.12 bn DRE:3.01 | 11.8% |
| BBAS3 · bank | R$ 16.78 bn DRE:3.11 | R$ 319.46 bn DRE:3.01 | 5.3% |
Download any of these DFPs from the CVM, take the income and revenue accounts, divide — you get the same number. Banks use interest income as revenue (what makes sense for a bank), so the reconciliation is sector-aware; the others use sales revenue. Figures are the latest fiscal year.
Why we may differ from another site (and it's not an error)
A difference between two sites usually isn't one being wrong — it's a method choice. We disclose ours:
- Average vs ending capital: ROE and ROIC use average equity/capital (this year + last ÷ 2), not the ending balance — so they're not a naive single-year division.
- Controlling vs consolidated: we state which one each item uses.
- TTM vs annual: quarterly multiples use trailing-twelve-months earnings.
- IFRS 16, goodwill, cash, exceptional tax: each handled explicitly and flagged when it distorts.
Do the tests bite? Yes — real cases the suite has caught
A test that never fails could mean perfect data — or a weak test. These were born from real errors that slipped through, and now fail — only shown for tests that actually exist in the collected suite above:
- I-B16 · banks' P/E = 0: the CVM reports share count sometimes in units, sometimes in thousands (varying by company and year); market cap came out 1000× too small and P/E was zero. I-B16 (price × shares recomputed) caught it — we fixed 661 annual and 2,027 quarterly multiples.
- I-B24 · the vanishing profit: the profit/equity account varies by bank (Itaú 3.09, BB 3.11); if the label search fails, the number vanishes silently and ROE is born wrong. I-B24 makes that hole fail.
- H-B23 · the 800% dividend yield: old B3 dividends carry a price not adjusted for splits; without H-B23 the yield would look absurdly real. The flag keeps the record and warns.
- I-B20 · the missing COTAHIST 2023: on the first deploy one year of prices failed to download silently; the API shipped with ~50k fewer prices and the suite passed, because nothing checked coverage. We added I-B20 — a year without prices now fails the build loudly.
- I-B33 · Oil & Gas at −89.6% in one week: COTAHIST isn't split-adjusted; a 10:1 split read as a −90% weekly return and stayed in the cumulative return forever, with nothing failing (a blind amplitude filter didn't fix it either — it just flipped which direction was wrong). I-B33 (no sector week beyond ±35%, the ruler is the exchange itself) stops the build.
- I-B31 · 364 of 865 sector-index weeks frozen: extending the series back to 2010, a sector with no company carrying a market cap that week turned into a factor of 1.0 — a flat line that the cumulative return read as 'market stood still', and the 'since 2010' return came out fictional (+527%). I-B31 fails on any week repeated to the cent.
- I-E05 · EMBRAER's 2010 P/E priced with 2025 data: the point-in-time price lookup fell forward with no ceiling whenever the current ticker had no price at balance-sheet time (ticker change, share-class migration); the multiple came out priced 15 years into the future, in 22% of annual and quarterly rows, silently. The 45-day window (and I-E05) blocks it: no session inside the deadline, no multiple computed.
- I-E04 · AZUL at R$ 1.67 quadrillion market cap: the balance sheet carried 54.7 trillion shares from the judicial recovery issuance, but the price used was already on the post-reverse-split (1:150,000) basis — two ends measured on different bases, market cap wrong by orders of magnitude. I-E04 (market cap never above Brazil's GDP) fails the build on that absurdity.
How far back each block of data goes
No asterisks here: this is coverage year by year, counted right now. Indicators (ROE, ROIC, margins, growth) come from the filings alone and cover the whole series. Multiples (P/E, P/BV, EV/EBITDA) need a price and a share count — and the share count comes from CVM's reference form, which the further back you go the fewer companies filed in a usable format. The gap between the two columns is a source limit, not an ingestion hole. If you look for an old P/E and do not find it, it is because nobody has it — not because we hid it. The same numbers as JSON: /cobertura.
| Year | Companies with indicators | Companies with multiples |
|---|---|---|
| 2025 | 441 | 290 |
| 2024 | 443 | 296 |
| 2023 | 441 | 298 |
| 2022 | 428 | 295 |
| 2021 | 422 | 296 |
| 2020 | 410 | 274 |
| 2019 | 371 | 166 |
| 2018 | 326 | 167 |
| 2017 | 317 | 165 |
| 2016 | 311 | 154 |
| 2015 | 303 | 144 |
| 2014 | 301 | 140 |
| 2013 | 292 | 131 |
| 2012 | 291 | 112 |
| 2011 | 284 | 98 |
| 2010 | 277 | 34 |
Live coverage
457 companies · 884,647 price points · 8,650 recorded restatements · last refresh 2026-11-12 01:38:24. Full live counts at /saude.
Sources: CVM (open data, ODbL) and B3 (COTAHIST). Not affiliated with B3 or the CVM. Not investment advice.
Numbers on this page are live. Data version 2026-11-09-ancora-do-fre · page generated 2026-11-12 08:09 UTC. If this does not match /saude, you are reading a cached copy.