import dash from dash import html, dcc, Input, Output import yfinance as yf import os # ========================= # PATH # ========================= BASE_DIR = os.path.dirname(__file__) # ========================= # INIT APP # ========================= app = dash.Dash( __name__, use_pages=True, pages_folder=os.path.join(BASE_DIR, "pages"), suppress_callback_exceptions=True, external_stylesheets=[ "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" ] ) server = app.server # 🔥 IMPORTANT pour Hugging Face app.title = "TradeLux - Plateforme de Trading" # ========================= # TICKERS # ========================= TICKERS = { "BTC-USD": "BTC/USD", "ETH-USD": "ETH/USD", "^IXIC": "NASDAQ", "AAPL": "AAPL", "GOOGL": "GOOGL" } # ========================= # FETCH DATA # ========================= def fetch_ticker_data(): data = [] for symbol, label in TICKERS.items(): try: stock = yf.Ticker(symbol) hist = stock.history(period="1d", interval="1m") if len(hist) >= 2: current = hist['Close'].iloc[-1] prev = hist['Close'].iloc[-2] change = (current - prev) / prev * 100 change_class = "up" if change > 0 else "down" data.append({ "label": label, "value": f"{current:,.2f}", "change": f"{change:+.2f}%", "class": change_class }) else: data.append({ "label": label, "value": "N/A", "change": "0.00%", "class": "down" }) except Exception as e: print("Ticker error:", e) data.append({ "label": label, "value": "ERR", "change": "0.00%", "class": "down" }) return data # ========================= # BACKGROUND SAFE (IMPORTANT) # ========================= background = html.Div( [ html.Div(className="trade-bg"), html.Div(className="grid-lines"), html.Div( [html.Div(className="particle") for _ in range(40)], style={ "position": "fixed", "zIndex": -10, "pointerEvents": "none" } ) ] ) # ========================= # NAVBAR # ========================= navbar = html.Div( className="navbar", children=[ html.Div( className="navbar-left", children=[ html.Img(src="/assets/logo.png", className="logo") ] ), html.Div( className="nav-links", children=[ dcc.Link("Accueil", href="/", className="nav-link"), dcc.Link("Marchés", href="/actions", className="nav-link"), dcc.Link("Analyse", href="/data", className="nav-link"), ] ), ] ) # ========================= # LAYOUT # ========================= app.layout = html.Div([ # Background FIXED (non bloquant) background, # Ticker dynamique html.Div(id="ticker-container"), # Navbar navbar, # Content html.Div( className="page-content", children=[ dash.page_container ], style={"zIndex": 1} # 🔥 FIX CLICK ), # Interval dcc.Interval(id="interval", interval=60000, n_intervals=0) ]) # ========================= # CALLBACK TICKER (FIX STRUCTURE) # ========================= @app.callback( Output("ticker-container", "children"), Input("interval", "n_intervals") ) def update_ticker(n): data = fetch_ticker_data() items = [ html.Div(className="ticker-item", children=[ html.Span(d["label"]), html.Span(d["value"], className="ticker-value"), html.Span(d["change"], className=f"ticker-change {d['class']}") ]) for d in data ] return html.Div( className="ticker-wrap", children=[ html.Div( className="ticker-inner", children=[ html.Div(className="ticker-set", children=items), html.Div(className="ticker-set", children=items) # duplication scroll ] ) ] ) # ========================= # RUN # ========================= if __name__ == "__main__": app.run(host="0.0.0.0", port=7860, debug=True)