CoolFace
Apppublic

Atif-67/yfi

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
1likes
app.py596 linesDownload Raw Back to root
1import streamlit as st
2import yfinance as yf
3import pandas as pd
4import datetime as dt
5import plotly.graph_objects as go
6from plotly.subplots import make_subplots
7import requests
8from requests.adapters import HTTPAdapter
9from urllib3.util.retry import Retry
10
11# Page Configuration
12st.set_page_config(
13    page_title="Global Markets Pro",
14    page_icon="๐Ÿ“ˆ",
15    layout="wide",
16    initial_sidebar_state="expanded"
17)
18
19# Custom CSS for professional styling
20# st.markdown("""
21# <style>
22#     :root {
23#         --primary-color: #2563eb;
24#         --secondary-color: #1e40af;
25#         --accent-color: #3b82f6;
26#         --background-color: #f8fafc;
27#         --surface-color: #ffffff;
28#         --text-color: #1e293b;
29#         --text-secondary: #64748b;
30#     }
31    
32#     .main {
33#         background-color: var(--background-color);
34#         color: var(--text-color);
35#     }
36    
37#     .stSelectbox div, .stTextInput div, .stDateInput div {
38#         background-color: var(--surface-color) !important;
39#         border-radius: 8px !important;
40#         box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important;
41#     }
42    
43#     .stButton>button {
44#         background-color: var(--primary-color) !important;
45#         color: white !important;
46#         border-radius: 8px !important;
47#         padding: 0.5rem 1rem !important;
48#         font-weight: 500 !important;
49#         transition: all 0.2s !important;
50#     }
51    
52#     .stButton>button:hover {
53#         background-color: var(--secondary-color) !important;
54#         transform: translateY(-1px) !important;
55#         box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important;
56#     }
57    
58#     .stMetric {
59#         background-color: var(--surface-color) !important;
60#         border-radius: 12px !important;
61#         padding: 1.5rem !important;
62#         box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important;
63#     }
64    
65#     .stDataFrame {
66#         border-radius: 12px !important;
67#         box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important;
68#     }
69    
70#     .stTabs [aria-selected="true"] {
71#         background-color: var(--primary-color) !important;
72#         color: white !important;
73#     }
74    
75#     .sidebar .sidebar-content {
76#         background: linear-gradient(180deg, #2563eb 0%, #1e40af 100%) !important;
77#         color: white !important;
78#     }
79    
80#     .sidebar .sidebar-content a {
81#         color: white !important;
82#     }
83    
84#     .sidebar .sidebar-content .stMarkdown h1, 
85#     .sidebar .sidebar-content .stMarkdown h2,
86#     .sidebar .sidebar-content .stMarkdown h3 {
87#         color: white !important;
88#     }
89# </style>
90# """, unsafe_allow_html=True)
91
92#just change the css becuse the css is so bright and not professional
93# Custom CSS for dark theme
94st.markdown("""
95<style>
96    :root {
97        --primary-color: #1f2937; /* Dark Gray */
98        --secondary-color: #4b5563; /* Medium Gray */
99        --accent-color: #10b981; /* Emerald Green */
100        --background-color: #111827; /* Dark Background */
101        --surface-color: #1f2937; /* Surface Background */
102        --text-color: #f9fafb; /* Light Text */
103        --text-secondary: #9ca3af; /* Muted Text */
104    }
105    
106    .main {
107        background-color: var(--background-color);
108        color: var(--text-color);
109    }
110    
111    .stSelectbox div, .stTextInput div, .stDateInput div {
112        background-color: var(--surface-color) !important;
113        border-radius: 8px !important;
114        box-shadow: 0 1px 3px rgba(0,0,0,0.5) !important;
115        color: var(--text-color) !important;
116    }
117    
118    .stButton>button {
119        background-color: var(--accent-color) !important;
120        color: white !important;
121        border-radius: 8px !important;
122        padding: 0.5rem 1rem !important;
123        font-weight: 500 !important;
124        transition: all 0.2s !important;
125    }
126    
127    .stButton>button:hover {
128        background-color: #059669 !important; /* Darker Emerald */
129        transform: translateY(-1px) !important;
130        box-shadow: 0 4px 6px rgba(0,0,0,0.5) !important;
131    }
132    
133    .stMetric {
134        background-color: var(--surface-color) !important;
135        border-radius: 12px !important;
136        padding: 1.5rem !important;
137        box-shadow: 0 1px 3px rgba(0,0,0,0.5) !important;
138        color: var(--text-color) !important;
139    }
140    
141    .stDataFrame {
142        border-radius: 12px !important;
143        box-shadow: 0 1px 3px rgba(0,0,0,0.5) !important;
144        color: var(--text-color) !important;
145    }
146    
147    .stTabs [aria-selected="true"] {
148        background-color: var(--accent-color) !important;
149        color: white !important;
150    }
151    
152    .sidebar .sidebar-content {
153        background: linear-gradient(180deg, #1f2937 0%, #4b5563 100%) !important;
154        color: white !important;
155    }
156    
157    .sidebar .sidebar-content a {
158        color: var(--accent-color) !important;
159    }
160    
161    .sidebar .sidebar-content .stMarkdown h1, 
162    .sidebar .sidebar-content .stMarkdown h2,
163    .sidebar .sidebar-content .stMarkdown h3 {
164        color: white !important;
165    }
166</style>
167""", unsafe_allow_html=True)
168
169# Title Section
170st.title("๐ŸŒ Global Markets Pro")
171st.markdown("""
172<div style="color: var(--text-secondary); margin-bottom: 2rem;">
173    Professional-grade market data analysis for investors and traders
174</div>
175""", unsafe_allow_html=True)
176
177# Enhanced Ticker List (500+ global companies)
178GLOBAL_TICKERS = {
179    "Technology": [
180        "AAPL", "MSFT", "NVDA", "AVGO", "ASML", "TSM", "ADBE", "CSCO", "ACN", "CRM",
181        "ORCL", "SAP", "INTU", "AMD", "INTC", "QCOM", "TXN", "AMAT", "LRCX", "KLAC",
182        "SNOW", "PLTR", "U", "DDOG", "ZS", "CRWD", "NET", "MDB", "NOW", "TEAM"
183    ],
184    "Finance": [
185        "JPM", "BAC", "WFC", "C", "HSBC", "GS", "MS", "BLK", "SCHW", "AXP",
186        "V", "MA", "PYPL", "SQ", "COIN", "MUFG", "RY", "TD", "BNPQY", "ING"
187    ],
188    "Consumer": [
189        "AMZN", "WMT", "COST", "TGT", "HD", "LOW", "NKE", "MCD", "SBUX", "PEP",
190        "KO", "PG", "UL", "NSRGY", "EL", "LVMUY", "KHC", "PM", "MO", "BUD"
191    ],
192    "Healthcare": [
193        "JNJ", "PFE", "ABBV", "LLY", "MRK", "NVS", "AZN", "UNH", "DHR", "TMO",
194        "ISRG", "SYK", "BDX", "BSX", "MDT", "ZTS", "VRTX", "REGN", "GILD", "BMY"
195    ],
196    "Energy & Industrials": [
197        "XOM", "CVX", "SHEL", "TTE", "BP", "ENB", "COP", "EOG", "BHP", "RIO",
198        "CAT", "DE", "HON", "GE", "BA", "RTX", "LMT", "NOC", "GD", "MMM"
199    ],
200    "Emerging Markets": [
201        "BABA", "TCEHY", "JD", "PDD", "BIDU", "NTES", "TSM", "005930.KS", "000660.KS",
202        "0688.HK", "3690.HK", "601318.SS", "600519.SS", "601288.SS", "RELIANCE.NS",
203        "TATASTEEL.NS", "INFY", "HDB", "ICICIY", "ITUB"
204    ],
205    "Crypto & Blockchain": [
206        "COIN", "MARA", "RIOT", "MSTR", "HUT", "BITF", "CLSK", "BTBT", "MOGO", "SI"
207    ],
208    "EV & Clean Energy": [
209        "TSLA", "NIO", "LI", "XPEV", "RIVN", "LCID", "FSR", "PLUG", "FCEL", "BE",
210        "ENPH", "SEDG", "FSLR", "RUN", "SPWR", "NEE", "DQ", "JKS", "CSIQ"
211    ]
212}
213
214# Session State Management
215if 'stock_data' not in st.session_state:
216    st.session_state.stock_data = None
217if 'current_ticker' not in st.session_state:
218    st.session_state.current_ticker = None
219if 'comparison_tickers' not in st.session_state:
220    st.session_state.comparison_tickers = []
221
222# Custom Session with Retries
223def create_session():
224    session = requests.Session()
225    retry = Retry(
226        total=5,
227        backoff_factor=0.5,
228        status_forcelist=[500, 502, 503, 504],
229    )
230    adapter = HTTPAdapter(max_retries=retry)
231    session.mount('http://', adapter)
232    session.mount('https://', adapter)
233    session.headers.update({
234        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
235    })
236    return session
237
238# Enhanced Data Fetching Function
239@st.cache_data(ttl=3600)  # Cache for 1 hour
240def fetch_stock_data(ticker, start_date, end_date, interval='1d'):
241    try:
242        ticker_obj = yf.Ticker(ticker)
243        data = ticker_obj.history(
244            start=start_date,
245            end=end_date,
246            interval=interval,
247            auto_adjust=False,
248            actions=True
249        )
250        if data is None or data.empty:
251            return None
252        # Calculate technical indicators
253        data['SMA_50'] = data['Close'].rolling(window=50).mean()
254        data['SMA_200'] = data['Close'].rolling(window=200).mean()
255        data['Daily_Return'] = data['Close'].pct_change()
256        # Format the data
257        data = data.rename(columns={
258            'Open': 'open',
259            'High': 'high',
260            'Low': 'low',
261            'Close': 'close',
262            'Adj Close': 'adj_close',
263            'Volume': 'volume'
264        })
265        data = data.reset_index().rename(columns={'Date': 'date'})
266        return data[['date', 'open', 'high', 'low', 'close', 'adj_close', 'volume', 
267                    'SMA_50', 'SMA_200', 'Daily_Return']]
268    except Exception as e:
269        st.error(f"Error fetching data for {ticker}: {str(e)}")
270        return None
271
272# Sidebar - Filters and Info
273with st.sidebar:
274    st.markdown("""
275    <div style="text-align: center; margin-bottom: 2rem;">
276        <h1 style="color: white;">Global Markets Pro</h1>
277        <p style="color: rgba(255,255,255,0.8);">Professional Market Analysis</p>
278    </div>
279    """, unsafe_allow_html=True)
280    
281    # Sector Selection
282    selected_sector = st.selectbox(
283        "Select Sector",
284        list(GLOBAL_TICKERS.keys()),
285        index=0
286    )
287    
288    # Ticker Selection
289    selected_ticker = st.selectbox(
290        "Select Ticker",
291        GLOBAL_TICKERS[selected_sector],
292        index=0
293    )
294    
295    # Date Range
296    col1, col2 = st.columns(2)
297    with col1:
298        start_date = st.date_input(
299            "Start Date",
300            value=dt.date(2020, 1, 1),
301            min_value=dt.date(1980, 1, 1),
302            max_value=dt.date.today()
303        )
304    with col2:
305        end_date = st.date_input(
306            "End Date",
307            value=dt.date.today(),
308            min_value=dt.date(1980, 1, 1),
309            max_value=dt.date.today()
310        )
311    
312    # Comparison Tickers
313    comparison_tickers = st.multiselect(
314        "Compare With (Max 4)",
315        [t for sector in GLOBAL_TICKERS.values() for t in sector],
316        default=[],
317        max_selections=4
318    )
319    
320    # Interval Selection
321    interval = st.selectbox(
322        "Data Interval",
323        ["1d", "1wk", "1mo"],
324        index=0
325    )
326    
327    st.markdown("---")
328    
329    # Social Links
330    st.markdown("""
331    <div style="margin-top: 2rem;">
332        <h3 style="color: white;">Connect</h3>
333        <p>
334            <a href="mailto:muhammadatiflatif67@gmail.com" style="color: white; text-decoration: none;">
335                ๐Ÿ“ง Email
336            </a>
337        </p>
338        <p>
339            <a href="https://www.linkedin.com/in/muhammad-atif-latif-13a171318" style="color: white; text-decoration: none;">
340                ๐Ÿ”— LinkedIn
341            </a>
342        </p>
343        <p>
344            <a href="https://www.kaggle.com/muhammadatiflatif" style="color: white; text-decoration: none;">
345                ๐Ÿ“Š Kaggle
346            </a>
347        </p>
348        <p>
349            <a href="https://x.com/mianatif5867" style="color: white; text-decoration: none;">
350                ๐• Twitter
351            </a>
352        </p>
353        <p>
354            <a href="https://github.com/M-Atif-Latif" style="color: white; text-decoration: none;">
355                ๐Ÿ’ป GitHub
356            </a>
357        </p>
358    </div>
359    """, unsafe_allow_html=True)
360
361# Main Content
362col1, col2 = st.columns([3, 1])
363with col1:
364    if st.button("๐Ÿ“Š Fetch Market Data", use_container_width=True):
365        with st.spinner(f"Loading data for {selected_ticker}..."):
366            data = fetch_stock_data(selected_ticker, start_date, end_date, interval)
367            if data is not None:
368                st.session_state.stock_data = data
369                st.session_state.current_ticker = selected_ticker
370                st.session_state.comparison_tickers = comparison_tickers
371                st.success("Data loaded successfully!")
372with col2:
373    if st.button("๐Ÿ”„ Clear Data", use_container_width=True, type="secondary"):
374        st.session_state.stock_data = None
375        st.session_state.current_ticker = None
376        st.session_state.comparison_tickers = []
377        st.rerun()
378
379# Display Data
380if st.session_state.stock_data is not None:
381    df = st.session_state.stock_data
382    ticker = st.session_state.current_ticker
383    
384    # Metrics Row
385    st.markdown("---")
386    col1, col2, col3, col4 = st.columns(4)
387    with col1:
388        st.metric(
389            "Current Price",
390            f"${df.iloc[-1]['close']:,.2f}",
391            f"{df.iloc[-1]['close'] - df.iloc[-2]['close']:,.2f}",
392            delta_color="normal"
393        )
394    with col2:
395        st.metric(
396            "52 Week Range",
397            f"${df['close'].min():,.2f} - ${df['close'].max():,.2f}"
398        )
399    with col3:
400        daily_return = df.iloc[-1]['Daily_Return'] * 100
401        st.metric(
402            "Daily Return",
403            f"{daily_return:.2f}%",
404            delta_color="inverse" if daily_return < 0 else "normal"
405        )
406    with col4:
407        vol = df['volume'].mean() / 1_000_000
408        st.metric(
409            "Avg Volume",
410            f"{vol:,.1f}M"
411        )
412    
413    # Interactive Chart
414    st.markdown("---")
415    st.markdown(f"### {ticker} Price Analysis")
416    
417    fig = make_subplots(rows=2, cols=1, shared_xaxes=True, 
418                       vertical_spacing=0.05, row_heights=[0.7, 0.3])
419    
420    # Price and Moving Averages
421    fig.add_trace(
422        go.Candlestick(
423            x=df['date'],
424            open=df['open'],
425            high=df['high'],
426            low=df['low'],
427            close=df['close'],
428            name="Price",
429            increasing_line_color='#2ecc71',
430            decreasing_line_color='#e74c3c'
431        ),
432        row=1, col=1
433    )
434    
435    fig.add_trace(
436        go.Scatter(
437            x=df['date'],
438            y=df['SMA_50'],
439            name="50-Day SMA",
440            line=dict(color='#3498db', width=2)
441        ),
442        row=1, col=1
443    )
444    
445    fig.add_trace(
446        go.Scatter(
447            x=df['date'],
448            y=df['SMA_200'],
449            name="200-Day SMA",
450            line=dict(color='#f39c12', width=2)
451        ),
452        row=1, col=1
453    )
454    
455    # Volume
456    fig.add_trace(
457        go.Bar(
458            x=df['date'],
459            y=df['volume'],
460            name="Volume",
461            marker_color='#7f8c8d'
462        ),
463        row=2, col=1
464    )
465    
466    fig.update_layout(
467        height=800,
468        showlegend=True,
469        hovermode="x unified",
470        template="plotly_white",
471        margin=dict(l=20, r=20, t=40, b=20),
472        xaxis_rangeslider_visible=False
473    )
474    
475    st.plotly_chart(fig, use_container_width=True)
476    
477    # Comparison Charts
478    if st.session_state.comparison_tickers:
479        st.markdown("---")
480        st.markdown("### Performance Comparison")
481        
482        comparison_data = {}
483        for comp_ticker in st.session_state.comparison_tickers:
484            comp_df = fetch_stock_data(comp_ticker, start_date, end_date, interval)
485            if comp_df is not None:
486                comparison_data[comp_ticker] = comp_df
487        
488        if comparison_data:
489            fig = go.Figure()
490            
491            # Normalize all prices to percentage change from start date
492            base_price = df.iloc[0]['close']
493            fig.add_trace(
494                go.Scatter(
495                    x=df['date'],
496                    y=(df['close'] / base_price - 1) * 100,
497                    name=ticker,
498                    line=dict(width=3)
499                )
500            )
501            
502            for comp_ticker, comp_df in comparison_data.items():
503                comp_base = comp_df.iloc[0]['close']
504                fig.add_trace(
505                    go.Scatter(
506                        x=comp_df['date'],
507                        y=(comp_df['close'] / comp_base - 1) * 100,
508                        name=comp_ticker
509                    )
510                )
511            
512            fig.update_layout(
513                title="Normalized Performance Comparison",
514                yaxis_title="Percentage Change (%)",
515                hovermode="x unified",
516                height=500
517            )
518            
519            st.plotly_chart(fig, use_container_width=True)
520    
521    # Data Table and Export
522    st.markdown("---")
523    st.markdown("### Market Data Table")
524    
525    # Show technical indicators in the table
526    display_cols = ['date', 'open', 'high', 'low', 'close', 'volume', 
527                   'SMA_50', 'SMA_200', 'Daily_Return']
528    
529    st.dataframe(
530        df[display_cols].rename(columns={
531            'date': 'Date',
532            'open': 'Open',
533            'high': 'High',
534            'low': 'Low',
535            'close': 'Close',
536            'volume': 'Volume',
537            'SMA_50': '50-Day SMA',
538            'SMA_200': '200-Day SMA',
539            'Daily_Return': 'Daily Return'
540        }).style.format({
541            'Open': '{:,.2f}',
542            'High': '{:,.2f}',
543            'Low': '{:,.2f}',
544            'Close': '{:,.2f}',
545            'Volume': '{:,.0f}',
546            '50-Day SMA': '{:,.2f}',
547            '200-Day SMA': '{:,.2f}',
548            'Daily Return': '{:.2%}'
549        }),
550        height=400,
551        use_container_width=True
552    )
553    
554    # Export Options
555    st.markdown("---")
556    st.markdown("### Export Data")
557    col1, col2 = st.columns(2)
558    with col1:
559        csv = df.to_csv(index=False)
560        st.download_button(
561            "๐Ÿ“ฅ Download CSV",
562            csv,
563            file_name=f"{ticker}_market_data_{start_date}_to_{end_date}.csv",
564            mime="text/csv",
565            use_container_width=True
566        )
567    with col2:
568        # Export Plotly chart as PNG
569        try:
570            chart_png = fig.to_image(format="png")
571            st.download_button(
572                "๐Ÿ“Š Download Chart as PNG",
573                chart_png,
574                file_name=f"{ticker}_chart.png",
575                mime="image/png",
576                use_container_width=True
577            )
578        except Exception as e:
579            st.download_button(
580                "๐Ÿ“Š Download Chart as PNG",
581                b"",
582                file_name=f"{ticker}_chart.png",
583                disabled=True,
584                help=f"PNG export failed: {str(e)}",
585                use_container_width=True
586            )
587
588# Footer
589st.markdown("---")
590st.markdown("""
591<div style="text-align: center; color: var(--text-secondary); padding: 1rem;">
592    <p>Global Markets Pro โ€ข Professional Market Analysis Tool</p>
593    <p style="font-size: 0.8rem;">Data provided by Yahoo Finance โ€ข Updated at {}</p>
594</div>
595""".format(dt.datetime.now().strftime("%Y-%m-%d %H:%M")), unsafe_allow_html=True)
596