From f6b21398b8d9d13fa707955852f4e73158d7db19 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 30 Mar 2026 18:19:50 -0700 Subject: Add score card, 52W range bar, short interest, options tab, CSV exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overview: - Score card: green/yellow/red signals for valuation, growth, profitability, leverage, momentum (vs 52W high), and short interest - 52W high/low visual range bar with current price marker and % context - Short interest metrics row: % of float, days to cover, shares short vs prior month - Replaced static 52W High/Low metrics with volume and avg volume Options tab (new): - Expiry selector across all available expirations - Put/call ratio by volume and open interest with bullish/bearish label - IV smile chart (calls + puts) with ATM marker - Open interest by strike (calls above, puts mirrored below axis) - Full chain table (calls/puts) in expandable section CSV exports: - Download button on each financial statement (income, balance, cash flow) - Download button on earnings history table Also fix top padding cut-off: block-container padding-top 1rem → 3.5rem Co-Authored-By: Claude Sonnet 4.6 --- services/data_service.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'services') diff --git a/services/data_service.py b/services/data_service.py index f0f981b..3de2484 100644 --- a/services/data_service.py +++ b/services/data_service.py @@ -158,6 +158,36 @@ def get_insider_transactions(ticker: str) -> pd.DataFrame: return pd.DataFrame() +@st.cache_data(ttl=900) +def get_options_chain(ticker: str) -> dict: + """Return options chain data for the nearest available expirations. + + Returns: + { + "expirations": [str, ...], # all available expiry dates + "chains": [ + {"expiry": str, "calls": DataFrame, "puts": DataFrame}, + ... + ] + } + """ + try: + t = yf.Ticker(ticker.upper()) + expirations = t.options + if not expirations: + return {} + chains = [] + for exp in expirations[:8]: + try: + chain = t.option_chain(exp) + chains.append({"expiry": exp, "calls": chain.calls, "puts": chain.puts}) + except Exception: + pass + return {"expirations": list(expirations), "chains": chains} + except Exception: + return {} + + @st.cache_data(ttl=3600) def get_sec_filings(ticker: str) -> list[dict]: """Return SEC filings from yfinance. -- cgit v1.3-2-g0d8e