From b322d28bd984b0b8ceb99262b77e2861db3ef336 Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Mon, 20 Apr 2026 16:17:10 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20yfinance=5Fplus=20.info=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=A7=80=EC=9B=90=20+=20company=20metadata=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - yfinance_plus submodule 업데이트 (EnhancedTicker.info property 추가) - company_metadata_service: yfinance_plus 우선 import (fallback: vanilla yfinance) - Dockerfile: COPY 후 site-packages에 로컬 yfinance_plus 덮어쓰기 - docs/DATA_COVERAGE.md: /company 엔드포인트 섹션 추가, /financial 변경사항 기록 Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 5 +- app/services/company_metadata_service.py | 5 +- docs/DATA_COVERAGE.md | 60 +++++++++++++++++++++++- yfinance_plus | 2 +- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 75d2ab5..99ea7df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,12 +11,15 @@ RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* COPY requirements-api.txt . RUN pip install --no-cache-dir -r requirements-api.txt -# Install updated yfinance_plus from Gitea repository +# Install updated yfinance_plus from Gitea repository (base version) RUN pip install git+https://gitea.yirugi.synology.me/yirugi/yfinance_plus.git@9fae52e # Copy application code COPY . . +# Override installed yfinance_plus with local version (adds .info property support) +RUN cp /app/yfinance_plus/yfinance_plus.py /usr/local/lib/python3.11/site-packages/yfinance_plus.py + # Create data directory for SQLite RUN mkdir -p /app/data diff --git a/app/services/company_metadata_service.py b/app/services/company_metadata_service.py index 8c8ed50..0d3b6fe 100644 --- a/app/services/company_metadata_service.py +++ b/app/services/company_metadata_service.py @@ -14,7 +14,10 @@ import logging from datetime import datetime, timezone from typing import Optional -import yfinance as yf +try: + import yfinance_plus as yf +except ImportError: + import yfinance as yf from sqlalchemy import select from sqlalchemy.dialects.postgresql import insert as pg_insert from sqlalchemy.ext.asyncio import AsyncSession diff --git a/docs/DATA_COVERAGE.md b/docs/DATA_COVERAGE.md index b68157e..d18f5ef 100644 --- a/docs/DATA_COVERAGE.md +++ b/docs/DATA_COVERAGE.md @@ -2,7 +2,7 @@ 각 API 엔드포인트의 **실제 DB 보유 데이터 범위**와 **과거 데이터 백필 방법**을 정리한 문서입니다. -> 마지막 업데이트: 2026-03-29 +> 마지막 업데이트: 2026-04-20 > DB 실측 기준 --- @@ -27,6 +27,8 @@ | `/insider/transactions` | SEC EDGAR Form 4 | ✅ | 요청 기반 자동 누적 | 2004년~ | 요청 기반 자동 누적 | | `/earnings/surprise` | yfinance-plus earnings_dates | ✅ | 요청 기반 자동 누적 | ~25분기 (6년+) | 요청 기반 자동 누적 | | `/universe/screen` | SEC EDGAR + yfinance 월별 스냅샷 | ✅ (사전 빌드 필요) | admin 빌드 후 사용 가능 | 2010년~ | **⚠️ 사전 빌드 필요** | +| `/company/{ticker}` | yfinance-plus + universe_ticker_registry | ✅ (Redis 24h + DB 영구) | 모든 yfinance 지원 티커 | 즉시 | 요청 기반 자동 누적 | +| `/company/bulk` | yfinance-plus + universe_ticker_registry | ✅ (Redis 24h + DB 영구) | 최대 100 티커/요청 | 즉시 | 요청 기반 자동 누적 | --- @@ -375,6 +377,62 @@ curl "http://localhost:18001/api/v1/universe/screen?date=2020-01-01&market_cap_m --- +### `/api/v1/company` — 종목 메타데이터 (신규, 2026-04-20) + +**현재 DB 보유**: 조회 시 자동 저장. 두 번째 조회부터 DB 히트 (Redis 24h → DB 영구). + +**데이터 소스**: yfinance-plus `.info` → `universe_ticker_registry` + `companies` 테이블 UPSERT + +**반환 필드**: `ticker`, `name`, `cik`, `exchange`, `sector`, `industry`, `country`, `market_cap`, `business_description` + +| 엔드포인트 | 메서드 | 설명 | +|---|---|---| +| `/company/{ticker}` | `GET` | 단일 종목 메타데이터. 미지원 티커 → 404 | +| `/company/bulk` | `POST` | 최대 100개 일괄 조회. 부분 실패 허용 (per-ticker `error` 필드) | + +**캐시 전략**: +- Redis 24h TTL (key: `company:meta:{TICKER}`) +- yfinance 실패 시 15분 TTL (재시도 빈도 조절) +- DB에 영구 저장 (sector 있는 경우 fast-path: DB만 조회, yfinance 미호출) + +**조회 예시**: + +```bash +# 단일 종목 +curl "http://localhost:18001/api/v1/company/AU" +# → {"ticker":"AU","sector":"Basic Materials","industry":"Gold","exchange":"NYSE","country":"United States",...} + +# 유효하지 않은 티커 → 404 +curl "http://localhost:18001/api/v1/company/ZZZZZZ" +# → {"detail":"Unknown ticker: ZZZZZZ"} + +# 최대 100개 일괄 조회 +curl -X POST "http://localhost:18001/api/v1/company/bulk" \ + -H "Content-Type: application/json" \ + -d '{"tickers":["AU","USAS","CPRX","HE","ACHR"]}' +# → {"results":[...],"total":5,"success_count":5,"error_count":0} +``` + +**성능 특성**: +- 콜드 캐시 (첫 조회): yfinance 호출 ~2-5초 / 티커. 동시 최대 5개 (semaphore) +- 웜 캐시 (재조회): Redis <10ms / DB <50ms +- bulk 100개 콜드 캐시: ~30-50초 (semaphore=5로 직렬화) + +**sector 대량 사전 보강** (선택): +```bash +# universe_ticker_registry의 NULL sector 전체 보강 (~30분, 9376 티커) +python scripts/backfill_registry_sector.py --batch 50 +# Dry-run +python scripts/backfill_registry_sector.py --dry-run +``` + +**`/financial/data/{ticker}` 변경사항** (2026-04-20): +- `company` 블록에 `exchange`, `country`, `market_cap` 필드 추가 +- placeholder sector(`Technology/Software/XXX Corporation`) 감지 시 자동 재보강 +- financials/price 조회 실패 시에도 `company` 블록은 200 OK로 유지 (이전: 500 가능) + +--- + ## 백필 우선순위 권장 사항 | 우선순위 | 대상 | 이유 | 예상 소요 시간 | diff --git a/yfinance_plus b/yfinance_plus index 343aac0..674b7e4 160000 --- a/yfinance_plus +++ b/yfinance_plus @@ -1 +1 @@ -Subproject commit 343aac090d06d6de7edca946be4f651112e43168 +Subproject commit 674b7e45c8c79f3617dee9cffdd3f1438e4852cf