
Every provider reports a different P/E and hides the formula, I open-sourced one where all 200+ metrics show their math
Run a factor backtest on fundamental signals and your historical P/E series often won't match what you'd actually have seen at the time. The usual cause: trailing-twelve-month vs fiscal-year-end earnings, diluted vs basic shares, different treatment of extraordinary items. Most providers don't document which they use. For example, Microsoft's PE ratio on the 6th of May, 2023 is reported to be 28.93 (Stockopedia), 32.05 (Morningstar), 32.66 (Macrotrends), 33.09 (Finance Charts), 33.66 (Y Charts), 33.67 (Wall Street Journal), 33.80 (Yahoo Finance) and 34.4 (Companies Market Cap). Whereas I report it at 32.07 (diluted), 31.96 (non-diluted), 30.07 (TTM diluted) and 29.93 (TTM non-diluted).
So that's why I open-sourced the math. The P/E, for example, is as simple as stock_price / earnings_per_share where Earnings per Share is (net_income - preferred_dividends) / average_outstanding_shares. There is a layer on top to also be able to work with trailing, TTM and growth rates for any metric which is also documented. This makes it so you can reproduce any provider's P/E if you know which definition they used (albeit that is often the issue..)
Same idea when it comes to any other metrics let it be fundamentals, technicals, risk, performance etc. (about 200). Here's CAPM, VaR and Max Drawdown for NVDA, AMD and INTC at five-year intervals since 2000:
# Install first: pip install financetoolkit -U
from financetoolkit import Toolkit
semis = Toolkit(["NVDA", "AMD", "INTC"], api_key="FMP_KEY", start_date="2000-01-01")
capm = semis.performance.get_capital_asset_pricing_model(period="yearly")
var = semis.risk.get_value_at_risk(period="yearly")
mdd = semis.risk.get_maximum_drawdown(period="yearly")
CAPM (expected annual return):
| Year | NVDA | AMD | INTC |
|---|---|---|---|
| 2010 | 16.9% | 20.2% | 13.7% |
| 2015 | -1.3% | -1.3% | -0.8% |
| 2020 | 21.6% | 19.0% | 18.9% |
| 2025 | 27.0% | 29.2% | 22.9% |
VaR (95% historic, worst expected daily loss):
| Year | NVDA | AMD | INTC |
|---|---|---|---|
| 2010 | -4.8% | -5.0% | -2.7% |
| 2015 | -2.7% | -5.2% | -2.3% |
| 2020 | -5.7% | -5.4% | -4.2% |
| 2025 | -4.5% | -5.4% | -5.3% |
Max Drawdown (peak-to-trough within year):
| Year | NVDA | AMD | INTC |
|---|---|---|---|
| 2010 | -53.0% | -44.8% | -27.1% |
| 2015 | -17.7% | -51.1% | -29.9% |
| 2020 | -37.6% | -34.3% | -35.6% |
| 2025 | -36.9% | -39.6% | -33.8% |
The whole point is to make things more transparent and with creating models, that is especially relevant that the metric you're training on is actually how you envision the metric to be.
While the library uses Financial Modeling Prep and Yahoo Finance as a default source, I've added in logic so you can swap in your own data provider or even a local CSV to not be provider-dependent. This way it should really become auditable for your backtests. The library is MIT-licensed, so you can use it in your own projects without restriction.