fix: custom tickers now placed in their natural asset-class tab

- Detect yfinance quote_type (CURRENCY→forex, FUTURE→energy, INDEX→indices,
  ETF→etfs, EQUITY→equities) when adding a custom ticker and persist it in
  market_watchlist.asset_class
- get_all_quotes() merges custom tickers into their proper group (e.g. EURUSD=X
  appears under Forex) instead of always under a separate "Custom" group
- "Custom" tab only shows tickers whose type couldn't be detected
- Add market_watchlist.asset_class migration; ensure backtest_lab_runs and
  market_watchlist are always created at init_db() time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-22 22:11:31 +02:00
parent c3ea0b7f8c
commit 33097e1812
3 changed files with 36 additions and 18 deletions

View File

@@ -45,6 +45,16 @@ def list_custom_tickers():
return get_market_custom_tickers()
_QUOTE_TYPE_TO_ASSET_CLASS = {
"CURRENCY": "forex",
"FUTURE": "energy",
"INDEX": "indices",
"ETF": "etfs",
"EQUITY": "equities",
"MUTUALFUND": "etfs",
}
@router.post("/custom-tickers/{ticker}")
def add_custom_ticker(ticker: str):
from services.data_fetcher import get_quote
@@ -55,13 +65,17 @@ def add_custom_ticker(ticker: str):
if not q or not q.get("price"):
from fastapi import HTTPException
raise HTTPException(400, f"Ticker '{ticker}' not found on yfinance")
name = ticker
asset_class = "custom"
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(), "custom")
except Exception:
name = ticker
add_market_custom_ticker(ticker, name)
return {"ticker": ticker, "name": name, "price": q["price"]}
pass
add_market_custom_ticker(ticker, name, asset_class)
return {"ticker": ticker, "name": name, "asset_class": asset_class, "price": q["price"]}
@router.delete("/custom-tickers/{ticker}")