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 plotly.subplots import make_subplots
from datetime import datetime, timedelta
from data_generator import generate_stock_data
st.set_page_config(page_title="Stock Analysis Dashboard", layout="wide")
# Load data
stock_data = generate_stock_data()
st.title("📈 Stock Analysis Dashboard")
st.markdown("Interactive analysis of tech stock performance with technical indicators")
# Sidebar controls
st.sidebar.header("🔧 Controls")
# Stock selector
stocks = list(stock_data.keys())
selected_stock = st.sidebar.selectbox("Select Stock", stocks, index=0)
# Date range picker
df = stock_data[selected_stock]
min_date = df['Date'].min()
max_date = df['Date'].max()
date_range = st.sidebar.date_input(
"Select Date Range",
value=(min_date, max_date),
min_value=min_date,
max_value=max_date
)
if len(date_range) == 2:
start_date, end_date = date_range
filtered_df = df[(df['Date'] >= pd.to_datetime(start_date)) &
(df['Date'] <= pd.to_datetime(end_date))]
else:
filtered_df = df
# Technical indicators
st.sidebar.subheader("Technical Indicators")
show_ma = st.sidebar.checkbox("Moving Averages", value=True)
ma_period_1 = st.sidebar.slider("MA Period 1", 5, 50, 20)
ma_period_2 = st.sidebar.slider("MA Period 2", 20, 100, 50)
show_bollinger = st.sidebar.checkbox("Bollinger Bands", value=False)
bb_period = st.sidebar.slider("Bollinger Period", 10, 50, 20)
# Chart type
chart_type = st.sidebar.radio("Chart Type", ["Candlestick", "Line", "Area"])
# Main dashboard
col1, col2, col3, col4 = st.columns(4)
with col1:
current_price = filtered_df['Close'].iloc[-1]
st.metric("Current Price", f"${current_price:.2f}")
with col2:
price_change = filtered_df['Close'].iloc[-1] - filtered_df['Close'].iloc[0]
price_change_pct = (price_change / filtered_df['Close'].iloc[0]) * 100
st.metric("Period Change", f"${price_change:.2f}", f"{price_change_pct:.1f}%")
with col3:
avg_volume = filtered_df['Volume'].mean()
st.metric("Average Volume", f"{avg_volume:,.0f}")
with col4:
volatility = filtered_df['Close'].pct_change().std() * np.sqrt(252) * 100
st.metric("Volatility (Annual)", f"{volatility:.1f}%")
# Price chart
st.subheader(f"📊 {selected_stock} Price Chart")
# Calculate technical indicators
if show_ma:
filtered_df[f'MA_{ma_period_1}'] = filtered_df['Close'].rolling(window=ma_period_1).mean()
filtered_df[f'MA_{ma_period_2}'] = filtered_df['Close'].rolling(window=ma_period_2).mean()
if show_bollinger:
rolling_mean = filtered_df['Close'].rolling(window=bb_period).mean()
rolling_std = filtered_df['Close'].rolling(window=bb_period).std()
filtered_df['BB_Upper'] = rolling_mean + (rolling_std * 2)
filtered_df['BB_Lower'] = rolling_mean - (rolling_std * 2)
# Create price chart
fig = make_subplots(
rows=2, cols=1,
shared_xaxes=True,
vertical_spacing=0.1,
subplot_titles=('Price', 'Volume'),
row_width=[0.7, 0.3]
)
# Price chart based on selected type
if chart_type == "Candlestick":
fig.add_trace(
go.Candlestick(
x=filtered_df['Date'],
open=filtered_df['Open'],
high=filtered_df['High'],
low=filtered_df['Low'],
close=filtered_df['Close'],
name="Price"
),
row=1, col=1
)
elif chart_type == "Line":
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df['Close'],
mode='lines',
name='Close Price',
line=dict(width=2)
),
row=1, col=1
)
else: # Area
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df['Close'],
fill='tonexty',
mode='lines',
name='Close Price',
line=dict(width=1)
),
row=1, col=1
)
# Add moving averages
if show_ma:
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df[f'MA_{ma_period_1}'],
mode='lines',
name=f'MA {ma_period_1}',
line=dict(color='orange', width=1)
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df[f'MA_{ma_period_2}'],
mode='lines',
name=f'MA {ma_period_2}',
line=dict(color='red', width=1)
),
row=1, col=1
)
# Add Bollinger Bands
if show_bollinger:
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df['BB_Upper'],
mode='lines',
name='BB Upper',
line=dict(color='gray', width=1, dash='dash')
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df['BB_Lower'],
mode='lines',
name='BB Lower',
line=dict(color='gray', width=1, dash='dash'),
fill='tonexty',
fillcolor='rgba(128,128,128,0.1)'
),
row=1, col=1
)
# Volume chart
fig.add_trace(
go.Bar(
x=filtered_df['Date'],
y=filtered_df['Volume'],
name='Volume',
marker_color='lightblue'
),
row=2, col=1
)
fig.update_layout(
title=f"{selected_stock} Stock Analysis",
xaxis_rangeslider_visible=False,
height=600,
showlegend=True
)
fig.update_xaxes(title_text="Date", row=2, col=1)
fig.update_yaxes(title_text="Price ($)", row=1, col=1)
fig.update_yaxes(title_text="Volume", row=2, col=1)
st.plotly_chart(fig, use_container_width=True)
# Statistics and comparison section
col1, col2 = st.columns(2)
with col1:
st.subheader("📈 Statistics")
stats_df = pd.DataFrame({
'Metric': ['Mean Price', 'Median Price', 'Std Deviation', 'Min Price', 'Max Price', 'Daily Return Mean', 'Daily Return Std'],
'Value': [
f"${filtered_df['Close'].mean():.2f}",
f"${filtered_df['Close'].median():.2f}",
f"${filtered_df['Close'].std():.2f}",
f"${filtered_df['Close'].min():.2f}",
f"${filtered_df['Close'].max():.2f}",
f"{filtered_df['Close'].pct_change().mean()*100:.3f}%",
f"{filtered_df['Close'].pct_change().std()*100:.3f}%"
]
})
st.table(stats_df)
with col2:
st.subheader("📊 Stock Comparison")
# Multi-select for comparison
comparison_stocks = st.multiselect(
"Select stocks to compare",
[s for s in stocks if s != selected_stock],
default=[s for s in stocks if s != selected_stock][:2]
)
if comparison_stocks:
comparison_fig = go.Figure()
# Normalize prices to percentage change for fair comparison
base_price = filtered_df['Close'].iloc[0]
normalized_main = ((filtered_df['Close'] - base_price) / base_price) * 100
comparison_fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=normalized_main,
mode='lines',
name=selected_stock,
line=dict(width=3)
)
)
for comp_stock in comparison_stocks:
comp_df = stock_data[comp_stock]
comp_filtered = comp_df[(comp_df['Date'] >= pd.to_datetime(start_date)) &
(comp_df['Date'] <= pd.to_datetime(end_date))] if len(date_range) == 2 else comp_df
comp_base_price = comp_filtered['Close'].iloc[0]
comp_normalized = ((comp_filtered['Close'] - comp_base_price) / comp_base_price) * 100
comparison_fig.add_trace(
go.Scatter(
x=comp_filtered['Date'],
y=comp_normalized,
mode='lines',
name=comp_stock,
line=dict(width=2)
)
)
comparison_fig.update_layout(
title="Stock Performance Comparison (% Change)",
xaxis_title="Date",
yaxis_title="Percentage Change (%)",
height=400
)
st.plotly_chart(comparison_fig, use_container_width=True)
# Volume analysis
st.subheader("📊 Volume Analysis")
col1, col2 = st.columns(2)
with col1:
# Volume moving average
volume_ma = st.slider("Volume MA Period", 5, 50, 20)
filtered_df[f'Volume_MA_{volume_ma}'] = filtered_df['Volume'].rolling(window=volume_ma).mean()
volume_fig = go.Figure()
volume_fig.add_trace(
go.Bar(
x=filtered_df['Date'],
y=filtered_df['Volume'],
name='Daily Volume',
marker_color='lightblue'
)
)
volume_fig.add_trace(
go.Scatter(
x=filtered_df['Date'],
y=filtered_df[f'Volume_MA_{volume_ma}'],
mode='lines',
name=f'Volume MA {volume_ma}',
line=dict(color='red', width=2)
)
)
volume_fig.update_layout(
title="Volume with Moving Average",
xaxis_title="Date",
yaxis_title="Volume",
height=400
)
st.plotly_chart(volume_fig, use_container_width=True)
with col2:
# Volume distribution
volume_hist = px.histogram(
filtered_df,
x='Volume',
bins=30,
title="Volume Distribution",
labels={'Volume': 'Volume', 'count': 'Frequency'}
)
volume_hist.update_layout(height=400)
st.plotly_chart(volume_hist, use_container_width=True)
# Raw data section
if st.checkbox("Show Raw Data"):
st.subheader("📋 Raw Data")
st.dataframe(filtered_df.sort_values('Date', ascending=False))
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?