74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import streamlit as st
|
|
import yfinance as yf
|
|
|
|
|
|
@st.cache_data(show_spinner=False, ttl=3600)
|
|
def lookup_symbol_candidates(query: str, max_results: int = 10) -> list[dict[str, str]]:
|
|
cleaned = query.strip()
|
|
if len(cleaned) < 2:
|
|
return []
|
|
|
|
try:
|
|
search = yf.Search(cleaned, max_results=max_results)
|
|
quotes = getattr(search, "quotes", []) or []
|
|
except Exception:
|
|
return []
|
|
|
|
seen_symbols: set[str] = set()
|
|
candidates: list[dict[str, str]] = []
|
|
for quote in quotes:
|
|
symbol = str(quote.get("symbol", "")).strip().upper()
|
|
if not symbol or symbol in seen_symbols:
|
|
continue
|
|
|
|
seen_symbols.add(symbol)
|
|
candidates.append(
|
|
{
|
|
"symbol": symbol,
|
|
"name": str(quote.get("shortname") or quote.get("longname") or "").strip(),
|
|
"exchange": str(quote.get("exchDisp") or quote.get("exchange") or "").strip(),
|
|
"type": str(quote.get("typeDisp") or quote.get("quoteType") or "").strip(),
|
|
}
|
|
)
|
|
return candidates
|
|
|
|
|
|
@st.cache_data(show_spinner=False, ttl=3600)
|
|
def resolve_symbol_identity(symbol: str) -> dict[str, str]:
|
|
normalized_symbol = symbol.strip().upper()
|
|
if not normalized_symbol:
|
|
return {"symbol": "", "name": "", "exchange": ""}
|
|
|
|
def _from_quote(quote: dict[str, Any]) -> dict[str, str]:
|
|
return {
|
|
"symbol": normalized_symbol,
|
|
"name": str(quote.get("shortname") or quote.get("longname") or "").strip(),
|
|
"exchange": str(quote.get("exchDisp") or quote.get("exchange") or "").strip(),
|
|
}
|
|
|
|
try:
|
|
search = yf.Search(normalized_symbol, max_results=8)
|
|
quotes = getattr(search, "quotes", []) or []
|
|
for quote in quotes:
|
|
candidate_symbol = str(quote.get("symbol", "")).strip().upper()
|
|
if candidate_symbol == normalized_symbol:
|
|
return _from_quote(quote)
|
|
if quotes:
|
|
return _from_quote(quotes[0])
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
info = yf.Ticker(normalized_symbol).info
|
|
return {
|
|
"symbol": normalized_symbol,
|
|
"name": str(info.get("shortName") or info.get("longName") or "").strip(),
|
|
"exchange": str(info.get("exchange") or "").strip(),
|
|
}
|
|
except Exception:
|
|
return {"symbol": normalized_symbol, "name": "", "exchange": ""}
|