125 lines
4.3 KiB
Python
125 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from app.agents.tools.types import ToolResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def get_stock_price(params: dict[str, Any]) -> ToolResult:
|
|
"""종목 OHLCV 데이터를 pykrx로 조회한다."""
|
|
from pykrx import stock as pykrx_stock
|
|
|
|
ticker = params.get("ticker", "")
|
|
start_date = params.get("start_date", "")
|
|
end_date = params.get("end_date", "")
|
|
|
|
if not all([ticker, start_date, end_date]):
|
|
return ToolResult(data="Error: ticker, start_date, end_date 모두 필수입니다.")
|
|
|
|
try:
|
|
df = pykrx_stock.get_market_ohlcv_by_date(start_date, end_date, ticker)
|
|
if df.empty:
|
|
return ToolResult(data=f"데이터 없음: {ticker} ({start_date}~{end_date})")
|
|
|
|
records = df.reset_index().to_dict(orient="records")
|
|
return ToolResult(
|
|
data={"ticker": ticker, "period": f"{start_date}~{end_date}", "ohlcv": records}
|
|
)
|
|
except Exception as e:
|
|
logger.exception("get_stock_price failed for %s", ticker)
|
|
return ToolResult(data=f"Error: {e}")
|
|
|
|
|
|
async def get_financial_statements(params: dict[str, Any]) -> ToolResult:
|
|
"""종목의 재무제표 데이터를 pykrx로 조회한다."""
|
|
from pykrx import stock as pykrx_stock
|
|
|
|
ticker = params.get("ticker", "")
|
|
year = params.get("year", "")
|
|
|
|
if not all([ticker, year]):
|
|
return ToolResult(data="Error: ticker, year 모두 필수입니다.")
|
|
|
|
try:
|
|
# pykrx 기본 재무 데이터: BPS, PER, PBR, EPS, DIV, DPS
|
|
start_date = f"{year}0101"
|
|
end_date = f"{year}1231"
|
|
df = pykrx_stock.get_market_fundamental_by_date(start_date, end_date, ticker)
|
|
|
|
if df.empty:
|
|
return ToolResult(data=f"재무 데이터 없음: {ticker} ({year})")
|
|
|
|
# 연말 기준 최신 데이터
|
|
latest = df.iloc[-1].to_dict()
|
|
return ToolResult(
|
|
data={"ticker": ticker, "year": year, "fundamentals": latest}
|
|
)
|
|
except Exception as e:
|
|
logger.exception("get_financial_statements failed for %s", ticker)
|
|
return ToolResult(data=f"Error: {e}")
|
|
|
|
|
|
async def get_market_metrics(params: dict[str, Any]) -> ToolResult:
|
|
"""종목의 시가총액, PER, PBR 등 시장 지표를 조회한다."""
|
|
from pykrx import stock as pykrx_stock
|
|
|
|
ticker = params.get("ticker", "")
|
|
date = params.get("date", "")
|
|
|
|
if not all([ticker, date]):
|
|
return ToolResult(data="Error: ticker, date 모두 필수입니다.")
|
|
|
|
try:
|
|
# 시가총액
|
|
cap_df = pykrx_stock.get_market_cap_by_date(date, date, ticker)
|
|
# 밸류에이션
|
|
fund_df = pykrx_stock.get_market_fundamental_by_date(date, date, ticker)
|
|
|
|
result: dict[str, Any] = {"ticker": ticker, "date": date}
|
|
|
|
if not cap_df.empty:
|
|
result["market_cap"] = cap_df.iloc[-1].to_dict()
|
|
if not fund_df.empty:
|
|
result["valuation"] = fund_df.iloc[-1].to_dict()
|
|
|
|
if len(result) == 2:
|
|
return ToolResult(data=f"시장 지표 없음: {ticker} ({date})")
|
|
|
|
return ToolResult(data=result)
|
|
except Exception as e:
|
|
logger.exception("get_market_metrics failed for %s", ticker)
|
|
return ToolResult(data=f"Error: {e}")
|
|
|
|
|
|
async def get_market_index(params: dict[str, Any]) -> ToolResult:
|
|
"""KOSPI/KOSDAQ 지수 데이터를 조회한다."""
|
|
from pykrx import stock as pykrx_stock
|
|
|
|
index_code = params.get("index_code", "1001") # 기본: 코스피
|
|
start_date = params.get("start_date", "")
|
|
end_date = params.get("end_date", "")
|
|
|
|
if not all([start_date, end_date]):
|
|
return ToolResult(data="Error: start_date, end_date 모두 필수입니다.")
|
|
|
|
try:
|
|
df = pykrx_stock.get_index_ohlcv_by_date(start_date, end_date, index_code)
|
|
|
|
if df.empty:
|
|
return ToolResult(data=f"지수 데이터 없음: {index_code} ({start_date}~{end_date})")
|
|
|
|
records = df.reset_index().to_dict(orient="records")
|
|
return ToolResult(
|
|
data={
|
|
"index_code": index_code,
|
|
"period": f"{start_date}~{end_date}",
|
|
"ohlcv": records,
|
|
}
|
|
)
|
|
except Exception as e:
|
|
logger.exception("get_market_index failed for %s", index_code)
|
|
return ToolResult(data=f"Error: {e}")
|