CCockrum commited on
Commit
40a48fb
·
verified ·
1 Parent(s): c7fe441

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -126
app.py CHANGED
@@ -1,17 +1,16 @@
1
- import pandas as pd
2
- import numpy as np
3
  import gradio as gr
4
- import matplotlib.pyplot as plt
5
  import requests
6
- import os
7
- from transformers import pipeline
8
  import datetime
9
  import tempfile
 
 
10
 
11
- # Initialize Summarizer
12
  summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
 
13
 
14
- # Polygon API Key
15
  POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")
16
 
17
  # Sector Averages
@@ -22,67 +21,60 @@ sector_averages = {
22
  "Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
23
  }
24
 
25
- # Helper Functions
 
 
 
 
 
 
 
26
 
 
27
  def safe_request(url):
28
  try:
29
  response = requests.get(url)
30
  response.raise_for_status()
31
  return response
32
- except requests.exceptions.HTTPError as http_err:
33
- print(f"DEBUG: HTTP error occurred: {http_err}")
34
- except Exception as err:
35
- print(f"DEBUG: Other error occurred: {err}")
36
- return None
37
-
38
 
39
  def get_company_info(symbol):
40
- api_key = os.getenv("POLYGON_API_KEY")
41
- if not api_key:
42
- print("DEBUG: API Key is missing!")
43
- return None
44
- url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={api_key}"
45
  response = safe_request(url)
46
  if response:
47
  data = response.json().get('results', {})
 
 
 
 
48
  return {
49
  'Name': data.get('name', 'N/A'),
50
  'Industry': data.get('sic_description', 'N/A'),
51
- 'Sector': data.get('market', 'N/A'),
52
  'Market Cap': data.get('market_cap', 0),
53
  'Total Revenue': data.get('total_employees', 0) * 100000
54
  }
55
  return None
56
 
57
-
58
  def get_current_price(symbol):
59
- api_key = os.getenv("POLYGON_API_KEY")
60
- url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={api_key}"
61
  response = safe_request(url)
62
  if response:
63
- data = response.json()['results'][0]
64
- return float(data['c'])
65
  return None
66
 
67
-
68
  def get_dividends(symbol):
69
- api_key = os.getenv("POLYGON_API_KEY")
70
- url = f"https://api.polygon.io/v3/reference/dividends?ticker={symbol}&apiKey={api_key}"
71
  response = safe_request(url)
72
  if response:
73
- data = response.json()['results'][0]
74
- return {
75
- 'Dividend Amount': data.get('cash_amount', 0),
76
- 'Ex-Dividend Date': data.get('ex_dividend_date', 'N/A')
77
- }
78
- return {'Dividend Amount': 0, 'Ex-Dividend Date': 'N/A'}
79
-
80
 
81
  def get_historical_prices(symbol):
82
- api_key = os.getenv("POLYGON_API_KEY")
83
  end = datetime.date.today()
84
  start = end - datetime.timedelta(days=365)
85
- url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/{start}/{end}?adjusted=true&sort=asc&apiKey={api_key}"
86
  response = safe_request(url)
87
  if response:
88
  results = response.json()['results']
@@ -91,58 +83,18 @@ def get_historical_prices(symbol):
91
  return dates, prices
92
  return [], []
93
 
