Create an app for stock analysis with mock data. Generate mock daily price data for 5 tech stocks over the past year with standard fields (Open, Close, etc). Features: - Stock selector dropdown - Price trend charts - Basic stats (mean, volatility) - Moving averages - Volume analysis - Stock comparison Interactive elements: - Date range picker - Technical indicators - Chart type toggle Focus on clean visualization of realistic mock data.
To upload files, please first save the app
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from datetime import datetime, timedelta
import random
from data_generator import generate_stock_data
from utils import calculate_technical_indicators
# Page configuration
st.set_page_config(
page_title="Stock Analysis Dashboard",
page_icon="📈",
layout="wide"
)
# App title
st.title("📈 Stock Analysis Dashboard")
st.markdown("### Interactive stock analysis with mock data")
# Load mock data
stocks = ["AAPL", "MSFT", "GOOGL", "AMZN", "META"]
start_date = datetime.now() - timedelta(days=365)
end_date = datetime.now()
# Generate mock data for all stocks
all_stock_data = {}
for stock in stocks:
all_stock_data[stock] = generate_stock_data(stock, start_date, end_date)
# Sidebar for controls
st.sidebar.header("Settings")
# Stock selector
selected_stocks = st.sidebar.multiselect(
"Select Stocks",
options=stocks,
default=["AAPL"]
)
if not selected_stocks:
st.warning("Please select at least one stock from the sidebar.")
st.stop()
# Date range selector
date_range = st.sidebar.date_input(
"Date Range",
[
start_date.date() + timedelta(days=90),
end_date.date()
],
min_value=start_date.date(),
max_value=end_date.date()
)
if len(date_range) == 2:
start_date_selected = pd.Timestamp(date_range[0])
end_date_selected = pd.Timestamp(date_range[1])
else:
# Default to the last 3 months if not properly selected
start_date_selected = pd.Timestamp(end_date.date() - timedelta(days=90))
end_date_selected = pd.Timestamp(end_date.date())
# Technical indicators
tech_indicators = st.sidebar.multiselect(
"Technical Indicators",
["SMA20", "SMA50", "SMA200", "EMA20", "Bollinger Bands"],
default=["SMA50"]
)
# Chart type
chart_type = st.sidebar.selectbox(
"Chart Type",
["Candlestick", "Line", "OHLC"],
index=0
)
# Main layout
tab1, tab2, tab3 = st.tabs(["Price Analysis", "Volume Analysis", "Stock Comparison"])
# Tab 1: Price Analysis
with tab1:
for stock in selected_stocks:
st.subheader(f"{stock} Stock Analysis")
# Filter data based on selected date range
df = all_stock_data[stock]
df = df[(df['Date'] >= start_date_selected) & (df['Date'] <= end_date_selected)]
# Add technical indicators
df = calculate_technical_indicators(df, tech_indicators)
# Create charts based on the selected chart type
if chart_type == "Candlestick":
fig = go.Figure(data=[go.Candlestick(x=df['Date'],
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
name="OHLC")])
elif chart_type == "Line":
fig = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'], y=df['Close'], mode='lines', name='Close Price'))
else: # OHLC
fig = go.Figure(data=[go.Ohlc(x=df['Date'],
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
name="OHLC")])
# Add technical indicators to the chart
if 'SMA20' in df.columns:
fig.add_trace(go.Scatter(x=df['Date'], y=df['SMA20'], mode='lines', name='SMA 20', line=dict(color='blue')))
if 'SMA50' in df.columns:
fig.add_trace(go.Scatter(x=df['Date'], y=df['SMA50'], mode='lines', name='SMA 50', line=dict(color='orange')))
if 'SMA200' in df.columns:
fig.add_trace(go.Scatter(x=df['Date'], y=df['SMA200'], mode='lines', name='SMA 200', line=dict(color='purple')))
if 'EMA20' in df.columns:
fig.add_trace(go.Scatter(x=df['Date'], y=df['EMA20'], mode='lines', name='EMA 20', line=dict(color='green')))
if 'Upper Band' in df.columns:
fig.add_trace(go.Scatter(x=df['Date'], y=df['Upper Band'], mode='lines', name='Upper Bollinger', line=dict(color='red', dash='dash')))
fig.add_trace(go.Scatter(x=df['Date'], y=df['Lower Band'], mode='lines', name='Lower Bollinger', line=dict(color='red', dash='dash')))
# Update layout
fig.update_layout(
title=f"{stock} Price Chart",
xaxis_title="Date",
yaxis_title="Price (USD)",
height=600,
xaxis_rangeslider_visible=False,
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
)
st.plotly_chart(fig, use_container_width=True)
# Basic stats
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Mean Price", f"${df['Close'].mean():.2f}", f"{(df['Close'].iloc[-1] - df['Close'].mean()):.2f}")
with col2:
volatility = df['Close'].std()
st.metric("Volatility (Std Dev)", f"${volatility:.2f}")
with col3:
change = ((df['Close'].iloc[-1] - df['Close'].iloc[0]) / df['Close'].iloc[0]) * 100
st.metric("Change %", f"{change:.2f}%")
with col4:
avg_volume = df['Volume'].mean()
st.metric("Avg. Volume", f"{avg_volume:.0f}")
# Tab 2: Volume Analysis
with tab2:
for stock in selected_stocks:
st.subheader(f"{stock} Volume Analysis")
# Filter data based on selected date range
df = all_stock_data[stock]
df = df[(df['Date'] >= start_date_selected) & (df['Date'] <= end_date_selected)]
# Volume chart
fig = go.Figure()
# Add volume bars
fig.add_trace(go.Bar(
x=df['Date'],
y=df['Volume'],
name='Volume',
marker=dict(color='rgba(58, 71, 80, 0.6)')
))
# Add close price on a secondary axis
fig.add_trace(go.Scatter(
x=df['Date'],
y=df['Close'],
name='Close Price',
yaxis='y2',
line=dict(color='rgb(82, 172, 192)')
))
# Update layout for dual-axis
fig.update_layout(
title=f"{stock} Volume vs Price",
xaxis_title="Date",
yaxis=dict(
title="Volume",
titlefont=dict(color='rgba(58, 71, 80, 0.6)'),
tickfont=dict(color='rgba(58, 71, 80, 0.6)')
),
yaxis2=dict(
title="Price (USD)",
titlefont=dict(color='rgb(82, 172, 192)'),
tickfont=dict(color='rgb(82, 172, 192)'),
anchor="x",
overlaying="y",
side="right"
),
height=500,
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
)
st.plotly_chart(fig, use_container_width=True)
# Volume statistics
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Average Volume", f"{df['Volume'].mean():.0f}")
with col2:
st.metric("Max Volume", f"{df['Volume'].max():.0f}", f"{(df['Volume'].max() - df['Volume'].mean()):.0f}")
with col3:
vol_change = ((df['Volume'].iloc[-5:].mean() - df['Volume'].iloc[:5].mean()) / df['Volume'].iloc[:5].mean()) * 100
st.metric("Recent Volume Trend", f"{vol_change:.2f}%")
# Volume distribution
fig = px.histogram(df, x='Volume', nbins=20, title=f"{stock} Volume Distribution")
st.plotly_chart(fig, use_container_width=True)
# Tab 3: Stock Comparison
with tab3:
if len(selected_stocks) < 2:
st.warning("Please select at least two stocks for comparison")
else:
# Prepare data for comparison
comparison_df = pd.DataFrame()
for stock in selected_stocks:
df = all_stock_data[stock]
df = df[(df['Date'] >= start_date_selected) & (df['Date'] <= end_date_selected)]
if comparison_df.empty:
comparison_df['Date'] = df['Date']
comparison_df[f'{stock}_Close'] = df['Close'].values
comparison_df[f'{stock}_Volume'] = df['Volume'].values
# Normalize prices for better comparison (base 100)
for stock in selected_stocks:
base_price = comparison_df[f'{stock}_Close'].iloc[0]
comparison_df[f'{stock}_Normalized'] = comparison_df[f'{stock}_Close'] / base_price * 100
# Price comparison chart
fig = go.Figure()
for stock in selected_stocks:
fig.add_trace(go.Scatter(
x=comparison_df['Date'],
y=comparison_df[f'{stock}_Normalized'],
name=f'{stock}',
mode='lines'
))
fig.update_layout(
title="Normalized Price Comparison (Base 100)",
xaxis_title="Date",
yaxis_title="Normalized Price",
height=500,
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
)
st.plotly_chart(fig, use_container_width=True)
# Stats comparison
st.subheader("Statistics Comparison")
stats_df = pd.DataFrame(index=selected_stocks)
for stock in selected_stocks:
df = all_stock_data[stock]
df = df[(df['Date'] >= start_date_selected) & (df['Date'] <= end_date_selected)]
# Calculate stats
stats_df.loc[stock, 'Mean Price'] = df['Close'].mean()
stats_df.loc[stock, 'Volatility'] = df['Close'].std()
stats_df.loc[stock, 'Change %'] = ((df['Close'].iloc[-1] - df['Close'].iloc[0]) / df['Close'].iloc[0]) * 100
stats_df.loc[stock, 'Min Price'] = df['Low'].min()
stats_df.loc[stock, 'Max Price'] = df['High'].max()
stats_df.loc[stock, 'Avg Volume'] = df['Volume'].mean()
# Format the dataframe
for col in ['Mean Price', 'Volatility', 'Min Price', 'Max Price']:
stats_df[col] = stats_df[col].map('${:.2f}'.format)
stats_df['Change %'] = stats_df['Change %'].map('{:.2f}%'.format)
stats_df['Avg Volume'] = stats_df['Avg Volume'].map('{:.0f}'.format)
st.table(stats_df)
# Correlation heatmap
st.subheader("Price Correlation Heatmap")
corr_data = pd.DataFrame()
for stock in selected_stocks:
corr_data[stock] = comparison_df[f'{stock}_Close']
corr_matrix = corr_data.corr()
fig = px.imshow(
corr_matrix,
text_auto=True,
color_continuous_scale='RdBu_r',
labels=dict(x="Stock", y="Stock", color="Correlation")
)
fig.update_layout(
title="Stock Price Correlation Matrix",
height=500
)
st.plotly_chart(fig, use_container_width=True)
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?