aboutsummaryrefslogtreecommitdiff
path: root/components/financials.py
blob: 547aedb4be3b0e650d6001fa1321b2916f8d42ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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)