diff options
| author | Tyler <tyler@tylerhoang.xyz> | 2026-03-29 00:52:25 -0700 |
|---|---|---|
| committer | Tyler <tyler@tylerhoang.xyz> | 2026-03-29 00:52:25 -0700 |
| commit | ad6b0b59c2a4f557d6d9d7fe9810c2ba7627580d (patch) | |
| tree | 7654f25a29d8900dfe52e5f36c371ec6162c07a0 /services/data_service.py | |
| parent | 91037dec4e714e31416d8c06eec824a7287fef00 (diff) | |
Add EV/EBITDA valuation, analyst targets, earnings history, and FCF growth override
- DCF model: user-adjustable FCF growth rate slider (defaults to historical median)
- EV/EBITDA valuation section with target multiple slider and implied price
- Analyst Targets tab: price target summary + recommendation breakdown chart
- Earnings History tab: EPS actual vs estimate table and line chart with next earnings date
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'services/data_service.py')
| -rw-r--r-- | services/data_service.py | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/services/data_service.py b/services/data_service.py index fa9b026..0399c58 100644 --- a/services/data_service.py +++ b/services/data_service.py @@ -92,6 +92,60 @@ def get_market_indices() -> dict: @st.cache_data(ttl=3600) +def get_analyst_price_targets(ticker: str) -> dict: + """Return analyst price target summary (keys: current, high, low, mean, median).""" + try: + t = yf.Ticker(ticker.upper()) + data = t.analyst_price_targets + return data if isinstance(data, dict) and data else {} + except Exception: + return {} + + +@st.cache_data(ttl=3600) +def get_recommendations_summary(ticker: str) -> pd.DataFrame: + """Return analyst recommendation counts by period. + Columns: period, strongBuy, buy, hold, sell, strongSell. + Row with period='0m' is the current month. + """ + try: + t = yf.Ticker(ticker.upper()) + df = t.recommendations_summary + return df if df is not None and not df.empty else pd.DataFrame() + except Exception: + return pd.DataFrame() + + +@st.cache_data(ttl=3600) +def get_earnings_history(ticker: str) -> pd.DataFrame: + """Return historical EPS actual vs estimate. + Columns: epsActual, epsEstimate, epsDifference, surprisePercent. + """ + try: + t = yf.Ticker(ticker.upper()) + df = t.earnings_history + return df if df is not None and not df.empty else pd.DataFrame() + except Exception: + return pd.DataFrame() + + +@st.cache_data(ttl=3600) +def get_next_earnings_date(ticker: str) -> str | None: + """Return the next expected earnings date as a string, or None. + Uses t.calendar (no lxml dependency). + """ + try: + t = yf.Ticker(ticker.upper()) + cal = t.calendar + dates = cal.get("Earnings Date", []) + if dates: + return str(dates[0]) + return None + except Exception: + return None + + +@st.cache_data(ttl=3600) def get_free_cash_flow_series(ticker: str) -> pd.Series: """Return annual Free Cash Flow series (most recent first).""" t = yf.Ticker(ticker.upper()) |
