# KRX Open API 전환 설계 ## 배경 - pykrx는 KRX 웹 스크래핑 방식으로 불안정 (로그인 필수화, 구조 변경 시 깨짐) - KRX Open API (openapi.krx.co.kr) 공식 REST API로 전환하여 안정성 확보 - `pykrx-openapi` 라이브러리 활용 (MIT, pip install pykrx-openapi) ## 전환 범위 ### 현재 pykrx 의존 Collector (5개) | Collector | pykrx 함수 | KRX Open API 대체 | |---|---|---| | StockCollector | `get_market_ticker_list`, `get_market_cap_by_ticker`, `get_market_fundamental_by_ticker` | `get_stock_base_info`, `get_stock_daily_trade`, `get_kosdaq_stock_daily_trade` | | PriceCollector | `get_market_ohlcv` | `get_stock_daily_trade`, `get_kosdaq_stock_daily_trade` | | ValuationCollector | `get_market_fundamental_by_ticker` | pykrx 유지 또는 별도 소스 (Open API에 PER/PBR 없음) | | ETFCollector | `ETF_전종목기본종목().fetch()` | `get_etf_daily_trade` (종목 목록 겸용) | | ETFPriceCollector | `get_etf_ohlcv_by_date` | `get_etf_daily_trade` | ### 주의: ValuationCollector KRX Open API 서비스 목록에 PER/PBR/배당수익률 API가 없음. → ValuationCollector는 pykrx(스크래핑) 유지 또는 네이버/FnGuide 등 대체 소스 검토. → 1차 전환에서는 pykrx fallback으로 유지. ### 스크립트 의존 - `scripts/generate_snapshots.py` — `pykrx_stock.get_etf_ohlcv_by_date` 사용 - `jobs/kjb_signal_job.py` — `Price.ticker == "069500"` (DB 조회, pykrx 직접 의존 없음) - `app/services/optimizer.py` — DB 조회만, pykrx 직접 의존 없음 ## 구현 계획 ### 1. KRX Open API 클라이언트 모듈 생성 **파일:** `backend/app/services/krx_client.py` ```python from pykrx_openapi import KRXOpenAPI class KRXClient: """Thin wrapper around pykrx-openapi with project defaults.""" def __init__(self, api_key: str = None): self.client = KRXOpenAPI( api_key=api_key or os.getenv("KRX_OPENAPI_KEY"), rate_limit=10, per_seconds=1, timeout=30, ) def get_etf_daily(self, date: str) -> pd.DataFrame: ... def get_stock_daily(self, date: str, market: str) -> pd.DataFrame: ... def get_stock_base_info(self, date: str, market: str) -> pd.DataFrame: ... ``` ### 2. Collector 전환 (4개) 각 collector에 `KRX_OPENAPI_KEY` 환경변수가 있으면 Open API 사용, 없으면 pykrx fallback. - **ETFCollector** → `get_etf_daily_trade` 로 전종목 ETF 목록 + 기본정보 취득 - **ETFPriceCollector** → `get_etf_daily_trade` 로 종가/거래량 취득 - **StockCollector** → `get_stock_base_info` + `get_stock_daily_trade` + `get_kosdaq_stock_daily_trade` - **PriceCollector** → `get_stock_daily_trade` + `get_kosdaq_stock_daily_trade` ### 3. ValuationCollector 1차: pykrx 유지 (KRX_ID/KRX_PW 사용) 향후: 네이버 금융 또는 FnGuide 스크래핑으로 전환 검토 ### 4. generate_snapshots.py 전환 `pykrx_stock.get_etf_ohlcv_by_date` → `KRXClient.get_etf_daily` ### 5. 의존성 변경 - `pyproject.toml`: `pykrx-openapi` 추가 - `pykrx` 는 ValuationCollector 용으로 유지 - `.env.example`: `KRX_OPENAPI_KEY` 추가 - Gitea Secrets: `KRX_OPENAPI_KEY` 추가 ### 6. 테스트 - 기존 unit test 업데이트 (mock 대상 변경) - KRX Open API mock으로 테스트 ## 환경 변수 ``` KRX_OPENAPI_KEY=xxx # KRX Open API 인증키 (신규) KRX_ID=xxx # pykrx 웹 로그인 (ValuationCollector용, 유지) KRX_PW=xxx # pykrx 웹 로그인 (ValuationCollector용, 유지) ``` ## 롤백 전략 - `KRX_OPENAPI_KEY` 환경변수를 제거하면 자동으로 pykrx fallback - 기존 pykrx 코드는 삭제하지 않고 fallback으로 유지 ## 작업 완료 조건 - [ ] KRX Open API 클라이언트 모듈 - [ ] ETFCollector 전환 - [ ] ETFPriceCollector 전환 - [ ] StockCollector 전환 - [ ] PriceCollector 전환 - [ ] generate_snapshots.py 전환 - [ ] 테스트 통과 - [ ] .env.example / deploy.yml 업데이트