Spaces:
Sleeping
Sleeping
import gradio as gr | |
import yfinance as yf | |
import pandas as pd | |
import numpy as np | |
import plotly.graph_objects as go | |
from plotly.subplots import make_subplots | |
from datetime import datetime, timedelta | |
import warnings | |
warnings.filterwarnings('ignore') | |
COMPANIES = { | |
'Apple (AAPL)': 'AAPL', | |
'Microsoft (MSFT)': 'MSFT', | |
'Amazon (AMZN)': 'AMZN', | |
'Google (GOOGL)': 'GOOGL', | |
'Meta (META)': 'META', | |
'Tesla (TSLA)': 'TSLA', | |
'NVIDIA (NVDA)': 'NVDA', | |
'JPMorgan Chase (JPM)': 'JPM', | |
'Johnson & Johnson (JNJ)': 'JNJ', | |
'Walmart (WMT)': 'WMT', | |
'Visa (V)': 'V', | |
'Mastercard (MA)': 'MA', | |
'Procter & Gamble (PG)': 'PG', | |
'UnitedHealth (UNH)': 'UNH', | |
'Home Depot (HD)': 'HD', | |
'Bank of America (BAC)': 'BAC', | |
'Coca-Cola (KO)': 'KO', | |
'Pfizer (PFE)': 'PFE', | |
'Disney (DIS)': 'DIS', | |
'Netflix (NFLX)': 'NFLX' | |
} | |
def calculate_metrics(data: pd.DataFrame) -> pd.DataFrame: | |
df = data.copy() | |
# Basic metrics | |
df['Returns'] = df['Close'].pct_change() | |
df['SMA_20'] = df['Close'].rolling(window=20).mean() | |
df['SMA_50'] = df['Close'].rolling(window=50).mean() | |
# RSI | |
delta = df['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 | |
df['RSI'] = 100 - (100 / (1 + rs)) | |
# Bollinger Bands | |
df['BB_middle'] = df['Close'].rolling(window=20).mean() | |
bb_std = df['Close'].rolling(window=20).std() | |
df['BB_upper'] = df['BB_middle'] + (2 * bb_std) | |
df['BB_lower'] = df['BB_middle'] - (2 * bb_std) | |
return df | |
def create_analysis_plots(data: pd.DataFrame) -> list: | |
# Price and Volume Plot | |
fig1 = make_subplots(rows=2, cols=1, shared_xaxes=True, | |
subplot_titles=('Price and Moving Averages', 'Volume'), | |
row_heights=[0.7, 0.3], | |
vertical_spacing=0.1) | |
# Price and SMAs | |
fig1.add_trace( | |
go.Scatter(x=data.index, y=data['Close'], name='Close', line=dict(color='blue')), | |
row=1, col=1 | |
) | |
fig1.add_trace( | |
go.Scatter(x=data.index, y=data['SMA_20'], name='SMA 20', line=dict(color='orange', dash='dash')), | |
row=1, col=1 | |
) | |
fig1.add_trace( | |
go.Scatter(x=data.index, y=data['SMA_50'], name='SMA 50', line=dict(color='green', dash='dash')), | |
row=1, col=1 | |
) | |
# Volume | |
fig1.add_trace( | |
go.Bar(x=data.index, y=data['Volume'], name='Volume', marker_color='lightblue'), | |
row=2, col=1 | |
) | |
fig1.update_layout(height=600, title_text="Price Analysis") | |
# Technical Indicators Plot | |
fig2 = make_subplots(rows=2, cols=1, shared_xaxes=True, | |
subplot_titles=('RSI', 'Bollinger Bands'), | |
row_heights=[0.5, 0.5], | |
vertical_spacing=0.1) | |
# RSI | |
fig2.add_trace( | |
go.Scatter(x=data.index, y=data['RSI'], name='RSI', line=dict(color='purple')), | |
row=1, col=1 | |
) | |
fig2.add_hline(y=70, line_dash="dash", line_color="red", row=1, col=1) | |
fig2.add_hline(y=30, line_dash="dash", line_color="green", row=1, col=1) | |
# Bollinger Bands | |
fig2.add_trace( | |
go.Scatter(x=data.index, y=data['Close'], name='Close', line=dict(color='blue')), | |
row=2, col=1 | |
) | |
fig2.add_trace( | |
go.Scatter(x=data.index, y=data['BB_upper'], name='Upper BB', | |
line=dict(color='gray', dash='dash')), | |
row=2, col=1 | |
) | |
fig2.add_trace( | |
go.Scatter(x=data.index, y=data['BB_middle'], name='Middle BB', | |
line=dict(color='red', dash='dash')), | |
row=2, col=1 | |
) | |
fig2.add_trace( | |
go.Scatter(x=data.index, y=data['BB_lower'], name='Lower BB', | |
line=dict(color='gray', dash='dash')), | |
row=2, col=1 | |
) | |
fig2.update_layout(height=600, title_text="Technical Analysis") | |
return [fig1, fig2] | |
def generate_summary(data: pd.DataFrame) -> str: | |
current_price = data['Close'].iloc[-1] | |
prev_price = data['Close'].iloc[-2] | |
daily_return = ((current_price - prev_price) / prev_price) * 100 | |
rsi = data['RSI'].iloc[-1] | |
sma_20 = data['SMA_20'].iloc[-1] | |
sma_50 = data['SMA_50'].iloc[-1] | |
summary = f"""Market Analysis Summary: | |
• Current Price: ${current_price:.2f} | |
• Daily Change: {daily_return:+.2f}% | |
• Trend: {'Bullish' if sma_20 > sma_50 else 'Bearish'} (20-day MA vs 50-day MA) | |
• RSI: {rsi:.2f} ({'Overbought' if rsi > 70 else 'Oversold' if rsi < 30 else 'Neutral'}) | |
• Volume: {data['Volume'].iloc[-1]:,.0f} | |
Technical Signals: | |
• Moving Averages: Price is {'above' if current_price > sma_20 else 'below'} 20-day MA | |
• Bollinger Bands: Price is { | |
'near upper band (potential resistance)' if current_price > data['BB_upper'].iloc[-1] * 0.95 | |
else 'near lower band (potential support)' if current_price < data['BB_lower'].iloc[-1] * 1.05 | |
else 'in middle range'} | |
""" | |
return summary | |
def analyze_stock(company: str, lookback_days: int = 180) -> tuple: | |
try: | |
symbol = COMPANIES[company] | |
end_date = datetime.now() | |
start_date = end_date - timedelta(days=lookback_days) | |
# Download data | |
data = yf.download(symbol, start=start_date, end=end_date) | |
if len(data) == 0: | |
return "No data available for the selected period.", None, None | |
# Calculate metrics | |
data = calculate_metrics(data) | |
# Generate analysis | |
summary = generate_summary(data) | |
plots = create_analysis_plots(data) | |
return summary, plots[0], plots[1] | |
except Exception as e: | |
return f"Error analyzing stock: {str(e)}", None, None | |
def refresh_analysis(company, lookback_days): | |
return analyze_stock(company, lookback_days) | |
def create_gradio_interface(): | |
with gr.Blocks() as interface: | |
gr.Markdown("# Stock Market Analysis Dashboard") | |
with gr.Row(): | |
company = gr.Dropdown( | |
choices=list(COMPANIES.keys()), | |
label="Select Company", | |
value="Apple (AAPL)" | |
) | |
lookback = gr.Slider( | |
minimum=30, | |
maximum=365, | |
value=180, | |
step=1, | |
label="Lookback Period (days)" | |
) | |
refresh_btn = gr.Button("Refresh Analysis") | |
with gr.Row(): | |
summary = gr.Textbox(label="Analysis Summary", lines=10) | |
with gr.Row(): | |
plot1 = gr.Plot(label="Price Analysis") | |
plot2 = gr.Plot(label="Technical Analysis") | |
refresh_btn.click( | |
fn=refresh_analysis, | |
inputs=[company, lookback], | |
outputs=[summary, plot1, plot2] | |
) | |
# Also trigger analysis when company or lookback period changes | |
company.change( | |
fn=analyze_stock, | |
inputs=[company, lookback], | |
outputs=[summary, plot1, plot2] | |
) | |
lookback.release( | |
fn=analyze_stock, | |
inputs=[company, lookback], | |
outputs=[summary, plot1, plot2] | |
) | |
return interface | |
if __name__ == "__main__": | |
interface = create_gradio_interface() | |
interface.launch(share=True) |