pvyas96 commited on
Commit
0977ccb
Β·
verified Β·
1 Parent(s): 4a31363

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -127
app.py CHANGED
@@ -1,129 +1,91 @@
1
  import streamlit as st
2
  import plotly.graph_objects as go
3
- from src.utils import StockAnalyzer
4
-
5
- st.set_page_config(page_title="Fundamental Analyzer", page_icon="πŸ“ˆ", layout="wide")
6
-
7
- # Use cache_resource to keep the network session alive for 1 hour (3600s)
8
- @st.cache_resource(ttl=3600)
9
- def get_analyzer(ticker):
10
- # This will only run if the ticker changes or the cache expires
11
- return StockAnalyzer(ticker)
12
-
13
- # --- SIDEBAR & CACHE MANAGEMENT ---
14
- with st.sidebar:
15
- st.header("Search")
16
- ticker_input = st.text_input("Ticker Symbol", value="RELIANCE.NS").upper()
17
- st.caption("Examples: TCS, INFY, AAPL")
18
- st.info("Data provided by Yahoo Finance")
19
-
20
- # NEW: Button to clear the cache and force a fresh data fetch
21
- if st.button("Refresh Data", type="primary"):
22
- st.cache_resource.clear()
23
- st.experimental_rerun()
24
-
25
- if ticker_input:
26
- try:
27
- with st.spinner(f"Fetching data for {ticker_input}..."):
28
- analyzer = get_analyzer(ticker_input)
29
- summary = analyzer.get_summary_metrics()
30
-
31
- # Check if we actually got valid data back
32
- if not summary.get('current_price'):
33
- st.error(f"Could not load data for **{ticker_input}**. Ticker might be invalid, delisted, or Yahoo Finance data is temporarily unavailable.")
34
- else:
35
- # --- HEADER ---
36
- st.title(f"{analyzer.info.get('shortName', ticker_input)}")
37
- st.markdown(f"**Sector:** {summary['sector']} | **Industry:** {summary['industry']}")
38
-
39
- # --- METRICS ---
40
- c1, c2, c3, c4 = st.columns(4)
41
- curr = summary.get('currency', 'USD')
42
-
43
- def fmt(val):
44
- if not val: return "N/A"
45
- # Use a cleaner way to format large numbers
46
- if abs(val) >= 1e12: return f"{val/1e12:.2f}T"
47
- if abs(val) >= 1e9: return f"{val/1e9:.2f}B"
48
- if abs(val) >= 1e6: return f"{val/1e6:.2f}M"
49
- return f"{val:,.0f}"
50
-
51
- c1.metric("Price", f"{summary['current_price']} {curr}")
52
- c2.metric("Market Cap", f"{fmt(summary['market_cap'])} {curr}")
53
- # Ensure P/E handles N/A gracefully
54
- pe_display = f"{summary['pe_ratio']:.2f}" if summary['pe_ratio'] and summary['pe_ratio'] > 0 else "N/A"
55
- c3.metric("P/E", pe_display)
56
-
57
- # Safe Dividend Yield Handling
58
- div_yield = summary.get('dividend_yield')
59
- div_display = f"{div_yield*100:.2f}%" if div_yield is not None else "0%"
60
- c4.metric("Div Yield", div_display)
61
-
62
- # --- TABS ---
63
- tab1, tab2, tab3 = st.tabs(["Charts", "Health Check", "Profile"])
64
-
65
- with tab1:
66
- df = analyzer.get_financial_trends()
67
- if not df.empty:
68
- # NEW: Chart data is converted to Billions for cleaner display
69
- df_billions = df.copy()
70
- for col in ['Revenue', 'Net Income', 'Operating Cash Flow', 'Free Cash Flow']:
71
- if col in df_billions:
72
- # Divide by 1 Billion (1e9)
73
- df_billions[col] = df_billions[col] / 1e9
74
-
75
- # Chart 1: Revenue vs Net Income
76
- st.subheader("Revenue vs Profit Trend (in Billions)")
77
- fig = go.Figure()
78
- if 'Revenue' in df_billions:
79
- fig.add_trace(go.Bar(x=df_billions.index.year, y=df_billions['Revenue'], name='Revenue', marker_color='#37536d'))
80
- if 'Net Income' in df_billions:
81
- fig.add_trace(go.Bar(x=df_billions.index.year, y=df_billions['Net Income'], name='Net Income', marker_color='#1a76ff'))
82
- # Updated Y-axis title
83
- fig.update_layout(barmode='group', yaxis_title=f"{curr} (in Billions)")
84
- st.plotly_chart(fig, use_container_width=True)
85
-
86
- # Chart 2: Cash Flow
87
- st.subheader("Cash Flow Analysis (in Billions)")
88
- fig2 = go.Figure()
89
- if 'Operating Cash Flow' in df_billions:
90
- fig2.add_trace(go.Bar(x=df_billions.index.year, y=df_billions['Operating Cash Flow'], name='Operating CF', marker_color='#00CC96'))
91
- if 'Free Cash Flow' in df_billions:
92
- fig2.add_trace(go.Bar(x=df_billions.index.year, y=df_billions['Free Cash Flow'], name='Free CF', marker_color='#EF553B'))
93
- # Updated Y-axis title
94
- fig2.update_layout(barmode='group', yaxis_title=f"{curr} (in Billions)")
95
- st.plotly_chart(fig2, use_container_width=True)
96
- else:
97
- st.warning("Financial history is unavailable for this ticker. Check if the ticker is correct.")
98
-
99
- with tab2:
100
- c1, c2 = st.columns(2)
101
- with c1:
102
- st.subheader("Key Health Flags")
103
- flags = analyzer.check_red_flags()
104
- if flags:
105
- for f in flags:
106
- if f['type'] == 'danger': st.error(f"❌ {f['msg']}")
107
- elif f['type'] == 'warning': st.warning(f"⚠️ {f['msg']}")
108
- else: st.success(f"βœ… {f['msg']}")
109
- else:
110
- st.info("No flags calculated (insufficient data).")
111
-
112
- with c2:
113
- st.subheader("Piotroski F-Score (9-Point Check)")
114
- score, details = analyzer.calculate_piotroski_score()
115
- color = "red" if score < 4 else "green" if score > 6 else "orange"
116
- st.markdown(f"<h1 style='color:{color}'>{score}/9</h1>", unsafe_allow_html=True)
117
- with st.expander("Score Breakdown (F1-F9)"):
118
- for d in details: st.write(d)
119
-
120
- with tab3:
121
- st.subheader(f"About {analyzer.info.get('shortName', ticker_input)}")
122
- st.write(summary['summary'])
123
- st.markdown(f"**Website:** [Visit Company Site]({summary['website']})")
124
-
125
- except Exception as e:
126
- # Catch connection and broader Streamlit exceptions
127
- st.error(f"A critical error occurred while processing the data: {str(e)}. Please check your network connection or try a different ticker.")
128
-
129
- # End of app.py
 
