from fastapi import APIRouter, HTTPException from pydantic import BaseModel from typing import List router = APIRouter(prefix="/api/watchlist", tags=["watchlist"]) # Intentionally duplicated from market_data.py to keep this system fully decoupled # from the other instrument-list mechanisms (market_watchlist, INSTRUMENT_MODELS, # instruments.json, options_vol watchlist-tickers). _QUOTE_TYPE_TO_ASSET_CLASS = { "CURRENCY": "forex", "FUTURE": "energy", "INDEX": "indices", "ETF": "etfs", "EQUITY": "equities", "MUTUALFUND": "etfs", } @router.get("/") def list_watchlist(): from services.database import get_instruments_watchlist return get_instruments_watchlist() @router.get("/quotes") def watchlist_quotes(): from services.database import get_instruments_watchlist from services.data_fetcher import get_quote items = [] for row in get_instruments_watchlist(): q = get_quote(row["ticker"]) or {} items.append({ **row, "price": q.get("price"), "change_pct": q.get("change_pct"), }) return {"items": items} @router.post("/{ticker}") def add_ticker(ticker: str): from services.data_fetcher import get_quote from services.database import get_instruments_watchlist, add_instrument_watchlist import yfinance as yf ticker = ticker.strip().upper() if any(row["ticker"] == ticker for row in get_instruments_watchlist()): raise HTTPException(409, f"'{ticker}' is already in the watchlist") q = get_quote(ticker) if not q or not q.get("price"): raise HTTPException(400, f"Ticker '{ticker}' not found on yfinance") name = ticker asset_class = "unknown" try: info = yf.Ticker(ticker).fast_info name = getattr(info, "long_name", None) or getattr(info, "short_name", None) or ticker quote_type = getattr(info, "quote_type", "") or "" asset_class = _QUOTE_TYPE_TO_ASSET_CLASS.get(quote_type.upper(), "unknown") except Exception: pass add_instrument_watchlist(ticker, name, asset_class) return {"ticker": ticker, "name": name, "asset_class": asset_class, "price": q["price"]} @router.delete("/{ticker}") def remove_ticker(ticker: str): from services.database import remove_instrument_watchlist remove_instrument_watchlist(ticker.strip().upper()) return {"removed": ticker.strip().upper()} class ReorderBody(BaseModel): tickers: List[str] @router.put("/reorder") def reorder(body: ReorderBody): from services.database import reorder_instruments_watchlist reorder_instruments_watchlist(body.tickers) return {"ok": True}