| |
| |
| |
| 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 |
|
|
| |
| |
| |
| st.set_page_config( |
| page_title="Ahsan's AI Stock Dashboard", |
| page_icon="π", |
| layout="wide", |
| initial_sidebar_state="expanded" |
| ) |
|
|
| |
| |
| |
| 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) |
|
|
| |
| |
| |
| ALL_PORTFOLIO = [ |
| |
| {'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'}, |
| |
| {'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'}, |
| |
| ] |
|
|
| |
| 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'}, |
| |
| } |
|
|
| |
| 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') |
| } |
|
|
| |
| |
| |
| def get_ai_recommendations(portfolio_stocks): |
| """Generate AI recommendations for portfolio""" |
| recommendations = [] |
| |
| for stock in portfolio_stocks: |
| try: |
| |
| ticker = yf.Ticker(stock['symbol']) |
| hist = ticker.history(period="1mo") |
| |
| if len(hist) > 10: |
| |
| 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 |
| |
| |
| details = PORTFOLIO_DETAILS.get(stock['symbol'], {}) |
| current_return = details.get('return', 0) |
| |
| |
| 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: |
| |
| 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 |
|
|
| |
| |
| |
| st.sidebar.title("π€ AI Stock Analyst") |
|
|
| if st.sidebar.button("Run AI Analysis on Portfolio"): |
| with st.spinner("π€ AI analyzing your portfolio..."): |
| |
| ai_recs = get_ai_recommendations(ALL_PORTFOLIO) |
| |
| |
| st.subheader("π§ AI Portfolio Analysis - All Holdings") |
| |
| |
| ai_df = pd.DataFrame(ai_recs) |
| ai_df = ai_df.sort_values('return', ascending=False) |
| |
| |
| st.dataframe(ai_df[['symbol', 'name', 'recommendation', 'return', 'reason']], |
| use_container_width=True) |
|
|
| |
| if st.sidebar.button("π View All Holdings"): |
| st.session_state.show_all_holdings = True |
|
|
| |
| st.sidebar.title("π Portfolio Breakdown") |
| sectors = get_sector_breakdown() |
| for sector, count in sectors.items(): |
| st.sidebar.write(f"**{sector}**: {count} stocks") |
|
|
| |
| 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 |
| """) |
|
|
| |
| |
| |
|
|
| |
| st.markdown('<h1 class="main-header">π Ahsan\'s AI Stock Dashboard</h1>', unsafe_allow_html=True) |
|
|
| |
| if st.session_state.get('show_all_holdings', False): |
| st.subheader("π All 39 Holdings") |
| |
| |
| 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) |
| |
| |
| portfolio_df = portfolio_df.sort_values('Return %', ascending=False) |
| |
| |
| def color_return(val): |
| if val > 0: |
| color = '#10b981' |
| elif val < 0: |
| color = '#ef4444' |
| else: |
| color = '#f59e0b' |
| 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) |
| |
| |
| 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: |
| |
| st.subheader("π Top 10 Holdings") |
| |
| |
| 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) |
| |
| |
| 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) |
|
|
| |
| st.markdown("---") |
| st.subheader("π Portfolio Performance") |
|
|
| |
| chart_fig = generate_portfolio_chart() |
| st.plotly_chart(chart_fig, use_container_width=True) |
|
|
| |
| 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) |
|
|
| |
| 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% |
| """) |
|
|
| |
| 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) |
|
|
| |
| |
| |
| 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__) |
| |
| |
| st.write("**Total Holdings:**", len(ALL_PORTFOLIO)) |
| |
| |
| if st.button("π Refresh Stock Data"): |
| st.rerun() |