12 Commits (e25f7295a67ff8e54cddee25f9dc1a18023dd942)

Author SHA1 Message Date
I Luk Kim dd3e38fbf5 fix: GET /price/data — Alpaca → yfinance 교체 + bulk end_date 버그 2건 수정
- GET /price/data를 AlpacaPriceService 대신 PriceDataService(yfinance)로 교체
- ?ticker= alias 추가 (기존 ?tickers= 유지, 인터페이스 호환)
- _bulk_fetch_price_data: yfinance end 파라미터 exclusive 미반영 (+1일 누락) 수정
- get_multi_ticker_daily_bars: end_dt를 min.time(00:00) → max.time(23:59:59)으로 수정
  (DB 쿼리 date <= end_dt 에서 당일 레코드가 필터링되던 버그)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim c203f3920b refactor: session-per-phase — DB 커넥션을 외부 API 호출 중 해제
서비스 메서드가 db: AsyncSession을 인자로 받아 외부 API 호출(yfinance 30-60s,
Alpaca HTTP) 중에도 DB 커넥션을 잡고 있던 구조를 제거.

변경 패턴 (Session-per-phase):
  Before: Endpoint(db) → Service(db) → DB check → API call(30s 세션 유지) → DB store
  After:  Endpoint()   → Service()   → DB check(세션1) → API call(세션 없음) → DB store(세션2)

변경 파일:
- alpaca_price_service.py: fetch_and_store_bars, get_or_fetch_multi_bars에서 db 제거
- price_data_service.py: get_or_update_price_data, get_multiple_tickers_data_optimized에서
  db 제거; _fetch_price_data(새), _bulk_fetch_price_data(새, lambda 클로저 버그 수정);
  _fetch_and_store_price_data, _bulk_fetch_and_store_price_data, get_multiple_tickers_data 제거
- alpaca.py, price.py: Depends(get_db) 제거 (GET /latest 제외)
- financial_service.py, real_sec_financial_service.py: 호출 인자 정리

결과: "idle in transaction" 커넥션 0개, 풀 고갈 원인 근본 해결

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 7db2e28691 docs: Alpaca 100-symbol batch limit — endpoint description + 502 error msg
Both GET /price/data and GET /alpaca/intraday:
- description에 배치 제한 설명 추가 (100개/요청, 자동 분할, 응답시간 선형 증가)
- 502 에러 메시지에 심볼 수 초과 가능성 힌트 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 22c1d975d4 docs: add intraday data limitations to endpoint descriptions
GET /price/intraday (Yahoo Finance):
- 15분 지연, 1m=7일/5m-30m=60일/1h=730일 한계
- 백테스트 용도, 실시간 전략 부적합

GET /alpaca/intraday (Alpaca IEX):
- 실시간, IEX 피드 2~5% 커버리지
- 거래량 낮게 표시, 가격 레벨은 유사
- ORB 등 당일 실시간 전략 용도

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 5ef4d1790d feat: GET /price/intraday — multi-ticker intraday via Yahoo Finance
Alpaca free plan blocks recent SIP data (403 on same-day requests).
Replace with Yahoo Finance which has no subscription requirement.

- PriceDataService.get_multi_intraday(): yf.download() in chunks of 50,
  handles both single (flat DataFrame) and multi-ticker (MultiIndex) cases
- GET /price/intraday?tickers=...&interval=5m&start_date=...&end_date=...
  → same AlpacaMultiBarsResponse format (bars: {sym → [{timestamp,ohlcv}]})
  → source="YAHOO_FINANCE", Redis 5-min TTL cache
- /alpaca/intraday still exists for historical data (works on free plan)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 2081611884 fix: multi-ticker daily bars — DB storage + DB-first fetch logic
- AlpacaPriceService.get_or_fetch_multi_bars(): checks DB max_date per
  ticker, only fetches missing ranges from Alpaca, upserts with chunking
  (3000 rows/chunk, asyncpg 32767-param limit) then reads back from DB
- GET /price/data endpoint: now uses service + Depends(get_db); subsequent
  calls for same date range skip Alpaca entirely
- force_refresh=true bypasses DB check and re-fetches all from Alpaca

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim fbb42edfc2 feat: multi-ticker bulk bars endpoints + BF-B ticker normalization
- GET /api/v1/price/data?tickers=AAPL,MSFT,BF-B&start_date=...&end_date=...
  → multi-ticker daily OHLCV via Alpaca (ORB engine daily bars interface)
- GET /api/v1/alpaca/intraday?tickers=...&interval=5min&start_date=...&end_date=...
  → multi-ticker intraday OHLCV via Alpaca (ORB engine ORB-window interface)
