Files
OpenFin/backend/routers/instruments_watchlist.py
2026-07-14 11:21:43 +02:00

81 lines
2.6 KiB
Python

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}