94
-
95
- def generate_summary(info, ratios):
96
- recommendation = "Hold"
97
- if ratios['P/E Ratio'] < 15 and ratios['P/B Ratio'] < 2 and ratios['PEG Ratio'] < 1.0 and ratios['Dividend Yield (%)'] > 2:
98
- recommendation = "Buy"
99
- elif ratios['P/E Ratio'] > 30 and ratios['P/B Ratio'] > 5 and ratios['PEG Ratio'] > 2.0:
100
- recommendation = "Sell"
101
-
102
- report = (
103
- f"Company Overview:\n"
104
- f"Name: {info['Name']}\n"
105
- f"Industry: {info['Industry']}\n"
106
- f"Sector: {info['Sector']}\n"
107
- f"Market Cap: ${info['Market Cap']:,.2f}\n\n"
108
- f"Financial Metrics:\n"
109
- f"P/E Ratio: {ratios['P/E Ratio']:.2f}\n"
110
- f"P/S Ratio: {ratios['P/S Ratio']:.2f}\n"
111
- f"P/B Ratio: {ratios['P/B Ratio']:.2f}\n"
112
- f"PEG Ratio: {ratios['PEG Ratio']:.2f}\n"
113
- f"Dividend Yield: {ratios['Dividend Yield (%)']:.2f}%\n\n"
114
- f"Recommended Investment Action: {recommendation}.\n\n"
115
- f"Please provide a detailed financial analysis based on the information above."
116
- )
117
- summary = summarizer(report, max_length=250, min_length=100, do_sample=False)[0]['summary_text']
118
- return summary
119
-
120
-
121
- def answer_investing_question(question):
122
- prompt = (
123
- f"Someone asked: '{question}'. "
124
- f"Please answer clearly, simply, and in a conversational tone without restating the question. "
125
- f"Keep the answer beginner-friendly and encouraging."
126
- )
127
- response = summarizer(prompt, max_length=200, min_length=60, do_sample=False)[0]['summary_text']
128
- return response
129
-
130
-
131
- # (Rest of the app continues with stock_research, download_report, and Gradio UI, including improved Valuation Ratios with sector ideal comparison and polished UI.)
132
-
133
-
134
- def calculate_ratios(market_cap, total_revenue, price, dividend_amount, assumed_eps=5.0, growth_rate=0.1, book_value=500000000):
135
- pe_ratio = price / assumed_eps if assumed_eps else 0
136
- ps_ratio = market_cap / total_revenue if total_revenue else 0
137
- pb_ratio = market_cap / book_value if book_value else 0
138
- peg_ratio = pe_ratio / (growth_rate * 100) if growth_rate else 0
139
- dividend_yield = (dividend_amount / price) * 100 if price else 0
140
  return {
141
- 'P/E Ratio': pe_ratio,
142
- 'P/S Ratio': ps_ratio,
143
- 'P/B Ratio': pb_ratio,
144
- 'PEG Ratio': peg_ratio,
145
- 'Dividend Yield (%)': dividend_yield
146
  }
147
 
148
  def compare_to_sector(sector, ratios):
@@ -158,7 +110,6 @@ def compare_to_sector(sector, ratios):
158
  "Sector Average": [],
159
  "Difference": []
160
  }
161
-
162
  for key in averages:
163
  stock_value = ratios.get(key, 0)
164
  sector_value = averages.get(key, 0)
@@ -167,59 +118,65 @@ def compare_to_sector(sector, ratios):
167
  data["Stock Value"].append(round(stock_value, 2))
168
  data["Sector Average"].append(round(sector_value, 2))
169
  data["Difference"].append(round(diff, 2))
170
-
171
  return pd.DataFrame(data)
172
 
173
- def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=500000000):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  info = get_company_info(symbol)
175
  price = get_current_price(symbol)
176
  dividends = get_dividends(symbol)
177
  dates, prices = get_historical_prices(symbol)
178
 
179
  if not info or not price:
180
- return "⚠️ Error: Could not fetch stock information. Please check your API Key or ticker.", None, None, None, None, None
181
 
182
- ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends['Dividend Amount'], assumed_eps, growth_rate, book_value)
183
  summary = generate_summary(info, ratios)
184
-
185
- # Apply fallback for sector
186
- sector = info.get('Sector', 'Technology')
187
- sector_comp = compare_to_sector(sector, ratios)
188
 
189
  fig, ax = plt.subplots()
190
- ax.plot(dates, prices, label=f"{symbol} Price")
191
- ax.set_title(f"{symbol} Historical Price (1 Year)")
192
  ax.set_xlabel("Date")
193
  ax.set_ylabel("Price ($)")
194
- ax.legend()
195
  ax.grid(True)
196
 
197
- info_table = pd.DataFrame({
198
- "Metric": list(info.keys()),
199
- "Value": [f"${v:,.0f}" if isinstance(v, (int, float)) and abs(v) > 1000 else v for v in info.values()]
200
- })
201
- ratios_table = pd.DataFrame({
202
- "Ratio": list(ratios.keys()),
203
- "Value": [f"{v:.3f}" if isinstance(v, float) else v for v in ratios.values()]
204
- })
205
 
206
  return summary, info_table, ratios_table, sector_comp, fig
207
 
208
- def download_report(info_table, ratios_table, sector_comp, summary):
209
- with tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode='w') as f:
210
- info_table.to_csv(f, index=False)
211
- f.write("\n")
212
- ratios_table.to_csv(f, index=False)
213
- f.write("\n")
214
- sector_comp.to_csv(f, index=False)
215
- f.write("\nSummary\n")
216
- f.write(summary)
217
- file_path = f.name
218
- return file_path
219
-
220
  # --- Gradio UI ---
221
-
222
- with gr.Blocks() as iface:
223
  with gr.Row():
224
  symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)")
225
  eps = gr.Number(label="Assumed EPS", value=5.0)
@@ -238,8 +195,8 @@ with gr.Blocks() as iface:
238
  with gr.Tab("Historical Price Chart"):
