diff options
Diffstat (limited to 'components/financials.py')
| -rw-r--r-- | components/financials.py | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/components/financials.py b/components/financials.py new file mode 100644 index 0000000..547aedb --- /dev/null +++ b/components/financials.py @@ -0,0 +1,82 @@ +"""Financial statements — Income Statement, Balance Sheet, Cash Flow.""" +import pandas as pd +import streamlit as st +from services.data_service import get_income_statement, get_balance_sheet, get_cash_flow +from utils.formatters import fmt_large + + +def _format_statement(df: pd.DataFrame) -> pd.DataFrame: + """Format a yfinance financial statement for display.""" + if df.empty: + return df + + # Columns are datetime; convert to year strings + df = df.copy() + df.columns = [str(c)[:10] for c in df.columns] + + # Add YoY % change columns if >= 2 periods + cols = list(df.columns) + result = pd.DataFrame(index=df.index) + + for i, col in enumerate(cols): + result[col] = df[col].apply(_fmt_cell) + if i + 1 < len(cols): + prev_col = cols[i + 1] + yoy = df.apply( + lambda row: _yoy_pct(row[col], row[prev_col]), axis=1 + ) + result[f"YoY {col[:4]}"] = yoy + + return result + + +def _fmt_cell(value) -> str: + try: + v = float(value) + except (TypeError, ValueError): + return "—" + return fmt_large(v) + + +def _yoy_pct(current, previous) -> str: + try: + c, p = float(current), float(previous) + if p == 0: + return "—" + pct = (c - p) / abs(p) * 100 + arrow = "▲" if pct >= 0 else "▼" + return f"{arrow} {abs(pct):.1f}%" + except (TypeError, ValueError): + return "—" + + +def render_financials(ticker: str): + col1, col2 = st.columns([1, 3]) + with col1: + freq = st.radio("Frequency", ["Annual", "Quarterly"], horizontal=False) + quarterly = freq == "Quarterly" + + tab_income, tab_balance, tab_cashflow = st.tabs( + ["Income Statement", "Balance Sheet", "Cash Flow"] + ) + + with tab_income: + df = get_income_statement(ticker, quarterly=quarterly) + if df.empty: + st.info("Income statement data unavailable.") + else: + st.dataframe(_format_statement(df), use_container_width=True) + + with tab_balance: + df = get_balance_sheet(ticker, quarterly=quarterly) + if df.empty: + st.info("Balance sheet data unavailable.") + else: + st.dataframe(_format_statement(df), use_container_width=True) + + with tab_cashflow: + df = get_cash_flow(ticker, quarterly=quarterly) + if df.empty: + st.info("Cash flow data unavailable.") + else: + st.dataframe(_format_statement(df), use_container_width=True) |
