diff options
| author | Tyler <tyler@tylerhoang.xyz> | 2026-03-28 23:01:14 -0700 |
|---|---|---|
| committer | Tyler <tyler@tylerhoang.xyz> | 2026-03-28 23:01:14 -0700 |
| commit | 23675b39b8055a8568cdcf71f66482b9d0cf90a9 (patch) | |
| tree | 14e42cf710b47072e904b1c21d7322352ae1823c /components/overview.py | |
Initial commit — Prism financial analysis dashboard
Streamlit app with market bar, price chart, financial statements,
DCF valuation engine, comparable companies, and news feed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'components/overview.py')
| -rw-r--r-- | components/overview.py | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/components/overview.py b/components/overview.py new file mode 100644 index 0000000..7407753 --- /dev/null +++ b/components/overview.py @@ -0,0 +1,97 @@ +"""Company overview — header, key stats, and price chart.""" +import streamlit as st +import plotly.graph_objects as go +from services.data_service import get_company_info, get_price_history +from utils.formatters import fmt_large, fmt_currency, fmt_pct, fmt_ratio + + +PERIODS = {"1 Month": "1mo", "3 Months": "3mo", "6 Months": "6mo", "1 Year": "1y", "5 Years": "5y"} + + +def render_overview(ticker: str): + info = get_company_info(ticker) + if not info: + st.error(f"Could not load data for **{ticker}**. Check the ticker symbol.") + return + + # ── Company header ────────────────────────────────────────────────────── + name = info.get("longName") or info.get("shortName", ticker.upper()) + price = info.get("currentPrice") or info.get("regularMarketPrice") + prev_close = info.get("regularMarketPreviousClose") or info.get("previousClose") + + price_change = None + price_change_pct = None + if price and prev_close: + price_change = price - prev_close + price_change_pct = price_change / prev_close + + col1, col2 = st.columns([3, 1]) + with col1: + st.subheader(f"{name} ({ticker.upper()})") + sector = info.get("sector", "") + industry = info.get("industry", "") + if sector: + st.caption(f"{sector} · {industry}") + + with col2: + delta_str = None + if price_change is not None and price_change_pct is not None: + delta_str = f"{price_change:+.2f} ({price_change_pct * 100:+.2f}%)" + st.metric( + label="Price", + value=fmt_currency(price) if price else "—", + delta=delta_str, + ) + + # ── Key stats strip ───────────────────────────────────────────────────── + stats_cols = st.columns(6) + stats = [ + ("Mkt Cap", fmt_large(info.get("marketCap"))), + ("P/E (TTM)", fmt_ratio(info.get("trailingPE"))), + ("EPS (TTM)", fmt_currency(info.get("trailingEps"))), + ("52W High", fmt_currency(info.get("fiftyTwoWeekHigh"))), + ("52W Low", fmt_currency(info.get("fiftyTwoWeekLow"))), + ("Beta", fmt_ratio(info.get("beta"))), + ] + for col, (label, val) in zip(stats_cols, stats): + col.metric(label, val) + + st.divider() + + # ── Price chart ───────────────────────────────────────────────────────── + period_label = st.radio( + "Period", + options=list(PERIODS.keys()), + index=3, + horizontal=True, + label_visibility="collapsed", + ) + period = PERIODS[period_label] + + hist = get_price_history(ticker, period=period) + if hist.empty: + st.warning("No price history available.") + return + + fig = go.Figure() + fig.add_trace( + go.Scatter( + x=hist.index, + y=hist["Close"], + mode="lines", + name="Close", + line=dict(color="#4F8EF7", width=2), + fill="tozeroy", + fillcolor="rgba(79, 142, 247, 0.08)", + ) + ) + fig.update_layout( + margin=dict(l=0, r=0, t=10, b=0), + xaxis=dict(showgrid=False, zeroline=False), + yaxis=dict(showgrid=True, gridcolor="rgba(255,255,255,0.05)", zeroline=False), + plot_bgcolor="rgba(0,0,0,0)", + paper_bgcolor="rgba(0,0,0,0)", + hovermode="x unified", + height=320, + ) + st.plotly_chart(fig, use_container_width=True) |