239
  output_chart = gr.Plot()
240
  with gr.Tab("Ask About Investing"):
241
- user_question = gr.Textbox(label="Ask a question about investing...")
242
- answer_box = gr.Textbox(label="Answer")
243
  ask_button = gr.Button("Get Answer")
244
  ask_button.click(fn=answer_investing_question, inputs=[user_question], outputs=[answer_box])
245
 
@@ -250,8 +207,17 @@ with gr.Blocks() as iface:
250
  submit_btn.click(fn=stock_research, inputs=[symbol, eps, growth, book],
251
  outputs=[output_summary, output_info, output_ratios, output_sector, output_chart])
252
 
253
- download_btn.click(fn=download_report, inputs=[output_info, output_ratios, output_sector, output_summary],
254
- outputs=file_output)
 
 
 
 
 
 
 
 
 
255
 
256
  if __name__ == "__main__":
257
  iface.launch()
 
 
 
1
  import gradio as gr
2
+ import pandas as pd
3
  import requests
 
 
4
  import datetime
5
  import tempfile
6
+ import os
7
+ from transformers import pipeline
8
 
9
+ # Initialize Models
10
  summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
11
+ chat_model = pipeline("text-generation", model="google/flan-t5-large", max_length=256)
12
 
13
+ # API Key
14
  POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")
15
 
16
  # Sector Averages
 
21
  "Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
22
  }
23
 
24
+ # Tooltip dictionary
25
+ tooltips = {
26
+ "P/E Ratio": "Price/Earnings: Lower can indicate better value.",
27
+ "P/S Ratio": "Price/Sales: Lower can indicate better value relative to sales.",
28
+ "P/B Ratio": "Price/Book: Lower can indicate undervaluation.",
29
+ "PEG Ratio": "Price/Earnings to Growth: Closer to 1 is ideal.",
30
+ "Dividend Yield": "Annual dividend income relative to price."
31
+ }
32
 
33
+ # Helper Functions
34
  def safe_request(url):
35
  try:
36
  response = requests.get(url)
37
  response.raise_for_status()
38
  return response
39
+ except:
40
+ return None
 
 
 
 
41
 
42
  def get_company_info(symbol):
43
+ url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={POLYGON_API_KEY}"
 
 
 
 
44
  response = safe_request(url)
45
  if response:
46
  data = response.json().get('results', {})
47
+ sector = data.get('market', 'Technology')
48
+ # Dynamic Guess
49
+ if sector.lower() == 'stocks':
50
+ sector = "Technology"
51
  return {
52
  'Name': data.get('name', 'N/A'),
53
  'Industry': data.get('sic_description', 'N/A'),
54
+ 'Sector': sector,
55
  'Market Cap': data.get('market_cap', 0),
56
  'Total Revenue': data.get('total_employees', 0) * 100000
57
  }
58
  return None
59
 
 
60
  def get_current_price(symbol):
61
+ url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={POLYGON_API_KEY}"
 
62
  response = safe_request(url)
63
  if response:
64
+ return response.json()['results'][0]['c']
 
65
  return None
66
 
 
67
  def get_dividends(symbol):
68
+ url = f"https://api.polygon.io/v3/reference/dividends?ticker={symbol}&apiKey={POLYGON_API_KEY}"
 
69
  response = safe_request(url)
70
  if response:
71
+ return response.json()['results'][0].get('cash_amount', 0)
72
+ return 0
 
 
 
 
 
73
 
74
  def get_historical_prices(symbol):
 
75
  end = datetime.date.today()
76
  start = end - datetime.timedelta(days=365)
77
+ url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/{start}/{end}?adjusted=true&sort=asc&apiKey={POLYGON_API_KEY}"
78
  response = safe_request(url)
79
  if response:
80
  results = response.json()['results']
 
83
  return dates, prices
84
  return [], []
85
 
86
+ def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
87
+ pe = price / eps if eps else 0
88
+ ps = market_cap / total_revenue if total_revenue else 0
89
+ pb = market_cap / book_value if book_value else 0
90
+ peg = pe / (growth * 100) if growth else 0
91
+ div_yield = (dividend_amount / price) * 100 if price else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  return {
93
+ 'P/E Ratio': pe,
94
+ 'P/S Ratio': ps,
95
+ 'P/B Ratio': pb,
96
+ 'PEG Ratio': peg,
97
+ 'Dividend Yield': div_yield
98
  }
99
 
100
  def compare_to_sector(sector, ratios):
 
110
  "Sector Average": [],
111
  "Difference": []
112
  }
 
113
  for key in averages:
114
  stock_value = ratios.get(key, 0)
