Multiples (P/E, P/BV, EV/EBITDA)
The principle that separates this database from most retail tools
The price used to compute a multiple is never the closing price of the fiscal
year (December 31 of the year). It is the price of the first trading session
on or after the date on which that year's financial statements became publicly
available — the DT_RECEB field (receipt date) on the document's own cover
page at CVM.
Why: a DFP for a fiscal year ended on December 31 is usually published only in
February or March of the following year. Using the December 31 price together
with the profit from that balance sheet is comparing a quote the market had on
that day with information the market did not yet have — future-information
leakage. A real case measured in this database: WEG's 2025 DFP (cd_cvm 5410,
fiscal year ended 31/12/2025) was only received by CVM on 25/02/2026; the
2025 multiple uses the closing price of 25/02/2026, not of 31/12/2025.
Formulas
- Shares outstanding = total issued (
QT_ACAO_TOTAL_CAP_INTEGR, total paid-in shares) minus treasury shares (QT_ACAO_TOTAL_TESOURO), from the capital composition that accompanies theDFPitself — never from an external source. - Market cap = point-in-time price × shares outstanding.
- P/E = Market cap / Profit attributable to controlling shareholders (falls
back to consolidated profit with flag
lucro_total_sem_minoritarioswhen the company does not report the breakdown). - P/BV = Market cap / (total shareholders' equity − non-controlling interests).
- EV/EBITDA = (Market cap + Net debt) / EBITDA — inherits the same locks as
EBITDA (see
divida_liquida_ebitda.md): without D&A in the cash flow statement, the multiple is not published.
Ticker selection
A company may have more than one share class traded (ON and PN). The "main"
ticker used for price and multiples comes from the official CVM registry (FCA —
Formulário Cadastral, the registration form, dataset valor_mobiliario
(securities)), never from a name search: priority goes to the Ordinary class,
still trading (no end date), among those listed on the exchange. Companies with
no eligible class (e.g., only listed debentures, or delisted) are left without a
multiple — it is not estimated.
When CVM's registry does not give the ticker
The ticker comes from the FCA, which the company itself fills in — and
companies fill it in wrong. CSN puts 4030 in the trading-code field: that
is its CVM code, not its ticker. Our format validation rejects it, correctly,
and CSNA3 — 251 sessions in 2024 alone — was missing from the entire database.
That was 104 companies with no code at all, among them BTG Pactual and
Marisa.
The second source is B3's catalogue (GetInitialCompanies, the same one we
already use to match dividends), which returns codeCVM → a four-letter issuer
code. Keyed by CVM code, never by name — matching companies by name
similarity is how data gets glued to the wrong company.
Three gates come with it:
- A code is not a ticker on its own. Only codes that actually trade in COTAHIST are accepted. An issuer code with no trades stays out; we do not invent instruments.
- Shares only. Suffixes 3, 4, 5, 6, 7, 8 and 11. Outside that, B3 trades
things under the same issuer code that are not equity — 1 and 2 are
subscription rights, 9 and 10 are subscription receipts. In the first version
I accepted any digit and Marisa came in with
AMAR1andAMAR9. - A disputed issuer code is dropped. If two companies claim the same one, neither gets it.
The main instrument is the most liquid one, not the best share class. Class
priority alone gets it wrong: under "ordinary first", BTG Pactual would be
represented by BPAC3, which barely trades, instead of BPAC11, where the
liquidity is. Session counts decide, with class as the tie-break. For the same
reason, a company whose declared main class does not trade is now
represented by the class that does — before, it had no price at all and
vanished from the site over a registry detail.
Result: 290 → 320 companies with prices, and 281 → 306 with multiples.
Companies that changed their ticker
B3 renames tickers fairly often: CCR became MOTV3, Arezzo became AZZA3,
CTEEP became ISAE3, Eletrobras became AXIA3, Embraer became EMBJ3.
For a while this database only knew today's code, so a renamed company lost its
entire earlier price series — and the point-in-time price lookup, which had no
upper bound, "fell forward" until it found a session: Embraer's 2010 P/E came
out computed with a 2025 price. It affected 22% of the multiples rows. See
/metodologia/setores for the full post-mortem.
What fixes it, and what does not. The obvious idea — match on ISIN, as we do
for REITs — does not work for stocks: the Brazilian ISIN embeds the four
letters of the ticker and changes along with it. ELET3/BRELETACNOR6 became
AXIA3/BRAXIAACNOR0; ARZZ3/BRARZZACNOR3 became AZZA3/BRAZZAACNOR9. The ISIN
is not the stable identity it appears to be.
What does work is the FCA read year by year: each annual filing carries the
code in force that year for the same tax ID, and the sequence of filings
reconstructs the timeline (FCA 2024: CCRO3 · FCA 2025: MOTV3). Official CVM
source, point-in-time by construction.
Two rules come with it:
- Share classes are never spliced. Only codes of the same class as today's main ticker are used. Azul traded as AZUL4 (preferred) and today has AZUL3 (ordinary); splicing the two would give a series that switches instrument midway, and the return computed on it would not belong to anything anyone could have bought and held.
- In the transition week, the current code wins. When old and new coexist, there is one price per day — the main ticker's — not whichever line appears last in the file.
Declared limitation: the FCA's Codigo_Negociacao column is only populated
from 2018 onward. Before that the file exists, the rows are there, and the
field is blank. A rename earlier than 2018 is not recoverable this way. Every
one we know of is later, but the limit is written down rather than assumed.
Where the share count comes from (and why coverage thins going back)
Market cap needs two ends: a price and a share count. The second comes from two CVM sources, in this order of preference:
composicao_capitalfrom the annual/quarterly filings — carries shares issued and held in treasury, so it gives the exact free count. It only exists from 2020: in the 2012, 2016 and 2019 archives the file is not there.capital_socialfrom the FRE (reference form) — exists since 2010. It carries shares issued by type of capital; we use Capital Emitido, the shares that actually exist (not authorized capital, which is a bylaw ceiling nobody holds).
While only the first was used, P/E, P/BV and EV/EBITDA started in 2019. With the FRE they start in 2010 — and Embraer, which had recovered 16 years of prices and no multiples at all, now has both.
What the FRE does not carry, declared: treasury stock. That block is sparse
(39 rows in 2016, against 402 companies in the capital block). A row from the
FRE stores treasury as null — null, not zero, because we do not know it is
zero — and the multiple carries the acoes_do_fre_sem_tesouraria flag. Where a
company has really bought back stock, this slightly overstates the share count
and the market cap. When both sources exist for the same date, the filing wins.
Point-in-time here too. The window uses the date the number became
public (DT_RECEB from the form's cover), not the period it refers to. A
balance sheet dated 31 March only becomes information in May; pairing an April
price with the 31-March count would be using data the market did not yet have —
the same kind of error as the multiple's price, on a smaller scale. Fixed along
the way.
Plausibility gate. The FRE is a free-text field filled in by the company,
and it contains order-of-magnitude garbage: Ferrovia Centro-Atlântica declares
210 trillion shares, Ampla 3.9 trillion. That produced a market cap of
R$ 180 trillion — fifteen times Brazil's GDP — and invariant I-E04 blocked
publication. The yardstick for rejecting is the company's own book equity,
which is independent of the share count: a listed company trades between a
fraction and a few dozen times book, and outside [0.02x, 50x] that is not a
market valuation, it is a wrong count. The band is deliberately very wide — it
does not judge whether a stock is expensive, it detects impossible orders of
magnitude. 38 rows were left out by this gate, with no market cap and the reason
in the acoes_implausiveis flag.
Coverage, year by year
Multiples exist from 2010 to today, but not for every company in every
year — and the /transparencia page shows the exact count, refreshed at every
publication, next to the indicators column (which does not depend on price and
covers the whole series). In 2010 that is ~30 companies with multiples against
~264 with indicators; in 2024, ~267 against ~426.
The gap between the two columns is a source limit, not an ingestion hole: the further back the form, the fewer companies filed it in a usable format. We would rather show the curve than let the reader assume the blank is our carelessness.
Declared locks (each one becomes a flag)
- No
DT_RECEBor no trading session from there on: multiple not computed, flagsem_data_publicacao/sem_preco_apos_publicacao. - No shares outstanding:
sem_acoes_em_circulacao. - Profit ≤ 0: P/E is published anyway (a real number, not hidden), with flag
pl_negativo— a negative P/E is not comparable to the P/E of a profitable company, but it is information, not an error. - Shareholders' equity attributable to controlling shareholders ≤ 0: P/BV is not
published (
pl_nao_positivo) — dividing by negative equity has no direct economic reading. |P/L| > 200or|P/VP| > 50: published with flagpl_extremo/pvp_extremo— across 402 companies this is almost always a tiny profit or a tiny equity (a company in bankruptcy reorganization, distressed post-crisis), not an arithmetic error.
Source and licensing
Price: COTAHIST (B3), historical end-of-day series — free distribution
confirmed in B3's commercial policy (items 7.9/7.10), at no cost and with no
contract. Ticker: CVM's FCA (ODbL). No real-time quote source is used or
redistributed.
Quarterly multiples (TTM P/E and P/BV)
Same point-in-time discipline, anchored on the DT_RECEB of each quarter's
ITR:
- TTM profit (last 12 months) by identity, without estimating the 4th
quarter:
TTM at Qk = annual(year−1) − [Q1..Qk of (year−1)] + [Q1..Qk of (year)]. If any piece is missing (the prior annual or a quarter), the TTM is left NULL with a flag (ttm_sem_anual_anterior/ttm_sem_trimestre_...) — never interpolated. - TTM P/E = Market cap on the price date / TTM profit.
- P/BV = Market cap / shareholders' equity attributable to controlling shareholders from that same quarter's balance sheet (the quarterly balance sheet is a snapshot, not a flow).
- Shares outstanding: the most recent snapshot of
composicao_capital(capital composition, fromDFPandITR) up to the price date — never a future snapshot, and never the prior year's count when the quarter's count exists: a stock split mid-year would silently break the market cap. A snapshot older than 200 days relative to the price gets flagacoes_defasadas. - Quarterly EV/EBITDA DOES NOT EXIST in this database, on purpose: the cash
flow statement in the
ITRcomes only cumulative (measured across the whole universe: isolated quarterly D&A exists in ~4,200 company-years in Q1, but only ~35 in Q2 and ~16 in Q3 — Q1 exists because isolated and cumulative coincide). Without isolated D&A there is no quarterly EBITDA without an estimate, and this database does not estimate. EV/EBITDA stays annual.
Declared limitations
- 402 companies in the universe, ~304 with a resolved ticker (the rest have no eligible exchange-listed class in CVM's most recent registry — delisted, debt only, or never traded a share).
- The TTM profit mixes profit attributable to controlling shareholders with
consolidated profit when some period reports only the total — the flag
lucro_total_sem_minoritariosaccompanies the number when that happens.