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
# Page config
st.set_page_config(
page_title="Stock Analysis Dashboard",
page_icon="📈",
layout="wide"
)
# App title
st.title("📈 Stock Analysis Dashboard")
st.markdown("Interactive analysis of tech stock performance with real-time indicators")
# Generate mock data
@st.cache_data
def load_data():
return generate_stock_data()
data = load_data()
# Sidebar controls
st.sidebar.header("📊 Analysis Controls")
# Stock selector
stocks = list(data.keys())
selected_stock = st.sidebar.selectbox("Select Stock", stocks, index=0)
# Date range picker
stock_data = data[selected_stock]
min_date = stock_data['Date'].min()
max_date = stock_data['Date'].max()
date_range = st.sidebar.date_input(
"Select Date Range",
value=(min_date, max_date),
min_value=min_date,
max_value=max_date
)
# Chart type
chart_type = st.sidebar.selectbox(
"Chart Type",
["Candlestick", "Line", "OHLC"]
)
# Technical indicators
st.sidebar.subheader("Technical Indicators")
show_ma = st.sidebar.checkbox("Moving Averages", True)
ma_periods = st.sidebar.multiselect(
"MA Periods",
[5, 10, 20, 50],
default=[20, 50]
)
show_bollinger = st.sidebar.checkbox("Bollinger Bands")
show_volume = st.sidebar.checkbox("Volume", True)
# Filter data by date range
if len(date_range) == 2:
start_date, end_date = date_range
filtered_data = stock_data[
(stock_data['Date'] >= pd.to_datetime(start_date)) &
(stock_data['Date'] <= pd.to_datetime(end_date))
].copy()
else:
filtered_data = stock_data.copy()
# Calculate technical indicators
def calculate_moving_averages(df, periods):
for period in periods:
df[f'MA_{period}'] = df['Close'].rolling(window=period).mean()
return df
def calculate_bollinger_bands(df, period=20, std_dev=2):
df['BB_Middle'] = df['Close'].rolling(window=period).mean()
bb_std = df['Close'].rolling(window=period).std()
df['BB_Upper'] = df['BB_Middle'] + (bb_std * std_dev)
df['BB_Lower'] = df['BB_Middle'] - (bb_std * std_dev)
return df
def calculate_volatility(df, period=20):
returns = df['Close'].pct_change()
return returns.rolling(window=period).std() * np.sqrt(252) * 100
# Apply calculations
if show_ma and ma_periods:
filtered_data = calculate_moving_averages(filtered_data, ma_periods)
if show_bollinger:
filtered_data = calculate_bollinger_bands(filtered_data)
# Main content layout
col1, col2 = st.columns([3, 1])
with col1:
# Price chart
st.subheader(f"{selected_stock} Price Chart")
# Create subplot with secondary y-axis for volume
fig = make_subplots(
rows=2 if show_volume else 1,
cols=1,
shared_xaxes=True,
vertical_spacing=0.1,
row_heights=[0.7, 0.3] if show_volume else [1],
subplot_titles=("Price", "Volume") if show_volume else ("Price",)
)
# Main price chart
if chart_type == "Candlestick":
fig.add_trace(
go.Candlestick(
x=filtered_data['Date'],
open=filtered_data['Open'],
high=filtered_data['High'],
low=filtered_data['Low'],
close=filtered_data['Close'],
name="Price",
increasing_line_color='#00CC44',
decreasing_line_color='#FF4444'
),
row=1, col=1
)
elif chart_type == "Line":
fig.add_trace(
go.Scatter(
x=filtered_data['Date'],
y=filtered_data['Close'],
mode='lines',
name="Close Price",
line=dict(color='#1f77b4', width=2)
),
row=1, col=1
)
elif chart_type == "OHLC":
fig.add_trace(
go.Ohlc(
x=filtered_data['Date'],
open=filtered_data['Open'],
high=filtered_data['High'],
low=filtered_data['Low'],
close=filtered_data['Close'],
name="OHLC"
),
row=1, col=1
)
# Add moving averages
if show_ma and ma_periods:
colors = ['orange', 'red', 'purple', 'brown']
for i, period in enumerate(ma_periods):
if f'MA_{period}' in filtered_data.columns:
fig.add_trace(
go.Scatter(
x=filtered_data['Date'],
y=filtered_data[f'MA_{period}'],
mode='lines',
name=f'MA {period}',
line=dict(color=colors[i % len(colors)], width=1.5)
),
row=1, col=1
)
# Add Bollinger Bands
if show_bollinger and 'BB_Upper' in filtered_data.columns:
fig.add_trace(
go.Scatter(
x=filtered_data['Date'],
y=filtered_data['BB_Upper'],
mode='lines',
name='BB Upper',
line=dict(color='rgba(173,216,230,0.5)', width=1),
showlegend=False
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=filtered_data['Date'],
y=filtered_data['BB_Lower'],
mode='lines',
name='BB Lower',
line=dict(color='rgba(173,216,230,0.5)', width=1),
fill='tonexty',
fillcolor='rgba(173,216,230,0.2)',
showlegend=False
),
row=1, col=1
)
# Add volume chart
if show_volume:
colors = ['green' if close >= open else 'red'
for close, open in zip(filtered_data['Close'], filtered_data['Open'])]
fig.add_trace(
go.Bar(
x=filtered_data['Date'],
y=filtered_data['Volume'],
name="Volume",
marker_color=colors,
opacity=0.7
),
row=2, col=1
)
# Update layout
fig.update_layout(
height=600,
xaxis_rangeslider_visible=False,
showlegend=True,
title_x=0.5,
hovermode='x unified'
)
fig.update_xaxes(title_text="Date")
fig.update_yaxes(title_text="Price ($)", row=1, col=1)
if show_volume:
fig.update_yaxes(title_text="Volume", row=2, col=1)
st.plotly_chart(fig, use_container_width=True)
with col2:
# Stock statistics
st.subheader("📊 Key Statistics")
current_price = filtered_data['Close'].iloc[-1]
prev_price = filtered_data['Close'].iloc[-2] if len(filtered_data) > 1 else current_price
price_change = current_price - prev_price
price_change_pct = (price_change / prev_price) * 100
# Current price with change
if price_change >= 0:
st.metric(
"Current Price",
f"${current_price:.2f}",
f"+${price_change:.2f} ({price_change_pct:+.2f}%)"
)
else:
st.metric(
"Current Price",
f"${current_price:.2f}",
f"${price_change:.2f} ({price_change_pct:.2f}%)"
)
# Statistics
high_52w = filtered_data['High'].max()
low_52w = filtered_data['Low'].min()
avg_volume = filtered_data['Volume'].mean()
volatility = calculate_volatility(filtered_data).iloc[-1] if len(filtered_data) > 20 else 0
st.metric("52W High", f"${high_52w:.2f}")
st.metric("52W Low", f"${low_52w:.2f}")
st.metric("Avg Volume", f"{avg_volume:,.0f}")
st.metric("Volatility (20d)", f"{volatility:.1f}%")
# Price distribution
st.subheader("Price Distribution")
hist_fig = px.histogram(
filtered_data,
x='Close',
nbins=20,
title="Price Frequency"
)
hist_fig.update_layout(height=300, showlegend=False)
st.plotly_chart(hist_fig, use_container_width=True)
# Stock comparison section
st.subheader("📈 Stock Comparison")
comparison_stocks = st.multiselect(
"Select stocks to compare",
stocks,
default=[selected_stock]
)
if len(comparison_stocks) > 1:
# Create comparison chart
comp_fig = go.Figure()
for stock in comparison_stocks:
stock_data_comp = data[stock]
if len(date_range) == 2:
stock_data_comp = stock_data_comp[
(stock_data_comp['Date'] >= pd.to_datetime(start_date)) &
(stock_data_comp['Date'] <= pd.to_datetime(end_date))
]
# Normalize prices to percentage change from first day
first_price = stock_data_comp['Close'].iloc[0]
normalized_prices = ((stock_data_comp['Close'] / first_price) - 1) * 100
comp_fig.add_trace(
go.Scatter(
x=stock_data_comp['Date'],
y=normalized_prices,
mode='lines',
name=stock,
line=dict(width=2)
)
)
comp_fig.update_layout(
title="Stock Performance Comparison (% Change)",
xaxis_title="Date",
yaxis_title="% Change from Start",
height=400,
hovermode='x unified'
)
st.plotly_chart(comp_fig, use_container_width=True)
# Comparison table
st.subheader("Performance Metrics Comparison")
comparison_data = []
for stock in comparison_stocks:
stock_data_comp = data[stock]
if len(date_range) == 2:
stock_data_comp = stock_data_comp[
(stock_data_comp['Date'] >= pd.to_datetime(start_date)) &
(stock_data_comp['Date'] <= pd.to_datetime(end_date))
]
current = stock_data_comp['Close'].iloc[-1]
start = stock_data_comp['Close'].iloc[0]
total_return = ((current / start) - 1) * 100
max_price = stock_data_comp['High'].max()
min_price = stock_data_comp['Low'].min()
avg_vol = stock_data_comp['Volume'].mean()
vol_20d = calculate_volatility(stock_data_comp).iloc[-1] if len(stock_data_comp) > 20 else 0
comparison_data.append({
'Stock': stock,
'Current Price': f"${current:.2f}",
'Total Return': f"{total_return:+.2f}%",
'High': f"${max_price:.2f}",
'Low': f"${min_price:.2f}",
'Avg Volume': f"{avg_vol:,.0f}",
'Volatility (20d)': f"{vol_20d:.1f}%"
})
comparison_df = pd.DataFrame(comparison_data)
st.table(comparison_df)
# Footer
st.markdown("---")
st.markdown("*This dashboard uses simulated data for demonstration purposes only.*")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?