115
  sector_value = averages.get(key, 0)
 
118
  data["Stock Value"].append(round(stock_value, 2))
119
  data["Sector Average"].append(round(sector_value, 2))
120
  data["Difference"].append(round(diff, 2))
 
121
  return pd.DataFrame(data)
122
 
123
+ def generate_summary(info, ratios):
124
+ recommendation = "Hold"
125
+ if ratios['P/E Ratio'] < 15 and ratios['P/B Ratio'] < 2 and ratios['PEG Ratio'] < 1.0 and ratios['Dividend Yield'] > 2:
126
+ recommendation = "Buy"
127
+ elif ratios['P/E Ratio'] > 30 and ratios['P/B Ratio'] > 5 and ratios['PEG Ratio'] > 2.0:
128
+ recommendation = "Sell"
129
+ report = (
130
+ f"Company Overview:\n"
131
+ f"Name: {info['Name']}\n"
132
+ f"Industry: {info['Industry']}\n"
133
+ f"Sector: {info['Sector']}\n"
134
+ f"Market Cap: ${info['Market Cap']:,.2f}\n\n"
135
+ f"Financial Metrics:\n"
136
+ f"P/E Ratio: {ratios['P/E Ratio']:.2f}\n"
137
+ f"P/S Ratio: {ratios['P/S Ratio']:.2f}\n"
138
+ f"P/B Ratio: {ratios['P/B Ratio']:.2f}\n"
139
+ f"PEG Ratio: {ratios['PEG Ratio']:.2f}\n"
140
+ f"Dividend Yield: {ratios['Dividend Yield']:.2f}%\n\n"
141
+ f"Recommended Investment Action: {recommendation}.\n"
142
+ )
143
+ return summarizer(report, max_length=250, min_length=100, do_sample=False)[0]['summary_text']
144
+
145
+ def answer_investing_question(question):
146
+ prompt = (
147
+ f"Explain the following investing question clearly and simply for a beginner:\n\n"
148
+ f"{question}\n\n"
149
+ f"Be conversational and encouraging."
150
+ )
151
+ return chat_model(prompt)[0]['generated_text']
152
+
153
+ def stock_research(symbol, eps=5.0, growth=0.1, book=500000000):
154
  info = get_company_info(symbol)
155
  price = get_current_price(symbol)
156
  dividends = get_dividends(symbol)
157
  dates, prices = get_historical_prices(symbol)
158
 
159
  if not info or not price:
160
+ return "⚠️ Error fetching stock info", None, None, None, None
161
 
162
+ ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends, eps, growth, book)
163
  summary = generate_summary(info, ratios)
164
+ sector_comp = compare_to_sector(info['Sector'], ratios)
 
 
 
165
 
166
  fig, ax = plt.subplots()
167
+ ax.plot(dates, prices)
168
+ ax.set_title(f"{symbol} Historical Price (1Y)")
169
  ax.set_xlabel("Date")
170
  ax.set_ylabel("Price ($)")
 
171
  ax.grid(True)
172
 
173
+ info_table = pd.DataFrame(info.items(), columns=["Metric", "Value"])
174
+ ratios_table = pd.DataFrame(ratios.items(), columns=["Ratio", "Value"])
 
 
 
 
 
 
175
 
176
  return summary, info_table, ratios_table, sector_comp, fig
177
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  # --- Gradio UI ---
179
+ with gr.Blocks(theme="soft") as iface:
 
180
  with gr.Row():
181
  symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)")
182
  eps = gr.Number(label="Assumed EPS", value=5.0)
 
195
  with gr.Tab("Historical Price Chart"):
196
  output_chart = gr.Plot()
197
  with gr.Tab("Ask About Investing"):
198
+ user_question = gr.Textbox(label="Ask about investing...")
199
+ answer_box = gr.Textbox()
200
  ask_button = gr.Button("Get Answer")
201
  ask_button.click(fn=answer_investing_question, inputs=[user_question], outputs=[answer_box])
202
 
 
207
  submit_btn.click(fn=stock_research, inputs=[symbol, eps, growth, book],
208
  outputs=[output_summary, output_info, output_ratios, output_sector, output_chart])
209
 
210
+ # Sector Comparison Color Highlight
211
+ def style_sector(df):
212
+ def highlight(val):
213
+ if isinstance(val, (int, float)):
214
+ if val < 0:
215
+ return 'color: green'
216
+ elif val > 0:
217
+ return 'color: red'
218
+ return ''
219
+ return df.style.applymap(highlight, subset=['Difference'])
220
+ output_sector.style_fn = style_sector
221
 
222
  if __name__ == "__main__":
223
  iface.launch()