8 Commits (27990ea9081e8819689b0428325d03b3d2fd6928)

Author SHA1 Message Date
I Luk Kim c4565159b1 fix: universe service - NASDAQ case bug + OOM prevention
Two fixes to universe snapshot build:

1. SEC EDGAR exchange case mismatch: company_tickers_exchange.json uses
   "Nasdaq" (mixed case) but filter expected "NASDAQ". All NASDAQ-listed
   stocks (AAPL, MSFT, GOOGL, etc.) were silently excluded from registry.
   Fixed with case-insensitive _US_EXCHANGE_MAP lookup + canonical normalization.

2. OOM during large builds: SEC EDGAR companyfacts JSONs accumulate in
   _json_cache without eviction, causing OOM after ~1500-1800 tickers.
   Fixed by clearing _json_cache + _text_cache + gc.collect() every 20
   batches. Memory remains stable throughout full 9,376-ticker build.

Result: 529,328 snapshot rows, 5,570 tickers (NASDAQ:2515, NYSE:2084, OTC:971)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 24736954bb fix: yfinance threads=False + 배치 30개로 OS 스레드 폭발 방지
threads=True일 때 배치당 50개 OS 스레드 생성 → 시스템 자원 고갈 → API 먹통.
threads=False로 순차 다운로드, 배치 30개로 축소.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 1b037c9256 fix: full force_rebuild 시 universe_snapshot 전체 삭제
tickers=None (전체 빌드)일 때 registry에서 제거된 stale 티커 데이터도
정리되도록 DELETE FROM universe_snapshot 실행.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim e51e045169 fix: universe build을 isolated thread로 분리하여 API 먹통 방지
BackgroundTask가 FastAPI event loop을 공유해서 deadlock 발생 →
별도 thread에서 새 asyncio event loop으로 실행하도록 변경.
- API event loop 완전 분리
- DB 커넥션 풀 독립적 사용 (per-batch factory session)
- 빌드 중 API 정상 응답 유지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 0e048f82ef fix: universe build event loop 차단 방지
- _PRICE_BATCH 100 → 50 (배치당 부하 감소)
- 배치 완료 후 asyncio.sleep(1) 추가 (event loop yield)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim b54ac6d5b7 fix: universe 데이터 품질 개선 — sanity check + preferred stock 필터링
- SEC EDGAR fallback에서 "-" 포함 티커 제외 (preferred stock, BAC-PL 등)
- W/R/Z suffix 티커 제외 (warrant, right, special)
- build_snapshots: close > $1M 또는 shares < 100,000 또는 market_cap > $5T 제외
- screen_historical: market_cap > $5T 쿼리 레벨 필터 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 5ab1663977 feat: universe discover에 SEC EDGAR fallback 추가
yf.screen() 401 에러 시 SEC EDGAR company_tickers_exchange.json으로 자동 전환.
- 5,848개 NYSE/NASDAQ/AMEX/ARCA 종목 등록 가능
- response에 source 필드 추가 (yfinance / sec_edgar)
- market_cap_min 필터는 yfinance 사용 시에만 적용 (SEC Edgar fallback 시 미적용, 스크리닝 시점에 필터링)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim b3092a0d5e feat: 백테스팅 유니버스 과거 시점 주식 스크리닝 (Historical Stock Universe)
## 새 기능
- GET  /universe/screen — 과거 날짜 기준 시총/섹터/거래소 필터링
- GET  /universe/registry — 추적 종목 목록 조회
- POST /universe/admin/discover — yfinance screener로 US 주식 자동 등록
- POST /universe/admin/build-snapshots — SEC EDGAR × yfinance 월별 시총 스냅샷 생성

## 데이터 모델
- universe_ticker_registry: 종목 마스터 (ticker, name, cik, sector, industry, exchange)
- universe_snapshot: 월별 스냅샷 (ticker, snapshot_date, market_cap, close_price, shares_outstanding)
  - 인덱스: (snapshot_date, market_cap) — 핵심 스크리닝 쿼리 최적화
  - ~4000종목 × 120개월 ≈ 480K 행 예상

## 데이터 흐름
1. SEC EDGAR companyfacts → shares_outstanding (최신, 주가분할 반영)
2. yfinance bulk download 1mo interval → 월별 종가
3. market_cap = latest_shares × close_price (yfinance 분할조정 가격과 일관성)

## 제한사항
- Survivorship bias: 현재 상장 종목만 (상폐 종목 미포함)
- 자사주 매입으로 과거 시총 ~20% 오차 가능 (분할 오차 방지가 주목적)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago