Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 기반 환경변수 로딩
설치
pip install -e .
다른 서비스에서 의존성으로 사용:
# pyproject.toml
[project]
dependencies = ["stock-common"]
Docker 빌드 시:
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 파일도 지원합니다.
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 큐 길이 |
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컨텍스트 매니저
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)
서비스 간 비동기 메시지 전달:
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
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
Description
Languages
Python
100%