eagle0504's picture
Upload folder using huggingface_hub
06df807 verified
import streamlit as st
import yfinance as yf
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px
from datetime import datetime, timedelta
import numpy as np
import anthropic
import json
# Page config
st.set_page_config(
page_title="Meta Stock Analysis",
page_icon="πŸ“ˆ",
layout="wide",
initial_sidebar_state="expanded"
)
# Title and description
st.title("πŸ“ˆ Meta (META) Stock Analysis Dashboard")
st.markdown("Real-time analysis of Meta Platforms Inc. stock performance with AI-powered insights")
# Sidebar for controls and chatbot
st.sidebar.header("πŸ”‘ API Configuration")
# Anthropic API Key input
api_key = st.sidebar.text_input(
"Enter your Anthropic API Key:",
type="password",
help="Enter your Anthropic API key to enable the AI stock analyst chatbot"
)
# Initialize session state for chat
if 'chat_messages' not in st.session_state:
st.session_state.chat_messages = []
# Sidebar for analysis parameters
st.sidebar.header("πŸ“Š Analysis Parameters")
# Time period selection
period_options = {
"1 Month": "1mo",
"3 Months": "3mo",
"6 Months": "6mo",
"1 Year": "1y",
"2 Years": "2y",
"5 Years": "5y"
}
selected_period = st.sidebar.selectbox(
"Select Time Period",
options=list(period_options.keys()),
index=3 # Default to 1 Year
)
# Moving averages
ma_short = st.sidebar.number_input("Short MA (days)", min_value=5, max_value=50, value=20)
ma_long = st.sidebar.number_input("Long MA (days)", min_value=50, max_value=200, value=50)
# Load data function
@st.cache_data(ttl=300) # Cache for 5 minutes
def load_stock_data(symbol, period):
"""Load stock data from Yahoo Finance"""
try:
ticker = yf.Ticker(symbol)
data = ticker.history(period=period)
info = ticker.info
return data, info
except Exception as e:
st.error(f"Error loading data: {str(e)}")
return None, None
# Technical indicators functions
def calculate_rsi(data, window=14):
"""Calculate RSI (Relative Strength Index)"""
delta = data['Close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def calculate_macd(data, fast=12, slow=26, signal=9):
"""Calculate MACD indicator"""
exp1 = data['Close'].ewm(span=fast).mean()
exp2 = data['Close'].ewm(span=slow).mean()
macd = exp1 - exp2
signal_line = macd.ewm(span=signal).mean()
histogram = macd - signal_line
return macd, signal_line, histogram
def safe_format(value, format_str):
"""Safely format values that might be None or NaN"""
if value is None or pd.isna(value):
return "N/A"
try:
return format_str.format(value)
except:
return str(value)
def get_stock_analysis_context(data, info):
"""Prepare stock data context for AI analysis"""
if data is None or data.empty:
return "No stock data available."
# Current metrics
current_price = data['Close'].iloc[-1]
prev_close = data['Close'].iloc[-2]
price_change = current_price - prev_close
price_change_pct = (price_change / prev_close) * 100
# Technical indicators
current_rsi = data['RSI'].iloc[-1] if 'RSI' in data.columns and not pd.isna(data['RSI'].iloc[-1]) else None
current_macd = data['MACD'].iloc[-1] if 'MACD' in data.columns and not pd.isna(data['MACD'].iloc[-1]) else None
current_macd_signal = data['MACD_Signal'].iloc[-1] if 'MACD_Signal' in data.columns and not pd.isna(data['MACD_Signal'].iloc[-1]) else None
# Moving averages
ma_short_val = data['MA_Short'].iloc[-1] if 'MA_Short' in data.columns and not pd.isna(data['MA_Short'].iloc[-1]) else None
ma_long_val = data['MA_Long'].iloc[-1] if 'MA_Long' in data.columns and not pd.isna(data['MA_Long'].iloc[-1]) else None
# Volume analysis
current_volume = data['Volume'].iloc[-1]
avg_volume = data['Volume'].rolling(20).mean().iloc[-1]
# 52-week range
week_52_high = data['High'].rolling(252).max().iloc[-1] if len(data) >= 252 else data['High'].max()
week_52_low = data['Low'].rolling(252).min().iloc[-1] if len(data) >= 252 else data['Low'].min()
# Calculate returns safely
returns_5d = "N/A"
returns_20d = "N/A"
if len(data) >= 6:
returns_5d = safe_format(((data['Close'].iloc[-1] / data['Close'].iloc[-6]) - 1) * 100, "{:+.2f}%")
if len(data) >= 21:
returns_20d = safe_format(((data['Close'].iloc[-1] / data['Close'].iloc[-21]) - 1) * 100, "{:+.2f}%")
# RSI analysis
rsi_status = "N/A"
if current_rsi is not None:
if current_rsi > 70:
rsi_status = "(Overbought >70)"
elif current_rsi < 30:
rsi_status = "(Oversold <30)"
else:
rsi_status = "(Neutral)"
# MACD analysis
macd_position = "N/A"
if current_macd is not None and current_macd_signal is not None:
if current_macd > current_macd_signal:
macd_position = "Bullish (MACD > Signal)"
else:
macd_position = "Bearish (MACD < Signal)"
# Price vs MA analysis
price_vs_short_ma = "N/A"
price_vs_long_ma = "N/A"
if ma_short_val is not None:
if current_price > ma_short_val:
pct_diff = ((current_price/ma_short_val)-1)*100
price_vs_short_ma = f"Above (+{pct_diff:.1f}%)"
else:
pct_diff = ((current_price/ma_short_val)-1)*100
price_vs_short_ma = f"Below ({pct_diff:.1f}%)"
if ma_long_val is not None:
if current_price > ma_long_val:
pct_diff = ((current_price/ma_long_val)-1)*100
price_vs_long_ma = f"Above (+{pct_diff:.1f}%)"
else:
pct_diff = ((current_price/ma_long_val)-1)*100
price_vs_long_ma = f"Below ({pct_diff:.1f}%)"
context = f"""META STOCK ANALYSIS DATA (Last Updated: {data.index[-1].strftime('%Y-%m-%d')}):
CURRENT PRICE METRICS:
- Current Price: ${current_price:.2f}
- Daily Change: ${price_change:+.2f} ({price_change_pct:+.2f}%)
- 52-Week High: ${week_52_high:.2f}
- 52-Week Low: ${week_52_low:.2f}
- Current Volume: {current_volume:,.0f}
- 20-Day Avg Volume: {avg_volume:,.0f}
TECHNICAL INDICATORS:
- RSI (14): {safe_format(current_rsi, '{:.1f}')} {rsi_status}
- MACD: {safe_format(current_macd, '{:.3f}')}
- MACD Signal: {safe_format(current_macd_signal, '{:.3f}')}
- MACD Position: {macd_position}
MOVING AVERAGES:
- {ma_short}-Day MA: ${safe_format(ma_short_val, '{:.2f}')}
- {ma_long}-Day MA: ${safe_format(ma_long_val, '{:.2f}')}
- Price vs Short MA: {price_vs_short_ma}
- Price vs Long MA: {price_vs_long_ma}
COMPANY INFO:
- Company: {info.get('longName', 'Meta Platforms Inc.')}
- Market Cap: ${safe_format(info.get('marketCap', 0)/1e9 if info.get('marketCap') else None, '{:.1f}B')}
- P/E Ratio: {info.get('trailingPE', 'N/A')}
- Sector: {info.get('sector', 'Technology')}
RECENT PERFORMANCE:
- 5-Day Return: {returns_5d}
- 20-Day Return: {returns_20d}
You are an expert stock analyst. Use this data to provide insights about whether META is overbought, oversold, or fairly valued based on technical indicators.
"""
return context
def chat_with_ai(messages, api_key, stock_context):
"""Chat with Anthropic AI using stock context"""
try:
client = anthropic.Anthropic(api_key=api_key)
# Prepare system message with stock context
system_message = f"""You are an expert stock analyst AI assistant specializing in Meta (META) stock analysis.
{stock_context}
Instructions for analysis:
1. Use the technical indicators (RSI, MACD, Moving Averages) to determine if the stock is overbought, oversold, or neutral
2. Consider multiple timeframes and indicators together
3. Provide specific reasoning for your conclusions
4. Give actionable insights while noting this is not financial advice
5. Be concise but thorough in your analysis
6. If asked about other stocks, politely redirect to Meta analysis
7. Use the current data provided to give relevant, timely insights
Key Analysis Rules:
- RSI > 70: Potentially overbought
- RSI < 30: Potentially oversold
- MACD above signal line: Bullish momentum
- MACD below signal line: Bearish momentum
- Price above both MAs: Uptrend
- Price below both MAs: Downtrend
- Volume above average: Strong conviction in moves
"""
# Convert messages to Anthropic format
formatted_messages = []
for msg in messages:
formatted_messages.append({
"role": msg["role"],
"content": msg["content"]
})
response = client.messages.create(
model="claude-3-haiku-20240307",
max_tokens=1000,
system=system_message,
messages=formatted_messages
)
return response.content[0].text
except Exception as e:
return f"Error: {str(e)}. Please check your API key and try again."
# Load Meta stock data
data, info = load_stock_data("META", period_options[selected_period])
if data is not None and not data.empty:
# Calculate indicators
data['MA_Short'] = data['Close'].rolling(window=ma_short).mean()
data['MA_Long'] = data['Close'].rolling(window=ma_long).mean()
data['RSI'] = calculate_rsi(data)
data['MACD'], data['MACD_Signal'], data['MACD_Histogram'] = calculate_macd(data)
# Get stock context for AI
stock_context = get_stock_analysis_context(data, info)
# Current price info
current_price = data['Close'].iloc[-1]
prev_close = data['Close'].iloc[-2]
price_change = current_price - prev_close
price_change_pct = (price_change / prev_close) * 100
# AI Chatbot in Sidebar
st.sidebar.header("πŸ€– AI Stock Analyst")
if api_key:
st.sidebar.success("βœ… API Key configured - Chat enabled!")
# Chat interface
st.sidebar.subheader("πŸ’¬ Ask about META stock")
# Display chat messages
chat_container = st.sidebar.container()
with chat_container:
for message in st.session_state.chat_messages:
if message["role"] == "user":
st.write(f"**You:** {message['content']}")
else:
st.write(f"**AI:** {message['content']}")
# Chat input
user_question = st.sidebar.text_input(
"Ask about META analysis:",
placeholder="Is META overbought right now?",
key="chat_input"
)
if st.sidebar.button("Send", key="send_chat"):
if user_question:
# Add user message
st.session_state.chat_messages.append({
"role": "user",
"content": user_question
})
# Get AI response
with st.spinner("πŸ€– AI analyzing..."):
ai_response = chat_with_ai(
st.session_state.chat_messages,
api_key,
stock_context
)
# Add AI response
st.session_state.chat_messages.append({
"role": "assistant",
"content": ai_response
})
st.rerun()
# Quick analysis buttons
st.sidebar.subheader("🎯 Quick Analysis")
if st.sidebar.button("πŸ“Š Overall Analysis"):
quick_question = "Based on all the technical indicators, is META currently overbought, oversold, or fairly valued? Give me a comprehensive analysis."
st.session_state.chat_messages.append({"role": "user", "content": quick_question})
with st.spinner("πŸ€– Analyzing..."):
ai_response = chat_with_ai(st.session_state.chat_messages, api_key, stock_context)
st.session_state.chat_messages.append({"role": "assistant", "content": ai_response})
st.rerun()
if st.sidebar.button("🎯 Buy/Sell Signal"):
quick_question = "Should I buy, sell, or hold META stock right now based on the technical indicators?"
st.session_state.chat_messages.append({"role": "user", "content": quick_question})
with st.spinner("πŸ€– Analyzing..."):
ai_response = chat_with_ai(st.session_state.chat_messages, api_key, stock_context)
st.session_state.chat_messages.append({"role": "assistant", "content": ai_response})
st.rerun()
if st.sidebar.button("πŸ“ˆ Risk Assessment"):
quick_question = "What are the current risks and opportunities for META stock based on the technical analysis?"
st.session_state.chat_messages.append({"role": "user", "content": quick_question})
with st.spinner("πŸ€– Analyzing..."):
ai_response = chat_with_ai(st.session_state.chat_messages, api_key, stock_context)
st.session_state.chat_messages.append({"role": "assistant", "content": ai_response})
st.rerun()
# Clear chat button
if st.sidebar.button("πŸ—‘οΈ Clear Chat"):
st.session_state.chat_messages = []
st.rerun()
else:
st.sidebar.warning("⚠️ Enter Anthropic API key to enable AI chat")
st.sidebar.info("Get your API key from: https://console.anthropic.com/")
# Display key metrics
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric(
"Current Price",
f"${current_price:.2f}",
f"{price_change:+.2f} ({price_change_pct:+.2f}%)"
)
with col2:
day_high = data['High'].iloc[-1]
day_low = data['Low'].iloc[-1]
st.metric("Day Range", f"${day_low:.2f} - ${day_high:.2f}")
with col3:
volume = data['Volume'].iloc[-1]
avg_volume = data['Volume'].rolling(20).mean().iloc[-1]
volume_ratio = volume / avg_volume
st.metric(
"Volume",
f"{volume:,.0f}",
f"{volume_ratio:.2f}x avg"
)
with col4:
market_cap = info.get('marketCap', 0)
if market_cap:
market_cap_b = market_cap / 1e9
st.metric("Market Cap", f"${market_cap_b:.1f}B")
# Main price chart
st.subheader("πŸ“Š Price Chart with Moving Averages")
fig_price = go.Figure()
# Candlestick chart
fig_price.add_trace(go.Candlestick(
x=data.index,
open=data['Open'],
high=data['High'],
low=data['Low'],
close=data['Close'],
name="META"
))
# Moving averages
fig_price.add_trace(go.Scatter(
x=data.index,
y=data['MA_Short'],
name=f"MA {ma_short}",
line=dict(color='orange', width=2)
))
fig_price.add_trace(go.Scatter(
x=data.index,
y=data['MA_Long'],
name=f"MA {ma_long}",
line=dict(color='red', width=2)
))
fig_price.update_layout(
title="Meta Stock Price with Moving Averages",
yaxis_title="Price ($)",
xaxis_title="Date",
height=500,
showlegend=True
)
st.plotly_chart(fig_price, use_container_width=True)
# Technical indicators
col1, col2 = st.columns(2)
with col1:
st.subheader("πŸ“ˆ RSI (Relative Strength Index)")
fig_rsi = go.Figure()
fig_rsi.add_trace(go.Scatter(
x=data.index,
y=data['RSI'],
name="RSI",
line=dict(color='purple', width=2)
))
fig_rsi.add_hline(y=70, line_dash="dash", line_color="red", annotation_text="Overbought (70)")
fig_rsi.add_hline(y=30, line_dash="dash", line_color="green", annotation_text="Oversold (30)")
fig_rsi.update_layout(
yaxis_title="RSI",
xaxis_title="Date",
height=300,
yaxis=dict(range=[0, 100])
)
st.plotly_chart(fig_rsi, use_container_width=True)
current_rsi = data['RSI'].iloc[-1]
if pd.notna(current_rsi):
if current_rsi > 70:
st.warning(f"⚠️ RSI: {current_rsi:.1f} - Potentially Overbought")
elif current_rsi < 30:
st.success(f"βœ… RSI: {current_rsi:.1f} - Potentially Oversold")
else:
st.info(f"ℹ️ RSI: {current_rsi:.1f} - Neutral")
with col2:
st.subheader("πŸ“Š MACD")
fig_macd = go.Figure()
fig_macd.add_trace(go.Scatter(
x=data.index,
y=data['MACD'],
name="MACD",
line=dict(color='blue', width=2)
))
fig_macd.add_trace(go.Scatter(
x=data.index,
y=data['MACD_Signal'],
name="Signal",
line=dict(color='red', width=2)
))
fig_macd.add_trace(go.Bar(
x=data.index,
y=data['MACD_Histogram'],
name="Histogram",
opacity=0.7
))
fig_macd.update_layout(
yaxis_title="MACD",
xaxis_title="Date",
height=300
)
st.plotly_chart(fig_macd, use_container_width=True)
# Volume analysis
st.subheader("πŸ“Š Volume Analysis")
fig_volume = px.bar(
x=data.index,
y=data['Volume'],
title="Daily Trading Volume"
)
fig_volume.update_layout(
yaxis_title="Volume",
xaxis_title="Date",
height=300
)
st.plotly_chart(fig_volume, use_container_width=True)
# Company information
if info:
st.subheader("🏒 Company Information")
col1, col2 = st.columns(2)
with col1:
st.write(f"**Company:** {info.get('longName', 'Meta Platforms Inc.')}")
st.write(f"**Sector:** {info.get('sector', 'N/A')}")
st.write(f"**Industry:** {info.get('industry', 'N/A')}")
st.write(f"**Employees:** {info.get('fullTimeEmployees', 'N/A'):,}" if info.get('fullTimeEmployees') else "**Employees:** N/A")
with col2:
st.write(f"**P/E Ratio:** {info.get('trailingPE', 'N/A')}")
st.write(f"**52W High:** ${info.get('fiftyTwoWeekHigh', 'N/A')}")
st.write(f"**52W Low:** ${info.get('fiftyTwoWeekLow', 'N/A')}")
st.write(f"**Dividend Yield:** {info.get('dividendYield', 'N/A')}")
# Company description
if 'longBusinessSummary' in info:
st.subheader("πŸ“„ Business Summary")
st.write(info['longBusinessSummary'])
# Performance summary
st.subheader("πŸ“ˆ Performance Summary")
# Calculate returns
returns_1d = ((data['Close'].iloc[-1] / data['Close'].iloc[-2]) - 1) * 100
returns_1w = ((data['Close'].iloc[-1] / data['Close'].iloc[-8]) - 1) * 100 if len(data) >= 8 else None
returns_1m = ((data['Close'].iloc[-1] / data['Close'].iloc[-22]) - 1) * 100 if len(data) >= 22 else None
returns_ytd = ((data['Close'].iloc[-1] / data['Close'].iloc[0]) - 1) * 100
perf_col1, perf_col2, perf_col3, perf_col4 = st.columns(4)
with perf_col1:
st.metric("1 Day Return", f"{returns_1d:+.2f}%")
with perf_col2:
if returns_1w is not None:
st.metric("1 Week Return", f"{returns_1w:+.2f}%")
with perf_col3:
if returns_1m is not None:
st.metric("1 Month Return", f"{returns_1m:+.2f}%")
with perf_col4:
st.metric(f"{selected_period} Return", f"{returns_ytd:+.2f}%")
else:
st.error("❌ Unable to load Meta stock data. Please check your internet connection and try again.")
# Footer
st.markdown("---")
st.markdown("**Disclaimer:** This is for educational purposes only and should not be considered as investment advice.")
st.markdown("**AI Analysis:** The AI chatbot provides analysis based on technical indicators but should not be used as the sole basis for investment decisions.")
st.markdown("Data source: Yahoo Finance via yfinance library β€’ AI: Anthropic Claude")