- AlpacaMultiBarsResponse schema: {source, interval, count, bars: {sym → [bar]}}
- normalize_ticker(): BF-B→BF.B, BRK-B→BRK.B applied in get_bars/get_multi_bars/get_snapshot(s)
- get_multi_bars: transparent batching (200 symbols/request) + INTERVAL_MAP aliases (5min, 15min, 60min, …)
- Response re-keys Alpaca normalized symbols back to original input names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 33b1749721 fix: GET /price/data/{ticker} — start/end alias 지원 + 단일 날짜 조회 허용
- ?start=&end= 쿼리 파라미터를 start_date/end_date의 alias로 수용
- end_date <= start_date 검증을 end_date < start_date 로 완화하여 당일(start==end) OHLCV 조회 가능

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim fb692fe592 feat: yfinance rate limit 처리 강화
- yfinance_plus: 세션 풀 다양화 (chrome/edge/safari/firefox 핑거프린트 6개)
  + 모듈 싱글톤으로 process-wide rate limiter 공유
  + Adaptive throttling (rate limit 감지 시 0.3s→최대 5s 자동 증가)
  + EnhancedTicker별 전용 세션으로 스레드 race condition 해결
- price.py: rate limit 에러 감지 시 HTTP 500 → HTTP 429 + Retry-After: 30
- test_rate_limit.py: rate limit 발생 조건 측정 스크립트 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 6a98cb2d94 perf: API 성능 개선 — 로그 분석 기반 6개 항목 수정
P0 — 500 에러 대폭 감소 (1.1% → 0.11%)
- price.py / financial.py: except HTTPException: raise 추가 →
  HTTPException(404)이 except Exception에 잡혀 500으로 재포장되던 버그 수정
- real_sec_financial_service: _get_price_data_for_period에 try/except 추가 →
  yfinance 실패가 financial 엔드포인트 500으로 전파되지 않도록 방어
- price.py: TimeoutError 별도 핸들러 추가 → yfinance 타임아웃 시 503 반환

P1 — _store_price_data() N+1 → batch upsert
- price_data_service: 252회 개별 SELECT+INSERT 루프를
  pg_insert(PriceData).on_conflict_do_nothing('uq_price_data') 단일 쿼리로 교체

P2 — financial/data 캐시 TTL 1h → 24h
- financial.py: 재무 데이터는 분기 발표 주기 → _FIN_TTL = 86400

P3 — 과거 가격 데이터 TTL 연장
- price.py: end_date < today-1 이면 TTL=7일, 나머지 1h 유지

P4 — 요청 로그 비동기 배치 처리
- error_logger.py: asyncio.Queue(10_000) 추가, _log_request를 put_nowait으로
  변경 (논블로킹), 백그라운드 _request_log_flusher 코루틴 (1s/100건마다 flush)
- main.py: 앱 시작 시 start_request_log_flusher() 호출

P5 — 누락 DB 인덱스 추가
- financial.py: CalculatedMetrics에 calculation_date, period_date 단독 인덱스
- attention.py: AttentionFeaturesDaily에 ticker 단독 인덱스
- alembic b3c4d5e6f7a8: 위 3개 인덱스 생성 마이그레이션 (idempotent)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 months ago
I Luk Kim 45d832ba5c perf: Phase 1-3 Stock Oracle API 성능 개선
Phase 1A - yfinance hang 제거
- _run_with_timeout() 헬퍼 추가 (asyncio.wait_for 래퍼)
- run_in_executor 6곳에 timeout 적용: history(30s), .info(20s), bulk download(60s)

Phase 1B - SEC Filing deadline 설정
- index_filings: 60s deadline + try/finally
- get_filing_documents: 30s deadline (중첩 호출 시 기존 deadline 유지)
- get_exhibit_content: 30s deadline + try/finally

Phase 1C - _get_ticker_max_range async 전환
- sync → async def + run_in_executor + wait_for(20s)
- get_or_create_company_data에서 period=="max" 사전 체크 → await 직접 호출

Phase 1D - Endpoint 레벨 timeout
- POST /price/data/bulk: 300s → 504
- POST /financial/data/bulk: 300s → 504
- GET /filings/search/{ticker}: 120s → 504
- GET /filings/documents/{accession}: 30s → 504
- GET /filings/exhibit/{accession}: 30s → 504

Phase 2 - Filing 캐시 추가
- GET /filings/documents: @with_cache(ttl=86400)
- GET /filings/exhibit: @with_cache(ttl=86400)

Phase 3A - POST /filings/search/bulk 추가
- BulkFilingSearchRequest/Item/Response 스키마
- search_filings_bulk(): 배치 DB 조회 → 미인덱싱 ticker 병렬 인덱싱(Semaphore 4)
- @with_cache(ttl=3600), 600s endpoint timeout

Phase 3B - POST /filings/exhibit/bulk 추가
- BulkExhibitRequest/Item/Response 스키마
- asyncio.gather + 개별 30s timeout, 최대 50건

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 355aeb19d3 Initial commit with full project improvements
Security: config-based CORS, default secret warnings, sort_by validation
Error handling: debug logging in cache silent failures
Architecture: shared resolve_time_parameters, deduplicated logger init, unified route structure
Database: conditional SQLite/PostgreSQL engine, in-memory test DB, dialect-aware date formatting, optimized stats query
Docker: .dockerignore, pinned yfinance_plus commit
Dependencies: removed duplicates, added version upper bounds, removed unused axios
Frontend: custom _document/_error pages, adminApi client, Layout standardization, ESLint version update

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