"""Top Movers component — day gainers, losers, most active.""" import streamlit as st import yfinance as yf @st.cache_data(ttl=180) def _fetch_movers(screen: str, count: int = 8) -> list[dict]: try: result = yf.screen(screen, count=count) return result.get("quotes", []) except Exception: return [] def _fmt_pct(val) -> str: try: return f"{float(val):+.2f}%" except Exception: return "—" def _fmt_price(val) -> str: try: return f"${float(val):,.2f}" except Exception: return "—" def _mover_row(q: dict): symbol = q.get("symbol", "") name = q.get("shortName") or q.get("longName") or symbol price = q.get("regularMarketPrice") chg_pct = q.get("regularMarketChangePercent") chg_abs = q.get("regularMarketChange") try: chg_f = float(chg_pct) color = "#2ecc71" if chg_f >= 0 else "#e74c3c" sign = "+" if chg_f >= 0 else "" pct_str = f"{sign}{chg_f:.2f}%" except Exception: color = "#9aa0b0" pct_str = "—" try: abs_str = f"({'+' if float(chg_abs) >= 0 else ''}{float(chg_abs):.2f})" except Exception: abs_str = "" col_sym, col_name, col_price, col_chg = st.columns([1, 3, 1.5, 1.5]) with col_sym: st.markdown(f"**{symbol}**") with col_name: st.caption(name[:40]) with col_price: st.markdown(_fmt_price(price)) with col_chg: st.markdown( f"{pct_str}" f" {abs_str}", unsafe_allow_html=True, ) def render_top_movers(): st.markdown("#### 🔥 Top Movers") tab_gainers, tab_losers, tab_active = st.tabs([ "📈 Gainers", "📉 Losers", "⚡ Most Active" ]) screens = { "gainers": "day_gainers", "losers": "day_losers", "active": "most_actives", } with tab_gainers: quotes = _fetch_movers(screens["gainers"]) if quotes: for q in quotes: _mover_row(q) else: st.caption("No data available.") with tab_losers: quotes = _fetch_movers(screens["losers"]) if quotes: for q in quotes: _mover_row(q) else: st.caption("No data available.") with tab_active: quotes = _fetch_movers(screens["active"]) if quotes: for q in quotes: _mover_row(q) else: st.caption("No data available.")