Napol_v2 / app.py
ibrahim yıldız
Update app.py
1aaaaf6 verified
import streamlit as st
import pandas as pd
import yfinance as yf
# Load data
df = pd.read_csv('merged_data.csv')
overview = pd.read_csv('company_overview.csv')
st.image('napol.png')
st.write('Hi! This is Napol, your long term personal portfolio assistant. See S&P 500 stock current prices and buy/sell signals by Short Term (3 Months), Long Term (18 Months) and Analyst Rating (Performance Forecasts). Press the buttons below to sort stocks.')
def score_to_percentage(score):
percentage = abs(score) * 100 # Use absolute value to avoid negative sign
if score > 0:
status = "buy"
elif score < 0:
status = "sell"
else:
status = ""
return f"{percentage:.0f}%{f' {status}' if status else ''}"
# Function to get color based on percentage
def get_color(percentage):
# Scale the intensity to start from 30% and go up to 100%
scaled_intensity = 0.30 + 0.70 * (abs(percentage) / 100)
if percentage == 0:
return "gray"
elif percentage > 0:
return f"rgba(19, 204, 78, {scaled_intensity})"
else:
return f"rgba(212, 0, 40, {scaled_intensity})"
# Function to safely get stock info
def get_stock_info(ticker):
try:
stock = yf.Ticker(ticker)
info = stock.info
# Try to get the current price
if 'regularMarketPrice' in info:
current_price = info['regularMarketPrice']
elif 'currentPrice' in info:
current_price = info['currentPrice']
else:
current_price = stock.history(period="1d")['Close'].iloc[-1]
# Try to get the weekly change
hist = stock.history(period="5d")
if not hist.empty:
weekly_change = ((hist['Close'].iloc[-1] - hist['Open'].iloc[0]) / hist['Open'].iloc[0]) * 100
else:
weekly_change = 0
return current_price, weekly_change
except Exception as e:
print(f"Error fetching data for {ticker}: {str(e)}")
return None, None
# Merge with company overview data
df = pd.merge(df, overview[['Symbol', 'Name']], left_on='symbol', right_on='Symbol')
df = df[df['symbol'] != 'GS']
# Calculate total score
df['total_score'] = df['short_term'] + df['long_term'] + df['analyst_rating']
# Initialize session state for sorting
if 'sort_column' not in st.session_state:
st.session_state.sort_column = 'total_score'
st.session_state.ascending = False
# Sorting options
sort_options = {
"Total Buy": ("total_score", False),
"Total Sell": ("total_score", True),
"Long Term Buy": ("long_term", False),
"Long Term Sell": ("long_term", True),
"Analyst Rating Buy": ("analyst_rating", False),
"Analyst Rating Sell": ("analyst_rating", True),
"Short Term Buy": ("short_term", False),
"Short Term Sell": ("short_term", True),
}
# Create buttons for sorting
cols = st.columns(4)
for i, (option, (column, ascending)) in enumerate(sort_options.items()):
if cols[i % 4].button(option):
st.session_state.sort_column = column
st.session_state.ascending = ascending
# Slider for user to choose number of stocks to display
num_stocks = st.slider("Select number of stocks to display:", min_value=1, max_value=100, value=25)
# Sort DataFrame
df_sorted = df.sort_values(st.session_state.sort_column, ascending=st.session_state.ascending).head(num_stocks)
# Display sorted stocks
for _, row in df_sorted.iterrows():
ticker = row['symbol']
# Get current price and weekly change
current_price, weekly_change = get_stock_info(ticker)
if current_price is None or weekly_change is None:
continue # Skip this stock if we couldn't fetch the data
# Read the SVG file
with open(f'images/{ticker}.svg', 'r') as f: svg_code = f.read()
svg_code = f"""<style>svg {{border-radius: 10px; height: 20px; width: 20px; border: 1px solid #202020; margin-right: 10px;}}</style>{svg_code}"""
# Create the stock box
html_content = f"""
<div style="background-color: #101010; border: 1px solid #202020; padding: 10px; margin-bottom: 10px; border-radius: 6px; width: 100%; box-sizing: border-box;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center;">
{svg_code}
<span style="font-weight: bold; color: white; font-size: 18px;">{ticker}</span>
</div>
<span style="font-size: 18px; color: white;">${current_price:.2f}</span>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 2px;">
<span style="color: #bfbfbf;">{row['Name']}</span>
<span style="color: {'green' if weekly_change > 0 else 'red'}">
week ({'+' if weekly_change > 0 else ''}{weekly_change:.2f}%)
</span>
</div>
<div style="display: flex; justify-content: space-between; margin-top: 10px;">
<!-- Short Term Box -->
<div style="text-align: center; width: 32%; padding: 8px; border: 1px solid #202020; border-radius: 4px; box-sizing: border-box;">
<div style="color: white; font-size: 14px; font-weight: bold;">Short Term</div>
<div style="color: {get_color((row['short_term']) * 100)};">
{score_to_percentage(row['short_term'])}
</div>
</div>
<!-- Long Term Box -->
<div style="text-align: center; width: 32%; padding: 8px; border: 1px solid #202020; border-radius: 4px; box-sizing: border-box;">
<div style="color: white; font-size: 14px; font-weight: bold;">Long Term</div>
<div style="color: {get_color((row['long_term']) * 100)};">
{score_to_percentage(row['long_term'])}
</div>
</div>
<!-- Analyst Rating Box -->
<div style="text-align: center; width: 32%; padding: 8px; border: 1px solid #202020; border-radius: 4px; box-sizing: border-box;">
<div style="color: white; font-size: 14px; font-weight: bold;">Analyst Rate</div>
<div style="color: {get_color((row['analyst_rating']) * 100)};">
{score_to_percentage(row['analyst_rating'])}
</div>
</div>
</div>
</div>
"""
st.markdown(html_content, unsafe_allow_html=True)