import json from fastapi import APIRouter, Depends, Query from app.api.deps import get_current_user from app.models.user import User from app.core.redis import get_redis from app.services import stock_service router = APIRouter(prefix="/stocks", tags=["stocks"]) CACHE_TTL = 30 # seconds # ── market overview ─────────────────────────────────────────────────────────── @router.get("/market/overview") async def market_overview(current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = "market:overview" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_market_overview() await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data # ── heatmap ─────────────────────────────────────────────────────────────────── @router.get("/market/heatmap") async def market_heatmap(current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = "market:heatmap" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_all_stocks_spot() await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data # ── sector ──────────────────────────────────────────────────────────────────── @router.get("/market/sectors") async def market_sectors(current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = "market:sectors" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_sector_spot() await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data # ── single stock quote ──────────────────────────────────────────────────────── @router.get("/{symbol}/quote") async def stock_quote(symbol: str, current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = f"quote:{symbol}" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_stock_quote(symbol) if data: await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data or {} # ── K-line ──────────────────────────────────────────────────────────────────── @router.get("/{symbol}/kline") async def stock_kline( symbol: str, period: str = Query("daily", pattern="^(daily|weekly|monthly)$"), adjust: str = Query("qfq", pattern="^(qfq|hfq|)$"), limit: int = Query(250, ge=10, le=1000), current_user: User = Depends(get_current_user), ): redis = await get_redis() cache_key = f"kline:{symbol}:{period}:{adjust}:{limit}" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_kline(symbol, period, adjust, limit) await redis.setex(cache_key, 300, json.dumps(data)) return data # ── intraday ────────────────────────────────────────────────────────────────── @router.get("/{symbol}/intraday") async def stock_intraday(symbol: str, current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = f"intraday:{symbol}" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_intraday(symbol) await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data # ── 5-day ───────────────────────────────────────────────────────────────────── @router.get("/{symbol}/fiveday") async def stock_fiveday(symbol: str, current_user: User = Depends(get_current_user)): redis = await get_redis() cache_key = f"fiveday:{symbol}" cached = await redis.get(cache_key) if cached: return json.loads(cached) data = await stock_service.get_five_day(symbol) await redis.setex(cache_key, CACHE_TTL, json.dumps(data)) return data # ── search ──────────────────────────────────────────────────────────────────── @router.get("/search") async def search( q: str = Query(..., min_length=1), limit: int = Query(20, ge=1, le=50), current_user: User = Depends(get_current_user), ): return await stock_service.search_stocks(q, limit)