Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -39,6 +39,7 @@ sector_averages = {
|
|
39 |
"Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
|
40 |
}
|
41 |
|
|
|
42 |
# Safe Request Function
|
43 |
def safe_request(url):
|
44 |
try:
|
@@ -50,7 +51,9 @@ def safe_request(url):
|
|
50 |
|
51 |
# Fetch Functions
|
52 |
# (functions unchanged)
|
|
|
53 |
|
|
|
54 |
# Financial Calculations
|
55 |
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
|
56 |
pe = price / eps if eps else 0
|
@@ -82,6 +85,152 @@ if selected_theme == "dark":
|
|
82 |
else:
|
83 |
theme = gr.themes.Soft(primary_hue="blue")
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
# Gradio UI
|
86 |
with gr.Blocks(theme=theme) as iface:
|
87 |
with gr.Row():
|
@@ -129,7 +278,13 @@ with gr.Blocks(theme=theme) as iface:
|
|
129 |
|
130 |
reset_btn.click(fn=reset_fields, inputs=[], outputs=[symbol, eps, growth, book, output_summary, output_info, output_ratios, output_sector, output_chart])
|
131 |
|
132 |
-
if __name__ == "__main__":
|
133 |
-
iface.launch()
|
134 |
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
"Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
|
40 |
}
|
41 |
|
42 |
+
|
43 |
# Safe Request Function
|
44 |
def safe_request(url):
|
45 |
try:
|
|
|
51 |
|
52 |
# Fetch Functions
|
53 |
# (functions unchanged)
|
54 |
+
# ...
|
55 |
|
56 |
+
# Financial Calculations
|
57 |
# Financial Calculations
|
58 |
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
|
59 |
pe = price / eps if eps else 0
|
|
|
85 |
else:
|
86 |
theme = gr.themes.Soft(primary_hue="blue")
|
87 |
|
88 |
+
|
89 |
+
# Fetch Functions
|
90 |
+
def get_company_info(symbol):
|
91 |
+
url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={POLYGON_API_KEY}"
|
92 |
+
response = safe_request(url)
|
93 |
+
if response:
|
94 |
+
data = response.json().get('results', {})
|
95 |
+
sector = data.get('market', 'Technology')
|
96 |
+
if sector.lower() == 'stocks':
|
97 |
+
sector = 'Technology'
|
98 |
+
return {
|
99 |
+
'Name': data.get('name', 'N/A'),
|
100 |
+
'Industry': data.get('sic_description', 'N/A'),
|
101 |
+
'Sector': sector,
|
102 |
+
'Market Cap': data.get('market_cap', 0),
|
103 |
+
'Total Revenue': data.get('total_employees', 0) * 100000
|
104 |
+
}
|
105 |
+
return None
|
106 |
+
|
107 |
+
def get_current_price(symbol):
|
108 |
+
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={POLYGON_API_KEY}"
|
109 |
+
response = safe_request(url)
|
110 |
+
if response:
|
111 |
+
return response.json()['results'][0]['c']
|
112 |
+
return None
|
113 |
+
|
114 |
+
def get_dividends(symbol):
|
115 |
+
url = f"https://api.polygon.io/v3/reference/dividends?ticker={symbol}&apiKey={POLYGON_API_KEY}"
|
116 |
+
response = safe_request(url)
|
117 |
+
if response:
|
118 |
+
return response.json()['results'][0].get('cash_amount', 0)
|
119 |
+
return 0
|
120 |
+
|
121 |
+
def get_historical_prices(symbol):
|
122 |
+
end = datetime.date.today()
|
123 |
+
start = end - datetime.timedelta(days=365)
|
124 |
+
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/{start}/{end}?adjusted=true&sort=asc&apiKey={POLYGON_API_KEY}"
|
125 |
+
response = safe_request(url)
|
126 |
+
if response:
|
127 |
+
results = response.json()['results']
|
128 |
+
dates = [datetime.datetime.fromtimestamp(r['t']/1000) for r in results]
|
129 |
+
prices = [r['c'] for r in results]
|
130 |
+
return dates, prices
|
131 |
+
return [], []
|
132 |
+
|
133 |
+
# Financial Calculations
|
134 |
+
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
|
135 |
+
pe = price / eps if eps else 0
|
136 |
+
ps = market_cap / total_revenue if total_revenue else 0
|
137 |
+
pb = market_cap / book_value if book_value else 0
|
138 |
+
peg = pe / (growth * 100) if growth else 0
|
139 |
+
div_yield = (dividend_amount / price) * 100 if price else 0
|
140 |
+
return {
|
141 |
+
'P/E Ratio': pe,
|
142 |
+
'P/S Ratio': ps,
|
143 |
+
'P/B Ratio': pb,
|
144 |
+
'PEG Ratio': peg,
|
145 |
+
'Dividend Yield': div_yield
|
146 |
+
}
|
147 |
+
|
148 |
+
def compare_to_sector(sector, ratios):
|
149 |
+
if sector.lower() == 'stocks':
|
150 |
+
sector = 'Technology'
|
151 |
+
averages = sector_averages.get(sector, {})
|
152 |
+
if not averages:
|
153 |
+
return pd.DataFrame({"Metric": ["Sector data not available"], "Value": ["N/A"]})
|
154 |
+
|
155 |
+
data = {
|
156 |
+
"Ratio": [],
|
157 |
+
"Stock Value": [],
|
158 |
+
"Sector Average": [],
|
159 |
+
"Difference": []
|
160 |
+
}
|
161 |
+
for key in averages:
|
162 |
+
stock_value = ratios.get(key, 0)
|
163 |
+
sector_value = averages.get(key, 0)
|
164 |
+
diff = stock_value - sector_value
|
165 |
+
|
166 |
+
# Add emoji based on difference
|
167 |
+
if diff < 0:
|
168 |
+
diff_display = f"{diff:.2f} 🟢"
|
169 |
+
elif diff > 0:
|
170 |
+
diff_display = f"{diff:.2f} 🔴"
|
171 |
+
else:
|
172 |
+
diff_display = f"{diff:.2f} ⚪"
|
173 |
+
|
174 |
+
data["Ratio"].append(key)
|
175 |
+
data["Stock Value"].append(round(stock_value, 2))
|
176 |
+
data["Sector Average"].append(round(sector_value, 2))
|
177 |
+
data["Difference"].append(diff_display)
|
178 |
+
|
179 |
+
return pd.DataFrame(data)
|
180 |
+
|
181 |
+
def generate_summary(info, ratios):
|
182 |
+
recommendation = "Hold"
|
183 |
+
if ratios['P/E Ratio'] < 15 and ratios['P/B Ratio'] < 2 and ratios['PEG Ratio'] < 1.0 and ratios['Dividend Yield'] > 2:
|
184 |
+
recommendation = "Buy"
|
185 |
+
elif ratios['P/E Ratio'] > 30 and ratios['P/B Ratio'] > 5 and ratios['PEG Ratio'] > 2.0:
|
186 |
+
recommendation = "Sell"
|
187 |
+
|
188 |
+
report = (
|
189 |
+
f"Company Overview:\n"
|
190 |
+
f"Name: {info['Name']}\n"
|
191 |
+
f"Industry: {info['Industry']}\n"
|
192 |
+
f"Sector: {info['Sector']}\n"
|
193 |
+
f"Market Cap: ${info['Market Cap']:,.2f}\n\n"
|
194 |
+
f"Financial Metrics:\n"
|
195 |
+
f"P/E Ratio: {ratios['P/E Ratio']:.2f}\n"
|
196 |
+
f"P/S Ratio: {ratios['P/S Ratio']:.2f}\n"
|
197 |
+
f"P/B Ratio: {ratios['P/B Ratio']:.2f}\n"
|
198 |
+
f"PEG Ratio: {ratios['PEG Ratio']:.2f}\n"
|
199 |
+
f"Dividend Yield: {ratios['Dividend Yield']:.2f}%\n\n"
|
200 |
+
f"Recommended Investment Action: {recommendation}.\n"
|
201 |
+
)
|
202 |
+
|
203 |
+
# Use Mistral to generate the summary
|
204 |
+
summary_prompt = f"Summarize the following financial report clearly and briefly:\n\n{report}"
|
205 |
+
return query_mistral(summary_prompt)
|
206 |
+
|
207 |
+
def stock_research(symbol, eps=5.0, growth=0.1, book=500000000):
|
208 |
+
info = get_company_info(symbol)
|
209 |
+
price = get_current_price(symbol)
|
210 |
+
dividends = get_dividends(symbol)
|
211 |
+
dates, prices = get_historical_prices(symbol)
|
212 |
+
|
213 |
+
if not info or not price:
|
214 |
+
return "⚠️ Error fetching stock info", None, None, None, None
|
215 |
+
|
216 |
+
ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends, eps, growth, book)
|
217 |
+
summary = generate_summary(info, ratios)
|
218 |
+
sector_comp = compare_to_sector(info['Sector'], ratios)
|
219 |
+
|
220 |
+
fig, ax = plt.subplots()
|
221 |
+
ax.plot(dates, prices)
|
222 |
+
ax.set_title(f"{symbol} Historical Price (1Y)")
|
223 |
+
ax.set_xlabel("Date")
|
224 |
+
ax.set_ylabel("Price ($)")
|
225 |
+
ax.grid(True)
|
226 |
+
|
227 |
+
info_table = pd.DataFrame(info.items(), columns=["Metric", "Value"])
|
228 |
+
ratios_table = pd.DataFrame(ratios.items(), columns=["Ratio", "Value"])
|
229 |
+
|
230 |
+
return summary, info_table, ratios_table, sector_comp, fig
|
231 |
+
|
232 |
+
|
233 |
+
|
234 |
# Gradio UI
|
235 |
with gr.Blocks(theme=theme) as iface:
|
236 |
with gr.Row():
|
|
|
278 |
|
279 |
reset_btn.click(fn=reset_fields, inputs=[], outputs=[symbol, eps, growth, book, output_summary, output_info, output_ratios, output_sector, output_chart])
|
280 |
|
|
|
|
|
281 |
|
282 |
+
def reset_fields():
|
283 |
+
return "", 5.0, 0.1, 500000000, "", "", "", "", None
|
284 |
+
|
285 |
+
reset_btn.click(fn=reset_fields, inputs=[], outputs=[symbol, eps, growth, book, output_summary, output_info, output_ratios, output_sector, output_chart])
|
286 |
+
|
287 |
+
|
288 |
+
|
289 |
+
if __name__ == "__main__":
|
290 |
+
iface.launch()
|