From 712bbf675cfcb32535d8c494505e566efa347feb Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 30 Mar 2026 18:54:56 -0700 Subject: Fix EV/EBITDA using income statement EBITDA instead of info dict yfinance's info["ebitda"] is a miscalculated TTM value for many tickers (e.g. DDOG shows $7.5M when the correct TTM EBITDA is $193.8M). Added get_ebitda_from_income_stmt() which reads directly from t.income_stmt, matching the annual and quarterly figures. Key Ratios and DCF EV/EBITDA valuation now both use this source, with FMP as the preferred override. Co-Authored-By: Claude Sonnet 4.6 --- components/valuation.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'components/valuation.py') diff --git a/components/valuation.py b/components/valuation.py index b6e9d46..a168580 100644 --- a/components/valuation.py +++ b/components/valuation.py @@ -9,6 +9,7 @@ from services.data_service import ( get_recommendations_summary, get_earnings_history, get_next_earnings_date, + get_ebitda_from_income_stmt, ) from services.fmp_service import ( get_key_ratios, @@ -148,13 +149,26 @@ def _render_ratios(ticker: str): val = info.get(yf_key) return fmt(val) if val is not None else "—" + # Compute EV/EBITDA from income statement EBITDA — yfinance's info["ebitda"] + # is a known bad value for many tickers (miscalculated TTM aggregation). + def _ev_ebitda() -> str: + # Prefer FMP if available + fmp_val = (ratios or {}).get("enterpriseValueMultipleTTM") or (ratios or {}).get("evToEBITDATTM") + if fmp_val is not None: + return fmt_ratio(fmp_val) + ev = info.get("enterpriseValue") + ebitda = get_ebitda_from_income_stmt(ticker) + if ev and ebitda and ebitda > 0: + return fmt_ratio(ev / ebitda) + return "—" + rows = [ ("Valuation", [ ("P/E (TTM)", r("peRatioTTM", "trailingPE")), ("Forward P/E", fmt_ratio(info.get("forwardPE")) if info.get("forwardPE") is not None else "—"), ("P/S (TTM)", r("priceToSalesRatioTTM", "priceToSalesTrailing12Months")), ("P/B", r("priceToBookRatioTTM", "priceToBook")), - ("EV/EBITDA", r("enterpriseValueMultipleTTM", "enterpriseToEbitda") if ratios.get("enterpriseValueMultipleTTM") is not None else r("evToEBITDATTM", "enterpriseToEbitda")), + ("EV/EBITDA", _ev_ebitda()), ("EV/Revenue", r("evToSalesTTM", "enterpriseToRevenue")), ]), ("Profitability", [ @@ -315,7 +329,8 @@ def _render_dcf(ticker: str): st.divider() st.markdown("**EV/EBITDA Valuation**") - ebitda = info.get("ebitda") + # Use income statement EBITDA — info["ebitda"] is unreliable in yfinance + ebitda = get_ebitda_from_income_stmt(ticker) or info.get("ebitda") total_debt = info.get("totalDebt") or 0.0 total_cash = info.get("totalCash") or 0.0 ev_ebitda_current = info.get("enterpriseToEbitda") -- cgit v1.3-2-g0d8e