aboutsummaryrefslogtreecommitdiff
path: root/services/data_service.py
diff options
context:
space:
mode:
authorTyler <tyler@tylerhoang.xyz>2026-03-30 18:54:56 -0700
committerTyler <tyler@tylerhoang.xyz>2026-03-30 18:54:56 -0700
commit712bbf675cfcb32535d8c494505e566efa347feb (patch)
tree539a874eab3c785e2a8ba9209939bdb3fb4ee978 /services/data_service.py
parentaa3b1a27118ef0efac056ad135a81181bfb15c8e (diff)
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 <noreply@anthropic.com>
Diffstat (limited to 'services/data_service.py')
-rw-r--r--services/data_service.py22
1 files changed, 22 insertions, 0 deletions
diff --git a/services/data_service.py b/services/data_service.py
index 3de2484..acc935f 100644
--- a/services/data_service.py
+++ b/services/data_service.py
@@ -158,6 +158,28 @@ def get_insider_transactions(ticker: str) -> pd.DataFrame:
return pd.DataFrame()
+@st.cache_data(ttl=3600)
+def get_ebitda_from_income_stmt(ticker: str) -> float | None:
+ """Return the most recent annual EBITDA from the income statement.
+
+ yfinance's info['ebitda'] can be badly wrong for companies with large
+ stock-based compensation (e.g. it may deduct SBC, leaving near-zero EBITDA
+ even when the income statement EBITDA line is hundreds of millions).
+ The income statement 'EBITDA' row is the standard EBIT + D&A figure.
+ """
+ try:
+ t = yf.Ticker(ticker.upper())
+ inc = t.income_stmt
+ for label in ("EBITDA", "Normalized EBITDA"):
+ if label in inc.index:
+ val = inc.loc[label].iloc[0]
+ if val is not None and pd.notna(val):
+ return float(val)
+ return None
+ except Exception:
+ return None
+
+
@st.cache_data(ttl=900)
def get_options_chain(ticker: str) -> dict:
"""Return options chain data for the nearest available expirations.