Stock-Analyser / app.py
CCockrum's picture
Update app.py
6dd319e verified
raw
history blame
8.45 kB
import gradio as gr
import pandas as pd
import requests
import datetime
import tempfile
import os
import matplotlib.pyplot as plt
from transformers import pipeline
# Initialize Models
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
chat_model = pipeline("text-generation", model="google/flan-t5-large", max_length=256)
# API Key
POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")
# Sector Averages
sector_averages = {
"Technology": {"P/E Ratio": 25, "P/S Ratio": 5, "P/B Ratio": 6},
"Healthcare": {"P/E Ratio": 20, "P/S Ratio": 4, "P/B Ratio": 3},
"Financials": {"P/E Ratio": 15, "P/S Ratio": 2, "P/B Ratio": 1.5},
"Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
}
# Tooltip dictionary
tooltips = {
"P/E Ratio": "Price/Earnings: Lower can indicate better value.",
"P/S Ratio": "Price/Sales: Lower can indicate better value relative to sales.",
"P/B Ratio": "Price/Book: Lower can indicate undervaluation.",
"PEG Ratio": "Price/Earnings to Growth: Closer to 1 is ideal.",
"Dividend Yield": "Annual dividend income relative to price."
}
# Helper Functions
def safe_request(url):
try:
response = requests.get(url)
response.raise_for_status()
return response
except:
return None
def get_company_info(symbol):
url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={POLYGON_API_KEY}"
response = safe_request(url)
if response:
data = response.json().get('results', {})
sector = data.get('market', 'Technology')
# Dynamic Guess
if sector.lower() == 'stocks':
sector = "Technology"
return {
'Name': data.get('name', 'N/A'),
'Industry': data.get('sic_description', 'N/A'),
'Sector': sector,
'Market Cap': data.get('market_cap', 0),
'Total Revenue': data.get('total_employees', 0) * 100000
}
return None
def get_current_price(symbol):
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={POLYGON_API_KEY}"
response = safe_request(url)
if response:
return response.json()['results'][0]['c']
return None
def get_dividends(symbol):
url = f"https://api.polygon.io/v3/reference/dividends?ticker={symbol}&apiKey={POLYGON_API_KEY}"
response = safe_request(url)
if response:
return response.json()['results'][0].get('cash_amount', 0)
return 0
def get_historical_prices(symbol):
end = datetime.date.today()
start = end - datetime.timedelta(days=365)
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/range/1/day/{start}/{end}?adjusted=true&sort=asc&apiKey={POLYGON_API_KEY}"
response = safe_request(url)
if response:
results = response.json()['results']
dates = [datetime.datetime.fromtimestamp(r['t']/1000) for r in results]
prices = [r['c'] for r in results]
return dates, prices
return [], []
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, eps=5.0, growth=0.1, book_value=500000000):
pe = price / eps if eps else 0
ps = market_cap / total_revenue if total_revenue else 0
pb = market_cap / book_value if book_value else 0
peg = pe / (growth * 100) if growth else 0
div_yield = (dividend_amount / price) * 100 if price else 0
return {
'P/E Ratio': pe,
'P/S Ratio': ps,
'P/B Ratio': pb,
'PEG Ratio': peg,
'Dividend Yield': div_yield
}
def compare_to_sector(sector, ratios):
if sector.lower() == 'stocks':
sector = 'Technology'
averages = sector_averages.get(sector, {})
if not averages:
return pd.DataFrame({"Metric": ["Sector data not available"], "Value": ["N/A"]})
data = {
"Ratio": [],
"Stock Value": [],
"Sector Average": [],
"Difference": []
}
for key in averages:
stock_value = ratios.get(key, 0)
sector_value = averages.get(key, 0)
diff = stock_value - sector_value
# Add emoji based on difference
if diff < 0:
diff_display = f"{diff:.2f} 🟢"
elif diff > 0:
diff_display = f"{diff:.2f} 🔴"
else:
diff_display = f"{diff:.2f} ⚪"
data["Ratio"].append(key)
data["Stock Value"].append(round(stock_value, 2))
data["Sector Average"].append(round(sector_value, 2))
data["Difference"].append(diff_display)
return pd.DataFrame(data)
def generate_summary(info, ratios):
recommendation = "Hold"
if ratios['P/E Ratio'] < 15 and ratios['P/B Ratio'] < 2 and ratios['PEG Ratio'] < 1.0 and ratios['Dividend Yield'] > 2:
recommendation = "Buy"
elif ratios['P/E Ratio'] > 30 and ratios['P/B Ratio'] > 5 and ratios['PEG Ratio'] > 2.0:
recommendation = "Sell"
report = (
f"Company Overview:\n"
f"Name: {info['Name']}\n"
f"Industry: {info['Industry']}\n"
f"Sector: {info['Sector']}\n"
f"Market Cap: ${info['Market Cap']:,.2f}\n\n"
f"Financial Metrics:\n"
f"P/E Ratio: {ratios['P/E Ratio']:.2f}\n"
f"P/S Ratio: {ratios['P/S Ratio']:.2f}\n"
f"P/B Ratio: {ratios['P/B Ratio']:.2f}\n"
f"PEG Ratio: {ratios['PEG Ratio']:.2f}\n"
f"Dividend Yield: {ratios['Dividend Yield']:.2f}%\n\n"
f"Recommended Investment Action: {recommendation}.\n"
)
return summarizer(report, max_length=250, min_length=100, do_sample=False)[0]['summary_text']
def answer_investing_question(question):
response = chat_model(['generated_text'])
return response
def stock_research(symbol, eps=5.0, growth=0.1, book=500000000):
info = get_company_info(symbol)
price = get_current_price(symbol)
dividends = get_dividends(symbol)
dates, prices = get_historical_prices(symbol)
if not info or not price:
return "⚠️ Error fetching stock info", None, None, None, None
ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends, eps, growth, book)
summary = generate_summary(info, ratios)
sector_comp = compare_to_sector(info['Sector'], ratios)
fig, ax = plt.subplots()
ax.plot(dates, prices)
ax.set_title(f"{symbol} Historical Price (1Y)")
ax.set_xlabel("Date")
ax.set_ylabel("Price ($)")
ax.grid(True)
info_table = pd.DataFrame(info.items(), columns=["Metric", "Value"])
ratios_table = pd.DataFrame(ratios.items(), columns=["Ratio", "Value"])
return summary, info_table, ratios_table, sector_comp, fig
# --- Gradio UI ---
with gr.Blocks(theme="soft") as iface:
with gr.Row():
symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)")
eps = gr.Number(label="Assumed EPS", value=5.0)
growth = gr.Number(label="Assumed Growth Rate", value=0.1)
book = gr.Number(label="Assumed Book Value", value=500000000)
with gr.Tabs():
with gr.Tab("AI Research Summary"):
output_summary = gr.Textbox()
with gr.Tab("Company Snapshot"):
output_info = gr.Dataframe()
with gr.Tab("Valuation Ratios"):
output_ratios = gr.Dataframe()
with gr.Tab("Sector Comparison"):
output_sector = gr.Dataframe()
with gr.Tab("Historical Price Chart"):
output_chart = gr.Plot()
with gr.Tab("Ask About Investing"):
user_question = gr.Textbox(label="Ask about investing...")
answer_box = gr.Textbox()
ask_button = gr.Button("Get Answer")
ask_button.click(fn=answer_investing_question, inputs=[user_question], outputs=[answer_box])
submit_btn = gr.Button("Run Analysis")
download_btn = gr.Button("Download Report")
file_output = gr.File()
submit_btn.click(fn=stock_research, inputs=[symbol, eps, growth, book],
outputs=[output_summary, output_info, output_ratios, output_sector, output_chart])
# Sector Comparison Color Highlight
def style_sector(df):
def highlight(val):
if isinstance(val, (int, float)):
if val < 0:
return 'color: green'
elif val > 0:
return 'color: red'
return ''
return df.style.applymap(highlight, subset=['Difference'])
output_sector.style_fn = style_sector
if __name__ == "__main__":
iface.launch()