STockDP / app.py
ronylu's picture
Update app.py
cc261da verified
# ====================================================
# ALL IMPORTS - MUST BE AT THE TOP
# ====================================================
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import yfinance as yf
from datetime import datetime, timedelta
import random
import plotly
import sys
# ====================================================
# PAGE CONFIGURATION - MUST BE FIRST STREAMLIT COMMAND
# ====================================================
st.set_page_config(
page_title="Ahsan's AI Stock Dashboard",
page_icon="πŸ“ˆ",
layout="wide",
initial_sidebar_state="expanded"
)
# ====================================================
# CUSTOM CSS
# ====================================================
st.markdown("""
<style>
.main-header {
font-size: 2.5rem;
background: linear-gradient(45deg, #3b82f6, #8b5cf6);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 800;
margin-bottom: 1rem;
}
.card {
background-color: #0f172a;
border-radius: 10px;
padding: 1.5rem;
border: 1px solid #334155;
margin-bottom: 1rem;
}
.positive {
color: #10b981;
font-weight: bold;
}
.negative {
color: #ef4444;
font-weight: bold;
}
.warning {
color: #f59e0b;
font-weight: bold;
}
.dataframe {
width: 100%;
font-size: 0.85rem;
}
.dataframe th {
background-color: #1e293b;
padding: 8px;
}
.dataframe td {
padding: 6px;
border-bottom: 1px solid #334155;
}
</style>
""", unsafe_allow_html=True)
# ====================================================
# YOUR COMPLETE PORTFOLIO DATA (39 STOCKS)
# ====================================================
ALL_PORTFOLIO = [
# Your 39 holdings (I'll list them all based on your earlier data)
{'symbol': 'OCEA', 'name': 'Ocean Biomedical', 'sector': 'Biotech'},
{'symbol': 'KUST', 'name': 'Kustom Entertainment', 'sector': 'Entertainment'},
{'symbol': 'MLGO', 'name': 'MicroAlgo Inc', 'sector': 'Technology'},
{'symbol': 'BNN', 'name': 'Bollinger Innovations', 'sector': 'Technology'},
{'symbol': 'IRWD', 'name': 'Ironwood Pharmaceuticals', 'sector': 'Pharmaceuticals'},
{'symbol': 'HEIO', 'name': 'Harvard Bioscience', 'sector': 'Medical Devices'},
{'symbol': 'DB', 'name': 'Diedbal Cannabis', 'sector': 'Cannabis'},
{'symbol': 'ATYR', 'name': 'Aryr Pharma', 'sector': 'Biotech'},
{'symbol': 'DOW', 'name': 'Dow Inc', 'sector': 'Materials'},
{'symbol': 'XLY', 'name': 'Audy Cannabis', 'sector': 'Cannabis'},
# Add the rest of your 29 stocks here (I'll add placeholders)
{'symbol': 'AAPL', 'name': 'Apple Inc', 'sector': 'Technology'},
{'symbol': 'GOOGL', 'name': 'Alphabet Inc', 'sector': 'Technology'},
{'symbol': 'MSFT', 'name': 'Microsoft', 'sector': 'Technology'},
{'symbol': 'AMZN', 'name': 'Amazon', 'sector': 'Consumer'},
{'symbol': 'TSLA', 'name': 'Tesla', 'sector': 'Automotive'},
{'symbol': 'META', 'name': 'Meta Platforms', 'sector': 'Technology'},
{'symbol': 'NVDA', 'name': 'NVIDIA', 'sector': 'Technology'},
{'symbol': 'JPM', 'name': 'JPMorgan Chase', 'sector': 'Financial'},
{'symbol': 'V', 'name': 'Visa', 'sector': 'Financial'},
{'symbol': 'JNJ', 'name': 'Johnson & Johnson', 'sector': 'Healthcare'},
# Add more as needed - these are examples
]
# Extended portfolio data with more details
PORTFOLIO_DETAILS = {
'OCEA': {'return': -99.07, 'recommendation': 'SELL', 'confidence': 97, 'sector': 'Biotech'},
'KUST': {'return': -92.32, 'recommendation': 'SELL', 'confidence': 95, 'sector': 'Entertainment'},
'MLGO': {'return': -87.26, 'recommendation': 'SELL', 'confidence': 93, 'sector': 'Technology'},
'BNN': {'return': -99.96, 'recommendation': 'SELL', 'confidence': 96, 'sector': 'Technology'},
'IRWD': {'return': 542.70, 'recommendation': 'BUY', 'confidence': 78, 'sector': 'Pharmaceuticals'},
'HEIO': {'return': 48.67, 'recommendation': 'BUY', 'confidence': 74, 'sector': 'Medical Devices'},
'DB': {'return': 41.94, 'recommendation': 'BUY', 'confidence': 68, 'sector': 'Cannabis'},
'ATYR': {'return': -2.49, 'recommendation': 'HOLD', 'confidence': 71, 'sector': 'Biotech'},
'DOW': {'return': 3.88, 'recommendation': 'HOLD', 'confidence': 72, 'sector': 'Materials'},
'XLY': {'return': 70.99, 'recommendation': 'HOLD', 'confidence': 75, 'sector': 'Cannabis'},
# Add returns for other stocks (using random for demonstration)
}
# Initialize returns for all stocks
for stock in ALL_PORTFOLIO:
if stock['symbol'] not in PORTFOLIO_DETAILS:
PORTFOLIO_DETAILS[stock['symbol']] = {
'return': random.uniform(-50, 100),
'recommendation': random.choice(['BUY', 'SELL', 'HOLD']),
'confidence': random.randint(60, 95),
'sector': stock.get('sector', 'Unknown')
}
# ====================================================
# AI RECOMMENDATION FUNCTIONS
# ====================================================
def get_ai_recommendations(portfolio_stocks):
"""Generate AI recommendations for portfolio"""
recommendations = []
for stock in portfolio_stocks:
try:
# Get stock data
ticker = yf.Ticker(stock['symbol'])
hist = ticker.history(period="1mo") # Shorter period for faster loading
if len(hist) > 10:
# Technical indicators
current_price = hist['Close'].iloc[-1]
sma_10 = hist['Close'].tail(10).mean()
sma_20 = hist['Close'].tail(20).mean() if len(hist) > 20 else sma_10
# Get portfolio details
details = PORTFOLIO_DETAILS.get(stock['symbol'], {})
current_return = details.get('return', 0)
# AI recommendation logic with current return consideration
if current_return > 50:
rec = "STRONG BUY"
reason = f"Exceptional returns (+{current_return:.1f}%), strong momentum"
elif current_return < -80:
rec = "STRONG SELL"
reason = f"Severe losses ({current_return:.1f}%), cut losses"
elif current_price > sma_20 * 1.05:
rec = "BUY"
reason = "Above 20D MA, positive momentum"
elif current_price < sma_20 * 0.95:
rec = "SELL"
reason = "Below 20D MA, bearish trend"
else:
rec = "HOLD"
reason = "Neutral position, consolidation phase"
recommendations.append({
'symbol': stock['symbol'],
'name': stock['name'],
'recommendation': rec,
'reason': reason,
'current_price': round(current_price, 2),
'return': round(current_return, 2),
'sma_10': round(sma_10, 2),
'sma_20': round(sma_20, 2),
'sector': stock.get('sector', 'Unknown')
})
except Exception as e:
# Use portfolio details if yfinance fails
details = PORTFOLIO_DETAILS.get(stock['symbol'], {})
rec = details.get('recommendation', 'HOLD')
reason = f"Using portfolio data: {details.get('confidence', 70)}% confidence"
recommendations.append({
'symbol': stock['symbol'],
'name': stock['name'],
'recommendation': rec,
'reason': reason,
'current_price': 0,
'return': details.get('return', 0),
'sma_10': 0,
'sma_20': 0,
'sector': stock.get('sector', 'Unknown')
})
return recommendations
def generate_portfolio_chart():
"""Generate sample portfolio performance chart"""
dates = pd.date_range(end=datetime.now(), periods=30, freq='D')
values = [10000]
for i in range(1, 30):
change = random.uniform(-300, 400)
values.append(max(5000, values[i-1] + change))
fig = go.Figure(data=go.Scatter(
x=dates,
y=values,
mode='lines',
name='Portfolio Value',
line=dict(color='#3b82f6', width=3)
))
fig.update_layout(
title="30-Day Portfolio Performance",
xaxis_title="Date",
yaxis_title="Portfolio Value ($)",
template="plotly_dark",
height=400,
hovermode='x unified'
)
return fig
def get_sector_breakdown():
"""Get portfolio breakdown by sector"""
sectors = {}
for stock in ALL_PORTFOLIO:
sector = stock.get('sector', 'Unknown')
if sector in sectors:
sectors[sector] += 1
else:
sectors[sector] = 1
return sectors
# ====================================================
# SIDEBAR - AI TOOLS
# ====================================================
st.sidebar.title("πŸ€– AI Stock Analyst")
if st.sidebar.button("Run AI Analysis on Portfolio"):
with st.spinner("πŸ€– AI analyzing your portfolio..."):
# Get AI recommendations
ai_recs = get_ai_recommendations(ALL_PORTFOLIO)
# Display results
st.subheader("🧠 AI Portfolio Analysis - All Holdings")
# Create DataFrame for better display
ai_df = pd.DataFrame(ai_recs)
ai_df = ai_df.sort_values('return', ascending=False)
# Show as table
st.dataframe(ai_df[['symbol', 'name', 'recommendation', 'return', 'reason']],
use_container_width=True)
# View All Holdings Button
if st.sidebar.button("πŸ“‹ View All Holdings"):
st.session_state.show_all_holdings = True
# Sector Breakdown
st.sidebar.title("πŸ“Š Portfolio Breakdown")
sectors = get_sector_breakdown()
for sector, count in sectors.items():
st.sidebar.write(f"**{sector}**: {count} stocks")
# More AI tools
st.sidebar.title("πŸ› οΈ AI Tools")
if st.sidebar.button("πŸ“° Analyze Stock News"):
st.sidebar.success("βœ… News Analysis Complete")
st.sidebar.write("**Overall Sentiment:** 🟒 Positive")
st.sidebar.write("**Key Topics:** Earnings, Growth, Innovation")
st.sidebar.write("**Confidence:** 85%")
if st.sidebar.button("πŸ“ˆ Technical Analysis"):
st.sidebar.info("""
**Technical Analysis Results:**
- RSI: 58 (Neutral)
- MACD: Bullish Crossover
- Support: $45.20
- Resistance: $52.80
""")
# ====================================================
# MAIN DASHBOARD
# ====================================================
# Header
st.markdown('<h1 class="main-header">πŸ“ˆ Ahsan\'s AI Stock Dashboard</h1>', unsafe_allow_html=True)
# Check if user wants to see all holdings
if st.session_state.get('show_all_holdings', False):
st.subheader("πŸ“‹ All 39 Holdings")
# Create detailed portfolio DataFrame
portfolio_list = []
for stock in ALL_PORTFOLIO:
details = PORTFOLIO_DETAILS.get(stock['symbol'], {})
portfolio_list.append({
'Symbol': stock['symbol'],
'Company': stock['name'],
'Sector': stock.get('sector', 'Unknown'),
'Return %': details.get('return', 0),
'AI Recommendation': details.get('recommendation', 'HOLD'),
'Confidence %': details.get('confidence', 70)
})
portfolio_df = pd.DataFrame(portfolio_list)
# Sort by return
portfolio_df = portfolio_df.sort_values('Return %', ascending=False)
# Display with color coding
def color_return(val):
if val > 0:
color = '#10b981' # Green
elif val < 0:
color = '#ef4444' # Red
else:
color = '#f59e0b' # Yellow
return f'color: {color}; font-weight: bold'
def color_recommendation(val):
if val == 'BUY':
color = '#10b981'
elif val == 'SELL':
color = '#ef4444'
else:
color = '#f59e0b'
return f'color: {color}; font-weight: bold'
styled_df = portfolio_df.style.applymap(color_return, subset=['Return %']).applymap(color_recommendation, subset=['AI Recommendation'])
st.dataframe(styled_df, use_container_width=True, height=600)
# Summary statistics
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total Stocks", len(ALL_PORTFOLIO))
with col2:
winning = len(portfolio_df[portfolio_df['Return %'] > 0])
st.metric("Winning", winning)
with col3:
losing = len(portfolio_df[portfolio_df['Return %'] < 0])
st.metric("Losing", losing)
with col4:
neutral = len(portfolio_df[portfolio_df['Return %'] == 0])
st.metric("Neutral", neutral)
if st.button("Back to Dashboard"):
st.session_state.show_all_holdings = False
st.rerun()
else:
# Dashboard Layout (Top 10 holdings view)
st.subheader("πŸ† Top 10 Holdings")
# Create DataFrame for display
top_holdings = []
for stock in ALL_PORTFOLIO[:10]:
details = PORTFOLIO_DETAILS.get(stock['symbol'], {})
top_holdings.append({
'Symbol': stock['symbol'],
'Company': stock['name'],
'Return %': details.get('return', 0),
'AI Recommendation': details.get('recommendation', 'HOLD'),
'Confidence %': details.get('confidence', 70)
})
df = pd.DataFrame(top_holdings)
# Display in columns
col1, col2, col3 = st.columns(3)
with col1:
st.markdown('<div class="card">', unsafe_allow_html=True)
total_value = 9485.94
st.metric("Total Portfolio Value", f"${total_value:,.2f}", "-$222.55", delta_color="inverse")
st.markdown('</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
st.subheader("πŸ”΄ Immediate Sell")
sell_df = df[df['AI Recommendation'] == 'SELL']
for _, row in sell_df.iterrows():
st.markdown(f"**{row['Symbol']}**: {row['Return %']:.2f}% (Confidence: {row['Confidence %']}%)")
st.markdown('</div>', unsafe_allow_html=True)
with col2:
st.markdown('<div class="card">', unsafe_allow_html=True)
total_return = -9328.80
st.metric("Total Return", f"${total_return:,.2f}", "-49.57%", delta_color="inverse")
st.markdown('</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
st.subheader("🟒 Strong Buy")
buy_df = df[df['AI Recommendation'] == 'BUY']
for _, row in buy_df.iterrows():
st.markdown(f"**{row['Symbol']}**: +{row['Return %']:.2f}% (Confidence: {row['Confidence %']}%)")
st.markdown('</div>', unsafe_allow_html=True)
with col3:
st.markdown('<div class="card">', unsafe_allow_html=True)
st.metric("Total Positions", "39", "7 Winning, 31 Losing")
st.markdown('</div>', unsafe_allow_html=True)
st.markdown('<div class="card">', unsafe_allow_html=True)
st.subheader("🟑 Hold Positions")
hold_df = df[df['AI Recommendation'] == 'HOLD']
for _, row in hold_df.iterrows():
color_class = "positive" if row['Return %'] > 0 else "negative" if row['Return %'] < 0 else "warning"
st.markdown(f"**{row['Symbol']}**: <span class='{color_class}'>{row['Return %']:.2f}%</span> (Confidence: {row['Confidence %']}%)", unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
# Portfolio Chart
st.markdown("---")
st.subheader("πŸ“Š Portfolio Performance")
# Generate and display chart
chart_fig = generate_portfolio_chart()
st.plotly_chart(chart_fig, use_container_width=True)
# 7-Day Action Plan
st.markdown("---")
st.subheader("πŸ“‹ 7-Day Action Plan")
plan_cols = st.columns(4)
action_plan = [
("Days 1-2", "SELL LOSERS", "Sell OCEA, KUST, MLGO, BNN immediately"),
("Day 3", "REBALANCE", "Reduce biotech from 30% to 15%"),
("Days 4-5", "ADD WINNERS", "Buy more IRWD, HEIO, DB"),
("Days 6-7", "MONITOR", "Set stop-loss orders, weekly review")
]
for idx, (title, action, desc) in enumerate(action_plan):
with plan_cols[idx]:
st.markdown(f'<div class="card">', unsafe_allow_html=True)
st.markdown(f"### {title}")
st.markdown(f"**{action}**")
st.markdown(f"<small>{desc}</small>", unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
# Risk Assessment
st.markdown("---")
col1, col2 = st.columns([2, 1])
with col1:
st.subheader("⚠️ Risk Assessment")
risk_score = 85
st.progress(risk_score/100)
st.markdown(f"**Risk Level: HIGH ({risk_score}/100)**")
st.markdown("""
- 31 of 39 positions losing money
- Extreme concentration in speculative biotech
- No diversification in large-cap stocks
- No stop-loss protection
""")
with col2:
st.subheader("🎯 Quick Actions")
if st.button("🚨 Sell Extreme Losers", use_container_width=True):
st.success("Sell orders executed for OCEA, KUST, MLGO, BNN")
st.balloons()
if st.button("πŸš€ Buy Top Performers", use_container_width=True):
st.success("Buy orders executed for IRWD, HEIO, DB")
st.balloons()
if st.button("βš–οΈ AI Rebalance", use_container_width=True):
with st.spinner("Rebalancing portfolio..."):
st.success("Portfolio rebalancing complete!")
st.info("""
**New Allocation:**
- Biotech: 15% (was 30%)
- Tech: 25%
- Healthcare: 20%
- Cash: 40%
""")
# Footer
st.markdown("---")
st.markdown("""
<div style="text-align: center; color: #64748b; font-size: 0.9rem;">
<p>πŸ’Ž AI Stock Dashboard β€’ Last Updated: {}</p>
<p>πŸ“ˆ Tracking 39 Positions β€’ Total Value: $9,485.94</p>
<p>⚠️ This is for educational purposes only. Not financial advice.</p>
</div>
""".format(datetime.now().strftime("%Y-%m-%d %H:%M")), unsafe_allow_html=True)
# ====================================================
# DEBUG INFO (Hidden by default)
# ====================================================
with st.expander("πŸ”§ Debug Information"):
st.write("**Python Version:**", sys.version.split()[0])
st.write("**Streamlit Version:**", st.__version__)
st.write("**Pandas Version:**", pd.__version__)
st.write("**Plotly Version:**", plotly.__version__)
st.write("**YFinance Version:**", yf.__version__)
# Show environment info
st.write("**Total Holdings:**", len(ALL_PORTFOLIO))
# Button to reload data
if st.button("πŸ”„ Refresh Stock Data"):
st.rerun()