Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- README.md +82 -6
- app.py +484 -0
- requirements.txt +9 -0
README.md
CHANGED
|
@@ -1,12 +1,88 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: green
|
| 6 |
-
sdk:
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: CoreWeave Stock Analysis Dashboard
|
| 3 |
+
emoji: π
|
| 4 |
+
colorFrom: blue
|
| 5 |
colorTo: green
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.34.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# π CoreWeave Stock Analysis Dashboard
|
| 14 |
+
|
| 15 |
+
A comprehensive AI-powered dashboard for analyzing CoreWeave (CRWV) stock with real-time data and intelligent insights.
|
| 16 |
+
|
| 17 |
+
## π Features
|
| 18 |
+
|
| 19 |
+
### π Real-Time Stock Analysis
|
| 20 |
+
- **Live Stock Data**: Current price, volume, and market metrics from Yahoo Finance
|
| 21 |
+
- **Interactive Charts**: Professional candlestick charts with volume analysis
|
| 22 |
+
- **Multiple Timeframes**: 1D to 2Y analysis periods
|
| 23 |
+
- **Technical Indicators**: Moving averages, RSI, and trend analysis
|
| 24 |
+
|
| 25 |
+
### π€ AI Stock Analyst
|
| 26 |
+
- **Powered by Anthropic Claude**: Ask natural language questions about CoreWeave stock
|
| 27 |
+
- **Intelligent Insights**: Get technical analysis, risk assessment, and investment guidance
|
| 28 |
+
- **Context-Aware**: Responses based on current market data and stock performance
|
| 29 |
+
- **Sample Questions**: Pre-built queries to get you started
|
| 30 |
+
|
| 31 |
+
### π° Market Intelligence
|
| 32 |
+
- **Latest News**: Real-time CoreWeave and market news integration
|
| 33 |
+
- **Financial Metrics**: Market cap, P/E ratio, 52-week ranges, and key ratios
|
| 34 |
+
- **Volume Analysis**: Trading volume trends and comparisons
|
| 35 |
+
|
| 36 |
+
## π― How to Use
|
| 37 |
+
|
| 38 |
+
1. **Enter API Key**: Add your Anthropic API key in the left sidebar to enable AI features
|
| 39 |
+
2. **Select Analysis**: Choose from Price Charts, Volume Analysis, Technical Indicators, News Feed
|
| 40 |
+
3. **Customize Timeframe**: Select from 1D, 5D, 1M, 3M, 6M, 1Y, or 2Y
|
| 41 |
+
4. **Ask Questions**: Use the AI chat to get insights about CoreWeave stock
|
| 42 |
+
|
| 43 |
+
## π‘ Sample AI Questions
|
| 44 |
+
|
| 45 |
+
- "What's your technical analysis of CoreWeave?"
|
| 46 |
+
- "Should I buy, hold, or sell CRWV?"
|
| 47 |
+
- "How does CoreWeave compare to other cloud companies?"
|
| 48 |
+
- "What are the key risks for CoreWeave?"
|
| 49 |
+
- "Explain the recent price movement"
|
| 50 |
+
|
| 51 |
+
## π§ Configuration
|
| 52 |
+
|
| 53 |
+
### Required: Anthropic API Key
|
| 54 |
+
To use the AI features, you'll need an Anthropic API key:
|
| 55 |
+
1. Visit [Anthropic Console](https://console.anthropic.com/)
|
| 56 |
+
2. Create an account and generate an API key
|
| 57 |
+
3. Enter the key in the dashboard sidebar
|
| 58 |
+
|
| 59 |
+
### Analysis Options
|
| 60 |
+
- **Price Chart**: Interactive candlestick chart with volume
|
| 61 |
+
- **Volume Analysis**: Trading volume trends and analysis
|
| 62 |
+
- **Technical Indicators**: Moving averages and RSI
|
| 63 |
+
- **News Feed**: Latest CoreWeave and market news
|
| 64 |
+
- **Financial Metrics**: Key company financial ratios
|
| 65 |
+
|
| 66 |
+
## π About CoreWeave
|
| 67 |
+
|
| 68 |
+
CoreWeave is a specialized cloud infrastructure company that provides GPU compute services, particularly focused on:
|
| 69 |
+
- AI/ML workloads
|
| 70 |
+
- High-performance computing
|
| 71 |
+
- Rendering and graphics processing
|
| 72 |
+
- Cloud gaming infrastructure
|
| 73 |
+
|
| 74 |
+
## β οΈ Disclaimer
|
| 75 |
+
|
| 76 |
+
This dashboard is for informational and educational purposes only. It should not be considered as financial advice. Always conduct your own research and consult with financial professionals before making investment decisions. Past performance does not guarantee future results.
|
| 77 |
+
|
| 78 |
+
## π οΈ Technical Stack
|
| 79 |
+
|
| 80 |
+
- **Frontend**: Streamlit with custom CSS styling
|
| 81 |
+
- **Data**: Yahoo Finance API for real-time stock data
|
| 82 |
+
- **AI**: Anthropic Claude for intelligent analysis
|
| 83 |
+
- **Charts**: Plotly for interactive visualizations
|
| 84 |
+
- **Deployment**: HuggingFace Spaces
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
**π Start analyzing CoreWeave stock with AI-powered insights!**
|
app.py
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import yfinance as yf
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import plotly.graph_objects as go
|
| 5 |
+
import plotly.express as px
|
| 6 |
+
from plotly.subplots import make_subplots
|
| 7 |
+
import numpy as np
|
| 8 |
+
from datetime import datetime, timedelta
|
| 9 |
+
import requests
|
| 10 |
+
from bs4 import BeautifulSoup
|
| 11 |
+
import anthropic
|
| 12 |
+
import time
|
| 13 |
+
|
| 14 |
+
# Page config
|
| 15 |
+
st.set_page_config(
|
| 16 |
+
page_title="CoreWeave Stock Dashboard",
|
| 17 |
+
page_icon="π",
|
| 18 |
+
layout="wide",
|
| 19 |
+
initial_sidebar_state="expanded"
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
# Custom CSS
|
| 23 |
+
st.markdown("""
|
| 24 |
+
<style>
|
| 25 |
+
.main-header {
|
| 26 |
+
font-size: 2.5rem;
|
| 27 |
+
font-weight: bold;
|
| 28 |
+
color: #1f77b4;
|
| 29 |
+
text-align: center;
|
| 30 |
+
margin-bottom: 1rem;
|
| 31 |
+
}
|
| 32 |
+
.metric-card {
|
| 33 |
+
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
| 34 |
+
padding: 1rem;
|
| 35 |
+
border-radius: 10px;
|
| 36 |
+
color: white;
|
| 37 |
+
text-align: center;
|
| 38 |
+
margin: 0.5rem 0;
|
| 39 |
+
}
|
| 40 |
+
.news-item {
|
| 41 |
+
background: #f8f9fa;
|
| 42 |
+
padding: 1rem;
|
| 43 |
+
border-radius: 8px;
|
| 44 |
+
margin: 0.5rem 0;
|
| 45 |
+
border-left: 4px solid #1f77b4;
|
| 46 |
+
}
|
| 47 |
+
.chat-message {
|
| 48 |
+
padding: 1rem;
|
| 49 |
+
border-radius: 10px;
|
| 50 |
+
margin: 0.5rem 0;
|
| 51 |
+
}
|
| 52 |
+
.user-message {
|
| 53 |
+
background: #e3f2fd;
|
| 54 |
+
margin-left: 2rem;
|
| 55 |
+
}
|
| 56 |
+
.assistant-message {
|
| 57 |
+
background: #f1f8e9;
|
| 58 |
+
margin-right: 2rem;
|
| 59 |
+
}
|
| 60 |
+
</style>
|
| 61 |
+
""", unsafe_allow_html=True)
|
| 62 |
+
|
| 63 |
+
# Sidebar
|
| 64 |
+
st.sidebar.title("π§ Configuration")
|
| 65 |
+
|
| 66 |
+
# API Key input
|
| 67 |
+
api_key = st.sidebar.text_input(
|
| 68 |
+
"Anthropic API Key",
|
| 69 |
+
type="password",
|
| 70 |
+
help="Enter your Anthropic API key to enable AI chat features"
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
# Stock symbol (locked to CRWV but could be expanded)
|
| 74 |
+
symbol = st.sidebar.selectbox("Stock Symbol", ["CRWV"], help="Currently focused on CoreWeave")
|
| 75 |
+
|
| 76 |
+
# Time range selection
|
| 77 |
+
time_range = st.sidebar.selectbox(
|
| 78 |
+
"Time Range",
|
| 79 |
+
["1D", "5D", "1M", "3M", "6M", "1Y", "2Y"],
|
| 80 |
+
index=3
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
# Analysis type
|
| 84 |
+
analysis_type = st.sidebar.multiselect(
|
| 85 |
+
"Analysis Features",
|
| 86 |
+
["Price Chart", "Volume Analysis", "Technical Indicators", "News Feed", "Financial Metrics"],
|
| 87 |
+
default=["Price Chart", "Volume Analysis", "News Feed"]
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
# Initialize session state
|
| 91 |
+
if 'chat_history' not in st.session_state:
|
| 92 |
+
st.session_state.chat_history = []
|
| 93 |
+
|
| 94 |
+
# Helper functions
|
| 95 |
+
@st.cache_data(ttl=300) # Cache for 5 minutes
|
| 96 |
+
def get_stock_data(symbol, period):
|
| 97 |
+
"""Fetch stock data from Yahoo Finance"""
|
| 98 |
+
try:
|
| 99 |
+
ticker = yf.Ticker(symbol)
|
| 100 |
+
|
| 101 |
+
# Map period
|
| 102 |
+
period_map = {
|
| 103 |
+
"1D": "1d", "5D": "5d", "1M": "1mo",
|
| 104 |
+
"3M": "3mo", "6M": "6mo", "1Y": "1y", "2Y": "2y"
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
hist = ticker.history(period=period_map[period])
|
| 108 |
+
info = ticker.info
|
| 109 |
+
|
| 110 |
+
return hist, info
|
| 111 |
+
except Exception as e:
|
| 112 |
+
st.error(f"Error fetching stock data: {e}")
|
| 113 |
+
return None, None
|
| 114 |
+
|
| 115 |
+
@st.cache_data(ttl=1800) # Cache for 30 minutes
|
| 116 |
+
def get_news_data():
|
| 117 |
+
"""Fetch news data from multiple sources"""
|
| 118 |
+
news_items = []
|
| 119 |
+
|
| 120 |
+
# Try to get news from Yahoo Finance
|
| 121 |
+
try:
|
| 122 |
+
ticker = yf.Ticker("CRWV")
|
| 123 |
+
news = ticker.news
|
| 124 |
+
|
| 125 |
+
for item in news[:10]:
|
| 126 |
+
news_items.append({
|
| 127 |
+
'title': item.get('title', 'No title'),
|
| 128 |
+
'link': item.get('link', '#'),
|
| 129 |
+
'published': item.get('providerPublishTime', int(time.time())),
|
| 130 |
+
'source': item.get('publisher', 'Unknown')
|
| 131 |
+
})
|
| 132 |
+
except:
|
| 133 |
+
pass
|
| 134 |
+
|
| 135 |
+
# Add some sample news if no real news found
|
| 136 |
+
if not news_items:
|
| 137 |
+
news_items = [
|
| 138 |
+
{
|
| 139 |
+
'title': 'CoreWeave Expands AI Cloud Infrastructure',
|
| 140 |
+
'link': '#',
|
| 141 |
+
'published': int(time.time()) - 3600,
|
| 142 |
+
'source': 'TechNews'
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
'title': 'GPU Cloud Computing Market Shows Strong Growth',
|
| 146 |
+
'link': '#',
|
| 147 |
+
'published': int(time.time()) - 7200,
|
| 148 |
+
'source': 'MarketWatch'
|
| 149 |
+
}
|
| 150 |
+
]
|
| 151 |
+
|
| 152 |
+
return news_items
|
| 153 |
+
|
| 154 |
+
def create_price_chart(hist_data, symbol):
|
| 155 |
+
"""Create interactive price chart"""
|
| 156 |
+
fig = make_subplots(
|
| 157 |
+
rows=2, cols=1,
|
| 158 |
+
shared_xaxes=True,
|
| 159 |
+
vertical_spacing=0.03,
|
| 160 |
+
row_heights=[0.7, 0.3],
|
| 161 |
+
subplot_titles=(f'{symbol} Stock Price', 'Volume')
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
# Candlestick chart
|
| 165 |
+
fig.add_trace(
|
| 166 |
+
go.Candlestick(
|
| 167 |
+
x=hist_data.index,
|
| 168 |
+
open=hist_data['Open'],
|
| 169 |
+
high=hist_data['High'],
|
| 170 |
+
low=hist_data['Low'],
|
| 171 |
+
close=hist_data['Close'],
|
| 172 |
+
name="Price"
|
| 173 |
+
),
|
| 174 |
+
row=1, col=1
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
# Volume chart
|
| 178 |
+
fig.add_trace(
|
| 179 |
+
go.Bar(
|
| 180 |
+
x=hist_data.index,
|
| 181 |
+
y=hist_data['Volume'],
|
| 182 |
+
name="Volume",
|
| 183 |
+
marker_color='rgba(31, 119, 180, 0.7)'
|
| 184 |
+
),
|
| 185 |
+
row=2, col=1
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
fig.update_layout(
|
| 189 |
+
height=600,
|
| 190 |
+
showlegend=False,
|
| 191 |
+
xaxis_rangeslider_visible=False
|
| 192 |
+
)
|
| 193 |
+
|
| 194 |
+
return fig
|
| 195 |
+
|
| 196 |
+
def create_technical_indicators(hist_data):
|
| 197 |
+
"""Create technical indicators chart"""
|
| 198 |
+
# Calculate moving averages
|
| 199 |
+
hist_data['MA20'] = hist_data['Close'].rolling(window=20).mean()
|
| 200 |
+
hist_data['MA50'] = hist_data['Close'].rolling(window=50).mean()
|
| 201 |
+
|
| 202 |
+
# Calculate RSI
|
| 203 |
+
delta = hist_data['Close'].diff()
|
| 204 |
+
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
|
| 205 |
+
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
|
| 206 |
+
rs = gain / loss
|
| 207 |
+
hist_data['RSI'] = 100 - (100 / (1 + rs))
|
| 208 |
+
|
| 209 |
+
fig = make_subplots(
|
| 210 |
+
rows=2, cols=1,
|
| 211 |
+
shared_xaxes=True,
|
| 212 |
+
vertical_spacing=0.03,
|
| 213 |
+
subplot_titles=('Price with Moving Averages', 'RSI')
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
# Price and moving averages
|
| 217 |
+
fig.add_trace(
|
| 218 |
+
go.Scatter(x=hist_data.index, y=hist_data['Close'], name='Close', line=dict(color='blue')),
|
| 219 |
+
row=1, col=1
|
| 220 |
+
)
|
| 221 |
+
fig.add_trace(
|
| 222 |
+
go.Scatter(x=hist_data.index, y=hist_data['MA20'], name='MA20', line=dict(color='orange')),
|
| 223 |
+
row=1, col=1
|
| 224 |
+
)
|
| 225 |
+
fig.add_trace(
|
| 226 |
+
go.Scatter(x=hist_data.index, y=hist_data['MA50'], name='MA50', line=dict(color='red')),
|
| 227 |
+
row=1, col=1
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
# RSI
|
| 231 |
+
fig.add_trace(
|
| 232 |
+
go.Scatter(x=hist_data.index, y=hist_data['RSI'], name='RSI', line=dict(color='purple')),
|
| 233 |
+
row=2, col=1
|
| 234 |
+
)
|
| 235 |
+
|
| 236 |
+
# RSI reference lines
|
| 237 |
+
fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
|
| 238 |
+
fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
|
| 239 |
+
|
| 240 |
+
fig.update_layout(height=500, showlegend=True)
|
| 241 |
+
return fig
|
| 242 |
+
|
| 243 |
+
def get_ai_response(question, stock_data, api_key):
|
| 244 |
+
"""Get AI response using Anthropic API"""
|
| 245 |
+
if not api_key:
|
| 246 |
+
return "Please enter your Anthropic API key in the sidebar to use AI features."
|
| 247 |
+
|
| 248 |
+
try:
|
| 249 |
+
client = anthropic.Anthropic(api_key=api_key)
|
| 250 |
+
|
| 251 |
+
# Prepare context
|
| 252 |
+
context = f"""
|
| 253 |
+
You are a financial analyst AI assistant specializing in CoreWeave (CRWV) stock analysis.
|
| 254 |
+
|
| 255 |
+
Current stock data available:
|
| 256 |
+
- Latest Close Price: ${stock_data['Close'].iloc[-1]:.2f}
|
| 257 |
+
- Daily Change: {((stock_data['Close'].iloc[-1] / stock_data['Close'].iloc[-2]) - 1) * 100:.2f}%
|
| 258 |
+
- Volume: {stock_data['Volume'].iloc[-1]:,}
|
| 259 |
+
- 52-week High: ${stock_data['High'].max():.2f}
|
| 260 |
+
- 52-week Low: ${stock_data['Low'].min():.2f}
|
| 261 |
+
|
| 262 |
+
About CoreWeave: CoreWeave is a specialized cloud infrastructure company that provides GPU compute services,
|
| 263 |
+
particularly focused on AI/ML workloads, rendering, and high-performance computing.
|
| 264 |
+
|
| 265 |
+
Please provide helpful, accurate financial analysis and insights. If you don't have specific information,
|
| 266 |
+
clearly state your limitations.
|
| 267 |
+
"""
|
| 268 |
+
|
| 269 |
+
message = client.messages.create(
|
| 270 |
+
model="claude-3-sonnet-20240229",
|
| 271 |
+
max_tokens=1000,
|
| 272 |
+
temperature=0.7,
|
| 273 |
+
system=context,
|
| 274 |
+
messages=[{"role": "user", "content": question}]
|
| 275 |
+
)
|
| 276 |
+
|
| 277 |
+
return message.content[0].text
|
| 278 |
+
|
| 279 |
+
except Exception as e:
|
| 280 |
+
return f"Error getting AI response: {str(e)}"
|
| 281 |
+
|
| 282 |
+
# Main app
|
| 283 |
+
def main():
|
| 284 |
+
# Header
|
| 285 |
+
st.markdown('<h1 class="main-header">π CoreWeave Stock Analysis Dashboard</h1>', unsafe_allow_html=True)
|
| 286 |
+
|
| 287 |
+
# Fetch data
|
| 288 |
+
with st.spinner("Loading stock data..."):
|
| 289 |
+
hist_data, stock_info = get_stock_data(symbol, time_range)
|
| 290 |
+
|
| 291 |
+
if hist_data is None:
|
| 292 |
+
st.error("Failed to load stock data. Please try again.")
|
| 293 |
+
return
|
| 294 |
+
|
| 295 |
+
# Key metrics row
|
| 296 |
+
col1, col2, col3, col4 = st.columns(4)
|
| 297 |
+
|
| 298 |
+
current_price = hist_data['Close'].iloc[-1]
|
| 299 |
+
prev_close = hist_data['Close'].iloc[-2] if len(hist_data) > 1 else current_price
|
| 300 |
+
price_change = current_price - prev_close
|
| 301 |
+
percent_change = (price_change / prev_close) * 100
|
| 302 |
+
|
| 303 |
+
with col1:
|
| 304 |
+
st.markdown(
|
| 305 |
+
f'<div class="metric-card"><h3>${current_price:.2f}</h3><p>Current Price</p></div>',
|
| 306 |
+
unsafe_allow_html=True
|
| 307 |
+
)
|
| 308 |
+
|
| 309 |
+
with col2:
|
| 310 |
+
color = "green" if price_change >= 0 else "red"
|
| 311 |
+
st.markdown(
|
| 312 |
+
f'<div class="metric-card"><h3 style="color: {color};">{price_change:+.2f}</h3><p>Change ($)</p></div>',
|
| 313 |
+
unsafe_allow_html=True
|
| 314 |
+
)
|
| 315 |
+
|
| 316 |
+
with col3:
|
| 317 |
+
color = "green" if percent_change >= 0 else "red"
|
| 318 |
+
st.markdown(
|
| 319 |
+
f'<div class="metric-card"><h3 style="color: {color};">{percent_change:+.2f}%</h3><p>Change (%)</p></div>',
|
| 320 |
+
unsafe_allow_html=True
|
| 321 |
+
)
|
| 322 |
+
|
| 323 |
+
with col4:
|
| 324 |
+
st.markdown(
|
| 325 |
+
f'<div class="metric-card"><h3>{hist_data["Volume"].iloc[-1]:,}</h3><p>Volume</p></div>',
|
| 326 |
+
unsafe_allow_html=True
|
| 327 |
+
)
|
| 328 |
+
|
| 329 |
+
# Main content
|
| 330 |
+
col_left, col_right = st.columns([2, 1])
|
| 331 |
+
|
| 332 |
+
with col_left:
|
| 333 |
+
# Price Chart
|
| 334 |
+
if "Price Chart" in analysis_type:
|
| 335 |
+
st.subheader("π Price Chart")
|
| 336 |
+
fig = create_price_chart(hist_data, symbol)
|
| 337 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 338 |
+
|
| 339 |
+
# Technical Indicators
|
| 340 |
+
if "Technical Indicators" in analysis_type:
|
| 341 |
+
st.subheader("π Technical Analysis")
|
| 342 |
+
fig_tech = create_technical_indicators(hist_data.copy())
|
| 343 |
+
st.plotly_chart(fig_tech, use_container_width=True)
|
| 344 |
+
|
| 345 |
+
# Volume Analysis
|
| 346 |
+
if "Volume Analysis" in analysis_type:
|
| 347 |
+
st.subheader("π Volume Analysis")
|
| 348 |
+
avg_volume = hist_data['Volume'].mean()
|
| 349 |
+
current_volume = hist_data['Volume'].iloc[-1]
|
| 350 |
+
volume_ratio = current_volume / avg_volume
|
| 351 |
+
|
| 352 |
+
col_v1, col_v2 = st.columns(2)
|
| 353 |
+
with col_v1:
|
| 354 |
+
st.metric("Current Volume", f"{current_volume:,}")
|
| 355 |
+
with col_v2:
|
| 356 |
+
st.metric("Avg Volume", f"{avg_volume:,.0f}")
|
| 357 |
+
|
| 358 |
+
st.write(f"**Volume Analysis:** Current volume is {volume_ratio:.1f}x the average")
|
| 359 |
+
|
| 360 |
+
# Volume chart
|
| 361 |
+
fig_vol = px.bar(
|
| 362 |
+
x=hist_data.index[-20:],
|
| 363 |
+
y=hist_data['Volume'].iloc[-20:],
|
| 364 |
+
title="Volume (Last 20 periods)"
|
| 365 |
+
)
|
| 366 |
+
st.plotly_chart(fig_vol, use_container_width=True)
|
| 367 |
+
|
| 368 |
+
with col_right:
|
| 369 |
+
# News Feed
|
| 370 |
+
if "News Feed" in analysis_type:
|
| 371 |
+
st.subheader("π° Latest News")
|
| 372 |
+
news_items = get_news_data()
|
| 373 |
+
|
| 374 |
+
for item in news_items[:5]:
|
| 375 |
+
published_time = datetime.fromtimestamp(item['published']).strftime('%Y-%m-%d %H:%M')
|
| 376 |
+
st.markdown(
|
| 377 |
+
f'''
|
| 378 |
+
<div class="news-item">
|
| 379 |
+
<strong>{item['title']}</strong><br>
|
| 380 |
+
<small>{item['source']} - {published_time}</small>
|
| 381 |
+
</div>
|
| 382 |
+
''',
|
| 383 |
+
unsafe_allow_html=True
|
| 384 |
+
)
|
| 385 |
+
|
| 386 |
+
# Financial Metrics
|
| 387 |
+
if "Financial Metrics" in analysis_type and stock_info:
|
| 388 |
+
st.subheader("π° Key Metrics")
|
| 389 |
+
|
| 390 |
+
metrics = {
|
| 391 |
+
"Market Cap": stock_info.get('marketCap', 'N/A'),
|
| 392 |
+
"P/E Ratio": stock_info.get('trailingPE', 'N/A'),
|
| 393 |
+
"52W High": f"${stock_info.get('fiftyTwoWeekHigh', 'N/A')}",
|
| 394 |
+
"52W Low": f"${stock_info.get('fiftyTwoWeekLow', 'N/A')}",
|
| 395 |
+
"Beta": stock_info.get('beta', 'N/A'),
|
| 396 |
+
"Dividend Yield": stock_info.get('dividendYield', 'N/A')
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
for key, value in metrics.items():
|
| 400 |
+
if value != 'N/A' and isinstance(value, (int, float)):
|
| 401 |
+
if key == "Market Cap" and value > 1e9:
|
| 402 |
+
value = f"${value/1e9:.2f}B"
|
| 403 |
+
elif key in ["P/E Ratio", "Beta"]:
|
| 404 |
+
value = f"{value:.2f}"
|
| 405 |
+
elif key == "Dividend Yield":
|
| 406 |
+
value = f"{value*100:.2f}%" if value else "N/A"
|
| 407 |
+
|
| 408 |
+
st.write(f"**{key}:** {value}")
|
| 409 |
+
|
| 410 |
+
# AI Chat Interface
|
| 411 |
+
st.markdown("---")
|
| 412 |
+
st.subheader("π€ AI Stock Analyst")
|
| 413 |
+
|
| 414 |
+
# Chat interface
|
| 415 |
+
chat_container = st.container()
|
| 416 |
+
|
| 417 |
+
# Display chat history
|
| 418 |
+
with chat_container:
|
| 419 |
+
for message in st.session_state.chat_history:
|
| 420 |
+
if message['role'] == 'user':
|
| 421 |
+
st.markdown(
|
| 422 |
+
f'<div class="chat-message user-message"><strong>You:</strong> {message["content"]}</div>',
|
| 423 |
+
unsafe_allow_html=True
|
| 424 |
+
)
|
| 425 |
+
else:
|
| 426 |
+
st.markdown(
|
| 427 |
+
f'<div class="chat-message assistant-message"><strong>AI Analyst:</strong> {message["content"]}</div>',
|
| 428 |
+
unsafe_allow_html=True
|
| 429 |
+
)
|
| 430 |
+
|
| 431 |
+
# Chat input
|
| 432 |
+
user_question = st.text_input(
|
| 433 |
+
"Ask me anything about CoreWeave stock:",
|
| 434 |
+
placeholder="e.g., What's your analysis of the current price trend?"
|
| 435 |
+
)
|
| 436 |
+
|
| 437 |
+
col_send, col_clear = st.columns([1, 1])
|
| 438 |
+
|
| 439 |
+
with col_send:
|
| 440 |
+
if st.button("Send", type="primary") and user_question:
|
| 441 |
+
# Add user message to history
|
| 442 |
+
st.session_state.chat_history.append({
|
| 443 |
+
'role': 'user',
|
| 444 |
+
'content': user_question
|
| 445 |
+
})
|
| 446 |
+
|
| 447 |
+
# Get AI response
|
| 448 |
+
with st.spinner("AI is analyzing..."):
|
| 449 |
+
ai_response = get_ai_response(user_question, hist_data, api_key)
|
| 450 |
+
|
| 451 |
+
# Add AI response to history
|
| 452 |
+
st.session_state.chat_history.append({
|
| 453 |
+
'role': 'assistant',
|
| 454 |
+
'content': ai_response
|
| 455 |
+
})
|
| 456 |
+
|
| 457 |
+
st.rerun()
|
| 458 |
+
|
| 459 |
+
with col_clear:
|
| 460 |
+
if st.button("Clear Chat"):
|
| 461 |
+
st.session_state.chat_history = []
|
| 462 |
+
st.rerun()
|
| 463 |
+
|
| 464 |
+
# Sample questions
|
| 465 |
+
st.markdown("**π‘ Try asking:**")
|
| 466 |
+
sample_questions = [
|
| 467 |
+
"What's your technical analysis of CoreWeave?",
|
| 468 |
+
"Should I buy, hold, or sell CRWV?",
|
| 469 |
+
"How does CoreWeave compare to other cloud companies?",
|
| 470 |
+
"What are the key risks for CoreWeave?",
|
| 471 |
+
"Explain the recent price movement"
|
| 472 |
+
]
|
| 473 |
+
|
| 474 |
+
cols = st.columns(len(sample_questions))
|
| 475 |
+
for i, question in enumerate(sample_questions):
|
| 476 |
+
with cols[i]:
|
| 477 |
+
if st.button(question, key=f"sample_{i}"):
|
| 478 |
+
st.session_state.chat_history.append({'role': 'user', 'content': question})
|
| 479 |
+
ai_response = get_ai_response(question, hist_data, api_key)
|
| 480 |
+
st.session_state.chat_history.append({'role': 'assistant', 'content': ai_response})
|
| 481 |
+
st.rerun()
|
| 482 |
+
|
| 483 |
+
if __name__ == "__main__":
|
| 484 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit>=1.28.0
|
| 2 |
+
yfinance>=0.2.22
|
| 3 |
+
pandas>=1.5.0
|
| 4 |
+
plotly>=5.15.0
|
| 5 |
+
numpy>=1.24.0
|
| 6 |
+
requests>=2.31.0
|
| 7 |
+
beautifulsoup4>=4.12.0
|
| 8 |
+
anthropic>=0.7.0
|
| 9 |
+
python-dateutil>=2.8.0
|