diff --git a/app/api/v1/endpoints/alpaca.py b/app/api/v1/endpoints/alpaca.py index 9e7dea4..e47f0bc 100644 --- a/app/api/v1/endpoints/alpaca.py +++ b/app/api/v1/endpoints/alpaca.py @@ -4,10 +4,21 @@ Alpaca Market Data endpoints — standalone price data via Alpaca API from datetime import date, datetime, timezone, timedelta from typing import Optional +from zoneinfo import ZoneInfo from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession +_ET = ZoneInfo("America/New_York") +_MARKET_CLOSE_HOUR = 16 # 4:00 PM ET + + +def _market_closed_for(d: date) -> bool: + """Return True if the US equity market session for date d has ended.""" + now_et = datetime.now(_ET) + market_close_et = datetime(d.year, d.month, d.day, _MARKET_CLOSE_HOUR, 0, tzinfo=_ET) + return now_et >= market_close_et + from app.core.database import get_db from app.schemas.financial import ( AlpacaMultiBarsResponse, @@ -62,12 +73,12 @@ async def alpaca_status(): description=( "멀티 종목 과거 분봉 데이터를 Alpaca **SIP 피드**로 가져옵니다. " "DB에 저장되며 재요청 시 Alpaca 미호출.\n\n" - "**⚠️ 어제(yesterday)까지만 조회 가능** — 당일 데이터는 `/intraday/today` 사용\n\n" + "**⚠️ 장 중 당일 데이터 불가** — 장 마감(오후 4시 ET) 후에는 당일 날짜도 조회 가능\n\n" "| 항목 | 내용 |\n" "|------|------|\n" "| 피드 | **SIP** (전체 미국 거래소 통합) |\n" "| 거래량 | **100%** 정확 |\n" - "| 조회 범위 | **2016년~어제** |\n" + "| 조회 범위 | **2016년~오늘(장 마감 후)** |\n" "| DB 저장 | 있음 (재요청 시 Alpaca 미사용) |\n\n" "**권장 용도**: 백테스트, 과거 분봉 분석\n\n" "- `tickers`: comma-separated, e.g. `AAPL,MSFT,BF-B`\n" @@ -84,7 +95,7 @@ async def get_alpaca_intraday_multi( force_refresh: bool = Query(False, description="Re-fetch from Alpaca even if DB has data"), db: AsyncSession = Depends(get_db), ): - """Multi-ticker historical intraday bars via Alpaca SIP (up to yesterday).""" + """Multi-ticker historical intraday bars via Alpaca SIP (up to today after market close).""" symbols = [s.strip().upper() for s in tickers.split(",") if s.strip()] if not symbols: raise HTTPException(status_code=400, detail="No tickers provided.") @@ -95,11 +106,17 @@ async def get_alpaca_intraday_multi( _start = start_date or yesterday _end = end_date or yesterday - if _end >= date.today(): + today = date.today() + if _end > today: + raise HTTPException( + status_code=400, + detail="미래 날짜는 조회할 수 없습니다.", + ) + if _end == today and not _market_closed_for(today): raise HTTPException( status_code=400, - detail="이 엔드포인트는 어제(yesterday)까지의 과거 데이터만 조회 가능합니다. " - "당일 실시간 데이터는 GET /api/v1/alpaca/intraday/today 를 사용하세요.", + detail="장 중에는 당일 SIP 데이터를 조회할 수 없습니다. " + "실시간 데이터는 GET /api/v1/alpaca/intraday/today 를 사용하세요.", ) svc = _require_alpaca()