Coverage for view / web / routes / ranking.py: 100%
38 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-04 15:08 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-04 15:08 +0000
1"""
2랭킹/시가총액 관련 API 엔드포인트 (ranking.html, marketcap.html).
3"""
4from fastapi import APIRouter, HTTPException
5from common.types import ErrorCode
6from view.web.api_common import _get_ctx, _serialize_response, _serialize_list_items
8router = APIRouter()
11@router.get("/ranking/progress")
12async def get_ranking_progress():
13 """투자자 랭킹 수집 진행률 조회."""
14 ctx = _get_ctx()
15 if ctx.ranking_task:
16 return ctx.ranking_task.get_investor_ranking_progress()
17 return {"running": False, "processed": 0, "total": 0, "collected": 0, "elapsed": 0.0}
20@router.get("/ranking/{category}")
21async def get_ranking(category: str):
22 """랭킹 조회 (rise/fall/volume/trading_value/foreign_buy/foreign_sell/inst_buy/inst_sell/prsn_buy/prsn_sell)."""
23 ctx = _get_ctx()
24 t_start = ctx.pm.start_timer()
25 valid = ("rise", "fall", "volume", "trading_value",
26 "foreign_buy", "foreign_sell", "inst_buy", "inst_sell", "prsn_buy", "prsn_sell",
27 "program_buy", "program_sell")
28 if category not in valid:
29 raise HTTPException(status_code=400, detail=f"category는 {', '.join(valid)} 중 하나여야 합니다.")
31 resp = await ctx.stock_query_service.handle_get_top_stocks(category)
33 ctx.pm.log_timer(f"get_ranking({category})", t_start)
34 if resp and resp.rt_cd == ErrorCode.SUCCESS.value:
35 return {
36 "rt_cd": resp.rt_cd,
37 "msg1": resp.msg1,
38 "data": _serialize_list_items(resp.data)
39 }
40 return _serialize_response(resp)
43@router.get("/top-market-cap")
44async def get_top_market_cap(limit: int = 20, market: str = "0001"):
45 """시가총액 상위 종목. market: 0001=거래소(코스피), 1001=코스닥"""
46 ctx = _get_ctx()
47 t_start = ctx.pm.start_timer()
48 if market not in ("0000", "0001", "1001", "2001"):
49 market = "0001"
50 resp = await ctx.broker.get_top_market_cap_stocks_code(market, limit)
51 ctx.pm.log_timer(f"get_top_market_cap({market}, {limit})", t_start)
52 if resp and resp.rt_cd == ErrorCode.SUCCESS.value:
53 items = resp.data or []
54 data = []
55 for idx, item in enumerate(items, 1):
56 get = (lambda k: getattr(item, k, None)) if not isinstance(item, dict) else item.get
57 data.append({
58 "rank": str(idx),
59 "name": get("hts_kor_isnm") or "",
60 "code": get("mksc_shrn_iscd") or get("iscd") or "",
61 "current_price": get("stck_prpr") or "0",
62 "change_rate": get("prdy_ctrt") or "0",
63 "market_cap": get("stck_avls") or "0",
64 })
65 return {"rt_cd": resp.rt_cd, "msg1": resp.msg1, "data": data}
66 return _serialize_response(resp)