|
|
|
|
@ -74,8 +74,15 @@ async def alpaca_status():
|
|
|
|
|
summary="Get Alpaca bars (raw, no DB)",
|
|
|
|
|
description=(
|
|
|
|
|
"Fetch historical bars directly from Alpaca without storing in DB.\n\n"
|
|
|
|
|
"**주의**: 이 엔드포인트는 DB에 저장하지 않음. 저장이 필요하면 `/alpaca/data/{ticker}` 사용.\n\n"
|
|
|
|
|
"**이론적 범위**: Alpaca API 제공 범위 (~20년). `ALPACA_API_KEY` / `ALPACA_SECRET_KEY` 필수."
|
|
|
|
|
"**데이터 소스 (피드 자동 선택)**\n\n"
|
|
|
|
|
"| interval | 피드 | 특성 |\n"
|
|
|
|
|
"|----------|------|------|\n"
|
|
|
|
|
"| `1m` `5m` `15m` `30m` `1h` | **IEX** | 실시간, 거래량 2~5%, 무료 |\n"
|
|
|
|
|
"| `1d` `1w` `1mo` | **SIP** | 전체 거래소 통합, 정확, 무료 |\n\n"
|
|
|
|
|
"- DB에 저장하지 않음 — 저장이 필요하면 `/alpaca/data/{ticker}` 사용\n"
|
|
|
|
|
"- 조회 범위: 2016년~ (Alpaca 무료 플랜 기준)\n"
|
|
|
|
|
"- Redis 24시간 캐시 적용 (`force_refresh=true`로 우회)\n"
|
|
|
|
|
"- Requires `ALPACA_API_KEY` / `ALPACA_SECRET_KEY`"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
@with_cache(namespace="alpaca:bars", ttl=86400, key_params=["ticker", "interval", "start_date", "end_date", "limit"])
|
|
|
|
|
@ -126,11 +133,15 @@ async def get_alpaca_bars(
|
|
|
|
|
description=(
|
|
|
|
|
"Fetch OHLCV price data from Alpaca, store in AlpacaPriceData table, and return "
|
|
|
|
|
"in PriceDataResponse format. Includes vwap and trade_count in metadata.\n\n"
|
|
|
|
|
"**데이터 소스 (피드 자동 선택)**\n\n"
|
|
|
|
|
"| interval | 피드 | 특성 |\n"
|
|
|
|
|
"|----------|------|------|\n"
|
|
|
|
|
"| `1m` `5m` `15m` `30m` `1h` | **IEX** | 실시간, 거래량 2~5%, 무료 |\n"
|
|
|
|
|
"| `1d` `1w` `1mo` | **SIP** | 전체 거래소 통합, 정확, 무료 |\n\n"
|
|
|
|
|
"- DB 저장 후 재요청 시 Alpaca 미사용 (DB-first)\n"
|
|
|
|
|
"- Requires `ALPACA_API_KEY` / `ALPACA_SECRET_KEY`\n"
|
|
|
|
|
"- Uses `data_source = \"ALPACA\"` to distinguish from Yahoo data\n"
|
|
|
|
|
"- Supports: 1m, 5m, 15m, 1h, 1d, 1w, 1mo intervals\n\n"
|
|
|
|
|
"**현재 DB 보유**: 현재 테스트 데이터만 존재 (AAPL 27일치). "
|
|
|
|
|
"백필은 이 엔드포인트를 원하는 날짜 범위로 호출하면 자동으로 DB에 누적됨."
|
|
|
|
|
"- `data_source = \"ALPACA\"`로 Yahoo Finance 데이터와 구분\n"
|
|
|
|
|
"- 조회 범위: 2016년~ (Alpaca 무료 플랜 기준)"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
@with_cache(namespace="alpaca:data", ttl=86400, key_params=["ticker", "interval", "start_date", "end_date"])
|
|
|
|
|
@ -402,8 +413,21 @@ async def get_alpaca_intraday_today(
|
|
|
|
|
@router.get(
|
|
|
|
|
"/intraday/{ticker}",
|
|
|
|
|
response_model=AlpacaIntradayResponse,
|
|
|
|
|
summary="Get intraday candles from Alpaca",
|
|
|
|
|
description="Fetch intraday bars (1m, 5m, 15m, 1h) directly from Alpaca. Not stored in DB.",
|
|
|
|
|
summary="Get intraday candles from Alpaca (single ticker, IEX feed)",
|
|
|
|
|
description=(
|
|
|
|
|
"단일 종목의 분봉 데이터를 Alpaca **IEX 피드**로 직접 가져옵니다.\n\n"
|
|
|
|
|
"**데이터 소스: IEX 피드**\n\n"
|
|
|
|
|
"| 항목 | 내용 |\n"
|
|
|
|
|
"|------|------|\n"
|
|
|
|
|
"| 피드 | **IEX** (IEX 거래소 단일) |\n"
|
|
|
|
|
"| 지연 | **실시간** (지연 없음) |\n"
|
|
|
|
|
"| 거래량 커버리지 | 미국 전체 시장의 약 **2~5%** |\n"
|
|
|
|
|
"| DB 저장 | **없음** — 매 요청 Alpaca 직접 호출 |\n"
|
|
|
|
|
"| 캐시 | Redis **5분 TTL** |\n\n"
|
|
|
|
|
"멀티 종목이 필요하면 → `GET /api/v1/alpaca/intraday/today` (오늘) 또는 "
|
|
|
|
|
"`GET /api/v1/alpaca/intraday` (과거, SIP)\n\n"
|
|
|
|
|
"- Requires `ALPACA_API_KEY` / `ALPACA_SECRET_KEY`"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
@with_cache(namespace="alpaca:intraday", ttl=300, key_params=["ticker", "interval", "start_date", "end_date"])
|
|
|
|
|
async def get_alpaca_intraday(
|
|
|
|
|
@ -482,11 +506,18 @@ def _parse_snapshot(ticker: str, raw: dict) -> AlpacaSnapshotResponse:
|
|
|
|
|
@router.get(
|
|
|
|
|
"/snapshot/{ticker}",
|
|
|
|
|
response_model=AlpacaSnapshotResponse,
|
|
|
|
|
summary="Real-time snapshot for a single ticker",
|
|
|
|
|
summary="Real-time snapshot for a single ticker (IEX feed)",
|
|
|
|
|
description=(
|
|
|
|
|
"Returns the latest trade price, bid/ask, today's OHLCV, and change vs previous close "
|
|
|
|
|
"using Alpaca's `/v2/stocks/{symbol}/snapshot` endpoint.\n\n"
|
|
|
|
|
"**캐시 없음** — 매 요청마다 Alpaca API를 직접 호출."
|
|
|
|
|
"단일 종목의 실시간 스냅샷을 반환합니다. 최신 체결가, bid/ask, 당일 OHLCV, 전일 대비 변동률 포함.\n\n"
|
|
|
|
|
"**데이터 소스: IEX 피드 (무료 플랜 강제)**\n\n"
|
|
|
|
|
"| 항목 | 내용 |\n"
|
|
|
|
|
"|------|------|\n"
|
|
|
|
|
"| 피드 | **IEX** — 무료 플랜에서 snapshot은 SIP 불가 |\n"
|
|
|
|
|
"| 지연 | **실시간** (지연 없음) |\n"
|
|
|
|
|
"| 거래량 | IEX 기준 (실제의 2~5%) |\n"
|
|
|
|
|
"| High/Low | IEX 기준 (실제보다 range 좁을 수 있음) |\n"
|
|
|
|
|
"| 캐시 | **없음** — 매 요청마다 Alpaca 직접 호출 |\n\n"
|
|
|
|
|
"- Requires `ALPACA_API_KEY` / `ALPACA_SECRET_KEY`"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
async def get_snapshot(ticker: str):
|
|
|
|
|
@ -505,11 +536,18 @@ async def get_snapshot(ticker: str):
|
|
|
|
|
@router.get(
|
|
|
|
|
"/snapshot",
|
|
|
|
|
response_model=AlpacaMultiSnapshotResponse,
|
|
|
|
|
summary="Real-time snapshots for multiple tickers",
|
|
|
|
|
summary="Real-time snapshots for multiple tickers (IEX feed)",
|
|
|
|
|
description=(
|
|
|
|
|
"Returns snapshots for up to 100 tickers in a single request.\n\n"
|
|
|
|
|
"멀티 종목의 실시간 스냅샷을 한 번의 요청으로 반환합니다.\n\n"
|
|
|
|
|
"**데이터 소스: IEX 피드 (무료 플랜 강제)**\n\n"
|
|
|
|
|
"| 항목 | 내용 |\n"
|
|
|
|
|
"|------|------|\n"
|
|
|
|
|
"| 피드 | **IEX** — 무료 플랜에서 snapshot은 SIP 불가 |\n"
|
|
|
|
|
"| 지연 | **실시간** (지연 없음) |\n"
|
|
|
|
|
"| 거래량 | IEX 기준 (실제의 2~5%) |\n"
|
|
|
|
|
"| 캐시 | **없음** — 매 요청마다 Alpaca 직접 호출 |\n\n"
|
|
|
|
|
"**Usage**: `?tickers=AAPL,MSFT,NVDA`\n\n"
|
|
|
|
|
"**캐시 없음** — 매 요청마다 Alpaca API를 직접 호출."
|
|
|
|
|
"- Requires `ALPACA_API_KEY` / `ALPACA_SECRET_KEY`"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
async def get_snapshots(
|
|
|
|
|
|