"""Standalone financial data-fetching functions (framework-agnostic). Used by the Claude Agent SDK MCP tools and standalone context enrichment. No dependency on LangChain or any agent framework. """ import requests as http_requests _TV_NEWS_URL = "https://news-mediator.tradingview.com/public/news-flow/v2/news" _TV_HEADERS = { "accept": "*/*", "origin": "https://in.tradingview.com", "referer": "https://in.tradingview.com/", "user-agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/145.0.0.0 Safari/537.36" ), } _TV_SCREENER_URL = ( "https://screener-facade.tradingview.com/screener-facade/api/v1/screener-table/scan" ) _TV_SCREENER_HEADERS = { "accept": "application/json", "content-type": "text/plain;charset=UTF-8", "origin": "https://in.tradingview.com", "referer": "https://in.tradingview.com/", "user-agent": _TV_HEADERS["user-agent"], } _COMMON_EXCHANGES = ["NYSE", "NASDAQ", "AMEX"] def fetch_stock_news_data(symbol: str) -> str: """Fetch latest news for a stock ticker from TradingView.""" all_items: list[dict] = [] seen: set[str] = set() for exchange in _COMMON_EXCHANGES: params = { "filter": ["lang:en", f"symbol:{exchange}:{symbol.upper()}"], "client": "landing", "streaming": "false", "user_prostatus": "non_pro", } try: resp = http_requests.get( _TV_NEWS_URL, params=params, headers=_TV_HEADERS, timeout=10, ) resp.raise_for_status() for item in resp.json().get("items", []): iid = str(item.get("id", "")) if iid and iid not in seen: seen.add(iid) all_items.append(item) except Exception: continue all_items.sort(key=lambda x: x.get("published", 0), reverse=True) top = all_items[:8] if not top: return f"No recent news found for {symbol}." lines = [f"Latest news for {symbol} ({len(top)} items):"] for idx, item in enumerate(top, 1): provider = "" prov = item.get("provider") if isinstance(prov, dict): provider = prov.get("name", "") title = item.get("title", "Untitled") lines.append(f"{idx}. [{provider}] {title}") return "\n".join(lines) def fetch_market_benchmarks_data() -> str: """Fetch US market index benchmarks with technical signals and RSI.""" params = { "table_id": "indices_quotes.us", "version": "52", "columnset_id": "technicals", } body = '{"lang":"en","range":[0,5],"scanner_product_label":"markets-screener"}' try: resp = http_requests.post( _TV_SCREENER_URL, params=params, headers=_TV_SCREENER_HEADERS, data=body, timeout=10, ) resp.raise_for_status() raw = resp.json() except Exception as exc: return f"Failed to fetch benchmarks: {exc}" symbols = raw.get("symbols", []) columns = raw.get("data", []) count = len(symbols) col_map: dict[str, dict] = {} for col in columns: col_map.setdefault(col["id"], col) lines = ["US Market Benchmarks:"] for i in range(count): ticker_col = col_map.get("TickerUniversal", {}) raw_vals = ticker_col.get("rawValues", []) info = raw_vals[i] if i < len(raw_vals) else {} tech = col_map.get("TechnicalRating", {}).get("rawValues", []) rsi = col_map.get("RelativeStrengthIndex", {}).get("rawValues", []) name = info.get("description", symbols[i] if i < len(symbols) else "") tech_val = tech[i] if i < len(tech) else "N/A" rsi_val = ( round(rsi[i], 2) if i < len(rsi) and isinstance(rsi[i], (int, float)) else "N/A" ) lines.append(f"- {name}: Signal={tech_val}, RSI={rsi_val}") return "\n".join(lines) def fetch_breaking_news_data() -> str: """Fetch breaking financial and market news from TradingView.""" params = { "filter": ["lang:en_IN", "priority:important"], "client": "screener", "streaming": "true", "user_prostatus": "non_pro", } try: resp = http_requests.get( _TV_NEWS_URL, params=params, headers=_TV_HEADERS, timeout=10, ) resp.raise_for_status() items = resp.json().get("items", []) except Exception as exc: return f"Failed to fetch breaking news: {exc}" top = items[:8] if not top: return "No breaking news available right now." lines = [f"Breaking market news ({len(top)} headlines):"] for idx, item in enumerate(top, 1): title = item.get("title", "Untitled") provider = "" prov = item.get("provider") if isinstance(prov, dict): provider = prov.get("name", "") lines.append(f"{idx}. [{provider}] {title}") return "\n".join(lines) def calculate_expression(expression: str) -> str: """Evaluate a mathematical expression safely.""" allowed = {"abs": abs, "round": round, "min": min, "max": max, "sum": sum} try: result = eval(expression, {"__builtins__": {}}, allowed) # noqa: S307 return f"Result: {result}" except Exception as exc: return f"Calculation error: {exc}"