File size: 7,393 Bytes
5be7da8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8dbdb70
 
5be7da8
8dbdb70
 
 
 
5be7da8
8dbdb70
 
 
 
 
 
5be7da8
8dbdb70
 
 
 
 
 
 
5be7da8
8dbdb70
 
5be7da8
8dbdb70
 
 
5be7da8
 
8dbdb70
 
 
 
 
 
 
 
 
 
 
 
5be7da8
 
8dbdb70
 
 
 
5be7da8
 
 
8dbdb70
 
 
 
 
5be7da8
 
8dbdb70
 
 
 
5be7da8
 
 
 
8dbdb70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5be7da8
 
 
8dbdb70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5be7da8
8dbdb70
 
 
 
 
5be7da8
 
 
8dbdb70
5be7da8
 
8dbdb70
 
 
 
 
 
 
 
 
 
 
 
 
5be7da8
 
 
 
 
 
 
 
8dbdb70
 
 
 
 
 
 
 
5be7da8
 
 
 
8dbdb70
 
 
 
 
 
5be7da8
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
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)