1
  import streamlit as st
2
  import plotly.graph_objects as go
3
+ from utils import fetch_financials, clean_financials
4
+
5
+ def plot_income(income_df, ticker_symbol):
6
+ fig = go.Figure()
7
+
8
+ # List of metrics we want to plot β€” change as per availability
9
+ metrics = [
10
+ "Total Revenue",
11
+ "Net Income Available to Common Shares"
12
+ ]
13
+
14
+ for m in metrics:
15
+ if m in income_df.columns:
16
+ fig.add_trace(go.Bar(
17
+ x=income_df.index,
18
+ y=income_df[m] / 1e9, # convert to billions
19
+ name=m
20
+ ))
21
+
22
+ fig.update_layout(
23
+ title=f"{ticker_symbol} Income Statement",
24
+ xaxis_title="Date",
25
+ yaxis_title="Value (in billions)",
26
+ barmode='group'
27
+ )
28
+ return fig
29
+
30
+ def plot_cashflow(cash_df, ticker_symbol):
31
+ fig = go.Figure()
32
+
33
+ metrics = [
34
+ "Total Cash From Operating Activities",
35
+ "Capital Expenditures",
36
+ ]
37
+
38
+ for m in metrics:
39
+ if m in cash_df.columns:
40
+ vals = cash_df[m]
41
+ # If CapEx, often negative -> make positive for bar
42
+ if "Capital Expenditures" in m:
43
+ vals = -vals
44
+ fig.add_trace(go.Bar(
45
+ x=cash_df.index,
46
+ y=vals / 1e9,
47
+ name=m
48
+ ))
49
+
50
+ fig.update_layout(
51
+ title=f"{ticker_symbol} Cash Flow Statement",
52
+ xaxis_title="Date",
53
+ yaxis_title="Value (in billions)",
54
+ barmode='group'
55
+ )
56
+ return fig
57
+
58
+
59
+ def main():
60
+ st.title("Financial Dashboard")
61
+
62
+ ticker_symbol = st.text_input("Ticker Symbol", "AAPL")
63
+
64
+ if st.button("Refresh Data"):
65
+ with st.spinner("Fetching data..."):
66
+ income, cash = fetch_financials(ticker_symbol, freq="annual")
67
+
68
+ if income.empty and cash.empty:
69
+ st.error("No financial data returned. Check ticker or try again.")
70
+ return
71
+
72
+ income_clean = clean_financials(income)
73
+ cash_clean = clean_financials(cash)
74
+
75
+ st.subheader("Income Statement")
76
+ fig_income = plot_income(income_clean, ticker_symbol)
77
+ st.plotly_chart(fig_income, use_container_width=True)
78
+
79
+ st.subheader("Cash Flow")
80
+ fig_cash = plot_cashflow(cash_clean, ticker_symbol)
81
+ st.plotly_chart(fig_cash, use_container_width=True)
82
+
83
+ st.write("### Raw Data β€” Income Statement")
84
+ st.dataframe(income_clean)
85
+
86
+ st.write("### Raw Data β€” Cash Flow")
87
+ st.dataframe(cash_clean)
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()