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') # List of companies with their symbols 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(df): """Calculate technical indicators""" data = df.copy() # Basic metrics data['Returns'] = data['Close'].pct_change() data['SMA_20'] = data['Close'].rolling(window=20).mean() data['SMA_50'] = data['Close'].rolling(window=50).mean() # RSI delta = data['Close'].diff() gain = delta.clip(lower=0) loss = -delta.clip(upper=0) avg_gain = gain.rolling(window=14).mean() avg_loss = loss.rolling(window=14).mean() rs = avg_gain / avg_loss data['RSI'] = 100 - (100 / (1 + rs)) # Bollinger Bands data['BB_middle'] = data['Close'].rolling(window=20).mean() bb_std = data['Close'].rolling(window=20).std() data['BB_upper'] = data['BB_middle'] + (2 * bb_std) data['BB_lower'] = data['BB_middle'] - (2 * bb_std) return data def create_plots(data): """Create analysis plots""" # Price and Volume Plot fig1 = make_subplots( rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=('Price and Moving Averages', 'Volume'), row_heights=[0.7, 0.3] ) 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 ) 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 Analysis Plot fig2 = make_subplots( rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=('RSI', 'Bollinger Bands'), row_heights=[0.5, 0.5] ) # 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 ) for band, color in [('BB_upper', 'gray'), ('BB_middle', 'red'), ('BB_lower', 'gray')]: fig2.add_trace( go.Scatter(x=data.index, y=data[band], name=band, line=dict(color=color, dash='dash')), row=2, col=1 ) fig2.update_layout(height=600, title_text="Technical Analysis") return [fig1, fig2] def generate_summary(data, symbol): """Generate analysis summary""" try: current_price = float(data['Close'].iloc[-1]) prev_price = float(data['Close'].iloc[-2]) daily_return = ((current_price - prev_price) / prev_price) * 100 rsi = float(data['RSI'].iloc[-1]) sma_20 = float(data['SMA_20'].iloc[-1]) sma_50 = float(data['SMA_50'].iloc[-1]) volume = float(data['Volume'].iloc[-1]) bb_position = "in middle range" if current_price > float(data['BB_upper'].iloc[-1] * 0.95): bb_position = "near upper band (potential resistance)" elif current_price < float(data['BB_lower'].iloc[-1] * 1.05): bb_position = "near lower band (potential support)" summary = f"""Analysis Summary for {symbol}: • 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: {volume:,.0f} Technical Signals: • Moving Averages: Price is {"above" if current_price > sma_20 else "below"} 20-day MA • Bollinger Bands: Price is {bb_position} """ return summary except Exception as e: return f"Error generating summary: {str(e)}" def analyze_stock(company, lookback_days=180): """Main analysis function""" 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 and create analysis data = calculate_metrics(data) summary = generate_summary(data, symbol) plots = create_plots(data) return summary, plots[0], plots[1] except Exception as e: return f"Error analyzing stock: {str(e)}", None, None def create_interface(): """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") 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") # Event handlers refresh_btn.click( fn=analyze_stock, inputs=[company, lookback], outputs=[summary, plot1, plot2] ) 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_interface() interface.launch(share=True)