# stock-common 한국 주식 분석 마이크로서비스 플랫폼의 **공유 라이브러리**. 모든 백엔드 서비스(`stock-dart-collector`, `stock-kis-collector`, `stock-screener` 등)가 이 패키지에 의존합니다. ## 주요 기능 - **데이터 모델**: Pydantic v2 기반 도메인 모델 (Stock, DailyPrice, Valuation, Financial, Screening 등) - **데이터베이스**: PostgreSQL (asyncpg) + MongoDB (motor) 커넥션 풀 관리 - **Redis Streams**: 서비스 간 비동기 메시지 큐 (publish/consume/ack) - **API 팩토리**: FastAPI 앱 생성 (`/health`, `/streams` 엔드포인트 자동 포함) - **Collector 베이스 클래스**: Rate limiting, 자동 재시도, HTTP 세션 관리 - **설정 관리**: pydantic-settings 기반 환경변수 로딩 ## 설치 ```bash pip install -e . ``` 다른 서비스에서 의존성으로 사용: ```toml # pyproject.toml [project] dependencies = ["stock-common"] ``` Docker 빌드 시: ```dockerfile COPY stock-common/ /tmp/stock-common/ RUN pip install --no-cache-dir /tmp/stock-common/ ``` ## 모듈 구조 ``` src/stock_common/ ├── __init__.py ├── config.py # Settings (pydantic-settings) - 환경변수 관리 ├── logging_config.py # structlog 기반 로깅 설정 ├── api_base.py # FastAPI 앱 팩토리 (create_app) ├── collector_base.py # BaseCollector ABC (rate limit, retry) ├── database/ │ ├── __init__.py │ ├── postgres.py # asyncpg 커넥션 풀 (get_pg_pool) │ └── mongodb.py # motor 클라이언트 (get_mongo_database) ├── queue/ │ ├── __init__.py │ ├── redis_client.py # Redis 싱글턴 (get_redis) │ └── streams.py # publish / consume / ack └── models/ ├── __init__.py ├── stock.py # Stock, Market ├── price.py # DailyPrice ├── valuation.py # Valuation (PER, PBR, ROE...) ├── financial.py # Financial, PeriodType ├── screening.py # ScreeningResult, ScreeningStrategy ├── analysis.py # LLMAnalysis, Recommendation ├── disclosure.py # Disclosure, Sentiment └── news.py # News ``` ## 핵심 컴포넌트 ### Settings (config.py) pydantic-settings로 환경변수를 자동 로딩합니다. `.env` 파일도 지원합니다. ```python from stock_common.config import settings # 데이터베이스 settings.postgres_dsn # postgresql://stock:stock@localhost:5432/stockdb settings.mongodb_uri # mongodb://localhost:27017 settings.redis_url # redis://localhost:6379/0 # API 키 settings.dart_api_key settings.kis_app_key settings.anthropic_api_key # Rate Limits settings.dart_rate_limit # 10.0 req/s settings.kis_rate_limit # 20.0 req/s ``` ### API 팩토리 (api_base.py) 모든 서비스는 `create_app()`으로 FastAPI 인스턴스를 생성합니다. 자동으로 포함되는 엔드포인트: | 엔드포인트 | 설명 | |-----------|------| | `GET /health` | 서비스 상태, Redis 연결, uptime | | `GET /streams` | 관련 Redis Stream 큐 길이 | ```python from stock_common.api_base import create_app app = create_app( title="stock-dart-collector", streams=["queue:trigger-dart", "queue:raw-financials"], ) # 서비스별 엔드포인트 추가 @app.post("/collect/financials") async def collect_financials(...): ... ``` ### BaseCollector (collector_base.py) HTTP API 수집기의 공통 패턴: - **Rate Limiting**: `aiolimiter.AsyncLimiter`로 초당 요청 수 제한 - **자동 재시도**: `tenacity`로 최대 3회, 지수 백오프 (1~30초) - **429 처리**: `Retry-After` 헤더 존중 - **세션 관리**: `async with` 컨텍스트 매니저 ```python from stock_common.collector_base import BaseCollector class DARTCollector(BaseCollector): def __init__(self): super().__init__(rate_limit=10.0, timeout=30) async def collect(self, **kwargs): data = await self._request("GET", url, params=params) binary = await self._download_binary(url) ``` ### Redis Streams (queue/streams.py) 서비스 간 비동기 메시지 전달: ```python from stock_common.queue import publish, consume, ack # 메시지 발행 msg_id = await publish("queue:trigger-dart", {"type": "financials", "stock_codes": ["005930"]}) # 메시지 소비 (consumer group) messages = await consume("queue:trigger-dart", "dart-collectors", "worker-1", count=10, block=5000) for msg in messages: process(msg.data) await ack("queue:trigger-dart", "dart-collectors", msg.message_id) ``` ### Database ```python from stock_common.database import get_pg_pool, get_mongo_database # PostgreSQL (asyncpg) pool = await get_pg_pool() async with pool.acquire() as conn: rows = await conn.fetch("SELECT * FROM stock WHERE is_active = true") # MongoDB (motor) db = get_mongo_database() cursor = db.llm_analysis.find({"stock_code": "005930"}) docs = await cursor.to_list(10) ``` ## 의존성 | 패키지 | 용도 | |--------|------| | `pydantic` >= 2.0 | 데이터 모델 | | `pydantic-settings` >= 2.0 | 환경변수 설정 | | `asyncpg` >= 0.29 | PostgreSQL 비동기 드라이버 | | `motor` >= 3.3 | MongoDB 비동기 드라이버 | | `redis` >= 5.0 | Redis 클라이언트 | | `fastapi` >= 0.115 | REST API 프레임워크 | | `uvicorn` >= 0.34 | ASGI 서버 | | `aiohttp` >= 3.9 | 비동기 HTTP 클라이언트 | | `aiolimiter` >= 1.1 | Rate limiting | | `tenacity` >= 8.2 | 재시도 로직 | | `structlog` >= 24.0 | 구조화된 로깅 | ## 요구사항 - Python >= 3.12 - 빌드: hatchling