aboutsummaryrefslogtreecommitdiff
path: root/components/financials.py
diff options
context:
space:
mode:
Diffstat (limited to 'components/financials.py')
-rw-r--r--components/financials.py82
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)