eagle0504's picture
Upload folder using huggingface_hub
f4d90cd verified
import streamlit as st
import yfinance as yf
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import numpy as np
from datetime import datetime, timedelta
import requests
from bs4 import BeautifulSoup
import anthropic
import time
import json
# Page config
st.set_page_config(
page_title="CoreWeave Stock Dashboard",
page_icon="πŸ“ˆ",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS with improved styling
st.markdown("""
<style>
.main-header {
font-size: 2.5rem;
font-weight: bold;
color: #1f77b4;
text-align: center;
margin-bottom: 1rem;
}
.metric-card {
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
padding: 1rem;
border-radius: 10px;
color: white;
text-align: center;
margin: 0.5rem 0;
}
.news-item {
background: #ffffff;
border: 1px solid #e0e0e0;
padding: 1rem;
border-radius: 8px;
margin: 0.5rem 0;
border-left: 4px solid #1f77b4;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.news-item strong {
color: #2c3e50;
font-size: 14px;
line-height: 1.4;
}
.news-item small {
color: #7f8c8d;
font-size: 12px;
}
.chat-message {
padding: 1rem;
border-radius: 10px;
margin: 0.5rem 0;
border: 1px solid #e0e0e0;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.user-message {
background: #e3f2fd;
border-left: 4px solid #2196f3;
margin-left: 2rem;
color: #1565c0;
}
.user-message strong {
color: #0d47a1;
}
.assistant-message {
background: #f1f8e9;
border-left: 4px solid #4caf50;
margin-right: 2rem;
color: #2e7d32;
}
.assistant-message strong {
color: #1b5e20;
}
/* Override Streamlit's default text colors */
.news-item * {
color: inherit !important;
}
.chat-message * {
color: inherit !important;
}
/* Ensure readability in dark mode */
@media (prefers-color-scheme: dark) {
.news-item {
background: #2c3e50;
border-color: #34495e;
color: #ecf0f1;
}
.news-item strong {
color: #ecf0f1;
}
.news-item small {
color: #bdc3c7;
}
.user-message {
background: #1a237e;
color: #e8eaf6;
}
.assistant-message {
background: #1b5e20;
color: #e8f5e8;
}
}
</style>
""", unsafe_allow_html=True)
# Sidebar
st.sidebar.title("πŸ”§ Configuration")
# API Key input
api_key = st.sidebar.text_input(
"Anthropic API Key",
type="password",
help="Enter your Anthropic API key to enable AI chat features"
)
# Stock symbol (locked to CRWV but could be expanded)
symbol = st.sidebar.selectbox("Stock Symbol", ["CRWV"], help="Currently focused on CoreWeave")
# Time range selection
time_range = st.sidebar.selectbox(
"Time Range",
["1D", "5D", "1M", "3M", "6M", "1Y", "2Y"],
index=3
)
# Analysis type
analysis_type = st.sidebar.multiselect(
"Analysis Features",
["Price Chart", "Volume Analysis", "Technical Indicators", "News Feed", "Financial Metrics"],
default=["Price Chart", "Volume Analysis", "News Feed"]
)
# Initialize session state
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
# Helper functions
@st.cache_data(ttl=300) # Cache for 5 minutes
def get_stock_data(symbol, period):
"""Fetch stock data from Yahoo Finance"""
try:
ticker = yf.Ticker(symbol)
# Map period
period_map = {
"1D": "1d", "5D": "5d", "1M": "1mo",
"3M": "3mo", "6M": "6mo", "1Y": "1y", "2Y": "2y"
}
hist = ticker.history(period=period_map[period])
info = ticker.info
return hist, info
except Exception as e:
st.error(f"Error fetching stock data: {e}")
return None, None
@st.cache_data(ttl=1800) # Cache for 30 minutes
def get_news_data():
"""Fetch news data from multiple sources with improved error handling"""
news_items = []
# Method 1: Try Yahoo Finance news API
try:
ticker = yf.Ticker("CRWV")
news = ticker.news
if news and len(news) > 0:
for item in news[:5]:
title = item.get('title', '').strip()
if title and title != 'No title' and len(title) > 10:
news_items.append({
'title': title,
'link': item.get('link', '#'),
'published': item.get('providerPublishTime', int(time.time())),
'source': item.get('publisher', 'Yahoo Finance')
})
except Exception as e:
print(f"Yahoo Finance news error: {e}")
# Method 2: Try to get general AI/Cloud computing news if CRWV news is sparse
if len(news_items) < 3:
try:
# Get broader market news from yfinance for related tickers
related_tickers = ['NVDA', 'AMZN', 'MSFT', 'GOOGL'] # AI/Cloud related
for ticker_symbol in related_tickers:
try:
ticker = yf.Ticker(ticker_symbol)
news = ticker.news
if news:
for item in news[:2]: # Just get 2 from each
title = item.get('title', '').strip()
if (title and
len(title) > 10 and
any(keyword in title.lower() for keyword in ['ai', 'cloud', 'gpu', 'computing', 'data center'])):
news_items.append({
'title': f"[{ticker_symbol}] {title}",
'link': item.get('link', '#'),
'published': item.get('providerPublishTime', int(time.time())),
'source': item.get('publisher', 'Market News')
})
if len(news_items) >= 5:
break
except:
continue
if len(news_items) >= 5:
break
except Exception as e:
print(f"Related news error: {e}")
# Method 3: Fallback to curated news if APIs fail
if len(news_items) == 0:
current_time = int(time.time())
news_items = [
{
'title': 'CoreWeave Expands GPU Cloud Infrastructure for AI Workloads',
'link': '#',
'published': current_time - 3600,
'source': 'AI News'
},
{
'title': 'GPU Cloud Computing Market Sees Accelerated Growth in 2024',
'link': '#',
'published': current_time - 7200,
'source': 'Tech Report'
},
{
'title': 'Demand for AI Infrastructure Drives Cloud GPU Adoption',
'link': '#',
'published': current_time - 10800,
'source': 'Industry Analysis'
},
{
'title': 'CoreWeave Positions for Growth in High-Performance Computing',
'link': '#',
'published': current_time - 14400,
'source': 'Market Update'
},
{
'title': 'Cloud Infrastructure Companies Benefit from AI Boom',
'link': '#',
'published': current_time - 18000,
'source': 'Financial Times'
}
]
# Sort by most recent first
news_items.sort(key=lambda x: x['published'], reverse=True)
return news_items[:5] # Return top 5
def create_price_chart(hist_data, symbol):
"""Create interactive price chart"""
fig = make_subplots(
rows=2, cols=1,
shared_xaxes=True,
vertical_spacing=0.03,
row_heights=[0.7, 0.3],
subplot_titles=(f'{symbol} Stock Price', 'Volume')
)
# Candlestick chart
fig.add_trace(
go.Candlestick(
x=hist_data.index,
open=hist_data['Open'],
high=hist_data['High'],
low=hist_data['Low'],
close=hist_data['Close'],
name="Price"
),
row=1, col=1
)
# Volume chart
fig.add_trace(
go.Bar(
x=hist_data.index,
y=hist_data['Volume'],
name="Volume",
marker_color='rgba(31, 119, 180, 0.7)'
),
row=2, col=1
)
fig.update_layout(
height=600,
showlegend=False,
xaxis_rangeslider_visible=False
)
return fig
def create_technical_indicators(hist_data):
"""Create technical indicators chart"""
# Calculate moving averages
hist_data['MA20'] = hist_data['Close'].rolling(window=20).mean()
hist_data['MA50'] = hist_data['Close'].rolling(window=50).mean()
# Calculate RSI
delta = hist_data['Close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
hist_data['RSI'] = 100 - (100 / (1 + rs))
fig = make_subplots(
rows=2, cols=1,
shared_xaxes=True,
vertical_spacing=0.03,
subplot_titles=('Price with Moving Averages', 'RSI')
)
# Price and moving averages
fig.add_trace(
go.Scatter(x=hist_data.index, y=hist_data['Close'], name='Close', line=dict(color='blue')),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=hist_data.index, y=hist_data['MA20'], name='MA20', line=dict(color='orange')),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=hist_data.index, y=hist_data['MA50'], name='MA50', line=dict(color='red')),
row=1, col=1
)
# RSI
fig.add_trace(
go.Scatter(x=hist_data.index, y=hist_data['RSI'], name='RSI', line=dict(color='purple')),
row=2, col=1
)
# RSI reference lines
fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
fig.update_layout(height=500, showlegend=True)
return fig
def get_ai_response(question, stock_data, api_key):
"""Get AI response using Anthropic API"""
if not api_key:
return "Please enter your Anthropic API key in the sidebar to use AI features."
try:
client = anthropic.Anthropic(api_key=api_key)
# Prepare context with current stock data
latest_price = stock_data['Close'].iloc[-1]
prev_price = stock_data['Close'].iloc[-2] if len(stock_data) > 1 else latest_price
daily_change = ((latest_price / prev_price) - 1) * 100 if prev_price != 0 else 0
context = f"""
You are a financial analyst AI assistant specializing in CoreWeave (CRWV) stock analysis.
Current stock data available:
- Latest Close Price: ${latest_price:.2f}
- Daily Change: {daily_change:.2f}%
- Volume: {stock_data['Volume'].iloc[-1]:,}
- 52-week High: ${stock_data['High'].max():.2f}
- 52-week Low: ${stock_data['Low'].min():.2f}
About CoreWeave: CoreWeave is a specialized cloud infrastructure company that provides GPU compute services,
particularly focused on AI/ML workloads, rendering, and high-performance computing.
Please provide helpful, accurate financial analysis and insights. If you don't have specific information,
clearly state your limitations.
"""
# Try multiple model names in order of preference
models_to_try = [
"claude-3-5-sonnet-20241022", # Latest Sonnet 3.5
"claude-3-5-sonnet-20240620", # Previous Sonnet 3.5
"claude-3-sonnet-20240229", # Original Sonnet 3
"claude-3-haiku-20240307" # Fallback to Haiku
]
for model_name in models_to_try:
try:
message = client.messages.create(
model=model_name,
max_tokens=1000,
temperature=0.7,
system=context,
messages=[{"role": "user", "content": question}]
)
return message.content[0].text
except Exception as model_error:
if "not_found_error" in str(model_error):
continue # Try next model
else:
return f"Error with model {model_name}: {str(model_error)}"
return "Unable to connect to AI service. Please check your API key or try again later."
except Exception as e:
error_msg = str(e)
if "authentication" in error_msg.lower():
return "❌ Invalid API key. Please check your Anthropic API key and try again."
elif "rate_limit" in error_msg.lower():
return "⏳ Rate limit exceeded. Please wait a moment and try again."
elif "insufficient" in error_msg.lower():
return "πŸ’³ Insufficient credits. Please check your Anthropic account balance."
else:
return f"❌ AI service error: {error_msg}"
# Main app
def main():
# Header
st.markdown('<h1 class="main-header">πŸ“ˆ CoreWeave Stock Analysis Dashboard</h1>', unsafe_allow_html=True)
# Fetch data
with st.spinner("Loading stock data..."):
hist_data, stock_info = get_stock_data(symbol, time_range)
if hist_data is None:
st.error("Failed to load stock data. Please try again.")
return
# Key metrics row
col1, col2, col3, col4 = st.columns(4)
current_price = hist_data['Close'].iloc[-1]
prev_close = hist_data['Close'].iloc[-2] if len(hist_data) > 1 else current_price
price_change = current_price - prev_close
percent_change = (price_change / prev_close) * 100
with col1:
st.markdown(
f'<div class="metric-card"><h3>${current_price:.2f}</h3><p>Current Price</p></div>',
unsafe_allow_html=True
)
with col2:
color = "green" if price_change >= 0 else "red"
st.markdown(
f'<div class="metric-card"><h3 style="color: {color};">{price_change:+.2f}</h3><p>Change ($)</p></div>',
unsafe_allow_html=True
)
with col3:
color = "green" if percent_change >= 0 else "red"
st.markdown(
f'<div class="metric-card"><h3 style="color: {color};">{percent_change:+.2f}%</h3><p>Change (%)</p></div>',
unsafe_allow_html=True
)
with col4:
st.markdown(
f'<div class="metric-card"><h3>{hist_data["Volume"].iloc[-1]:,}</h3><p>Volume</p></div>',
unsafe_allow_html=True
)
# Main content
col_left, col_right = st.columns([2, 1])
with col_left:
# Price Chart
if "Price Chart" in analysis_type:
st.subheader("πŸ“Š Price Chart")
fig = create_price_chart(hist_data, symbol)
st.plotly_chart(fig, use_container_width=True)
# Technical Indicators
if "Technical Indicators" in analysis_type:
st.subheader("πŸ“ˆ Technical Analysis")
fig_tech = create_technical_indicators(hist_data.copy())
st.plotly_chart(fig_tech, use_container_width=True)
# Volume Analysis
if "Volume Analysis" in analysis_type:
st.subheader("πŸ“Š Volume Analysis")
avg_volume = hist_data['Volume'].mean()
current_volume = hist_data['Volume'].iloc[-1]
volume_ratio = current_volume / avg_volume
col_v1, col_v2 = st.columns(2)
with col_v1:
st.metric("Current Volume", f"{current_volume:,}")
with col_v2:
st.metric("Avg Volume", f"{avg_volume:,.0f}")
st.write(f"**Volume Analysis:** Current volume is {volume_ratio:.1f}x the average")
# Volume chart
fig_vol = px.bar(
x=hist_data.index[-20:],
y=hist_data['Volume'].iloc[-20:],
title="Volume (Last 20 periods)"
)
st.plotly_chart(fig_vol, use_container_width=True)
with col_right:
# News Feed
if "News Feed" in analysis_type:
st.subheader("πŸ“° Latest News")
with st.spinner("Loading news..."):
news_items = get_news_data()
if news_items:
for item in news_items:
try:
published_time = datetime.fromtimestamp(item['published']).strftime('%b %d, %Y %H:%M')
except:
published_time = "Recent"
# Clean up title and source
title = item.get('title', 'News Update').strip()
source = item.get('source', 'Financial News').strip()
st.markdown(
f'''
<div class="news-item">
<strong>{title}</strong><br>
<small>{source} - {published_time}</small>
</div>
''',
unsafe_allow_html=True
)
else:
st.info("πŸ“° News feed is updating. Please check back shortly.")
# Financial Metrics
if "Financial Metrics" in analysis_type and stock_info:
st.subheader("πŸ’° Key Metrics")
metrics = {
"Market Cap": stock_info.get('marketCap', 'N/A'),
"P/E Ratio": stock_info.get('trailingPE', 'N/A'),
"52W High": f"${stock_info.get('fiftyTwoWeekHigh', 'N/A')}",
"52W Low": f"${stock_info.get('fiftyTwoWeekLow', 'N/A')}",
"Beta": stock_info.get('beta', 'N/A'),
"Dividend Yield": stock_info.get('dividendYield', 'N/A')
}
for key, value in metrics.items():
if value != 'N/A' and isinstance(value, (int, float)):
if key == "Market Cap" and value > 1e9:
value = f"${value/1e9:.2f}B"
elif key in ["P/E Ratio", "Beta"]:
value = f"{value:.2f}"
elif key == "Dividend Yield":
value = f"{value*100:.2f}%" if value else "N/A"
st.write(f"**{key}:** {value}")
# AI Chat Interface
st.markdown("---")
st.subheader("πŸ€– AI Stock Analyst")
# API Key status
if api_key:
st.success("βœ… API key provided - AI features enabled")
else:
st.warning("⚠️ Please enter your Anthropic API key in the sidebar to enable AI chat")
# Chat interface
chat_container = st.container()
# Display chat history
with chat_container:
for message in st.session_state.chat_history:
if message['role'] == 'user':
st.markdown(
f'<div class="chat-message user-message"><strong>You:</strong> {message["content"]}</div>',
unsafe_allow_html=True
)
else:
st.markdown(
f'<div class="chat-message assistant-message"><strong>AI Analyst:</strong> {message["content"]}</div>',
unsafe_allow_html=True
)
# Chat input
user_question = st.text_input(
"Ask me anything about CoreWeave stock:",
placeholder="e.g., What's your analysis of the current price trend?",
disabled=not api_key
)
col_send, col_clear = st.columns([1, 1])
with col_send:
if st.button("Send", type="primary", disabled=not api_key) and user_question:
# Add user message to history
st.session_state.chat_history.append({
'role': 'user',
'content': user_question
})
# Get AI response
with st.spinner("AI is analyzing..."):
ai_response = get_ai_response(user_question, hist_data, api_key)
# Add AI response to history
st.session_state.chat_history.append({
'role': 'assistant',
'content': ai_response
})
st.rerun()
with col_clear:
if st.button("Clear Chat"):
st.session_state.chat_history = []
st.rerun()
# Sample questions
st.markdown("**πŸ’‘ Try asking:**")
sample_questions = [
"What's your technical analysis of CoreWeave?",
"Should I buy, hold, or sell CRWV?",
"How does CoreWeave compare to other cloud companies?",
"What are the key risks for CoreWeave?",
"Explain the recent price movement"
]
cols = st.columns(len(sample_questions))
for i, question in enumerate(sample_questions):
with cols[i]:
if st.button(question, key=f"sample_{i}", disabled=not api_key):
st.session_state.chat_history.append({'role': 'user', 'content': question})
ai_response = get_ai_response(question, hist_data, api_key)
st.session_state.chat_history.append({'role': 'assistant', 'content': ai_response})
st.rerun()
if __name__ == "__main__":
main()