added stock split support
Deploy / lint (push) Successful in 6s
Deploy / test (push) Successful in 30s
Deploy / deploy (push) Successful in 21s

This commit is contained in:
2026-03-07 16:50:18 +01:00
parent 03ea60e067
commit d331f551e3
2 changed files with 27 additions and 0 deletions
+2
View File
@@ -9,6 +9,7 @@ from datetime import date
from alpaca.data.historical import StockHistoricalDataClient from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame from alpaca.data.timeframe import TimeFrame
from alpaca.data.enums import Adjustment
from app.exceptions import ProviderError, RateLimitError from app.exceptions import ProviderError, RateLimitError
from app.providers.protocol import OHLCVData from app.providers.protocol import OHLCVData
@@ -34,6 +35,7 @@ class AlpacaOHLCVProvider:
timeframe=TimeFrame.Day, timeframe=TimeFrame.Day,
start=start_date, start=start_date,
end=end_date, end=end_date,
adjustment=Adjustment.SPLIT,
) )
# alpaca-py's client is synchronous — run in a thread # alpaca-py's client is synchronous — run in a thread
+25
View File
@@ -11,11 +11,15 @@ import logging
from datetime import date from datetime import date
from fastapi import APIRouter, Depends, Query from fastapi import APIRouter, Depends, Query
from sqlalchemy import delete, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings from app.config import settings
from app.dependencies import get_db, require_access from app.dependencies import get_db, require_access
from app.exceptions import ProviderError from app.exceptions import ProviderError
from app.models.ohlcv import OHLCVRecord
from app.models.settings import IngestionProgress
from app.models.ticker import Ticker
from app.models.user import User from app.models.user import User
from app.providers.alpaca import AlpacaOHLCVProvider from app.providers.alpaca import AlpacaOHLCVProvider
from app.providers.fundamentals_chain import build_fundamental_provider_chain from app.providers.fundamentals_chain import build_fundamental_provider_chain
@@ -47,6 +51,7 @@ async def fetch_symbol(
symbol: str, symbol: str,
start_date: date | None = Query(None, description="Start date (YYYY-MM-DD)"), start_date: date | None = Query(None, description="Start date (YYYY-MM-DD)"),
end_date: date | None = Query(None, description="End date (YYYY-MM-DD)"), end_date: date | None = Query(None, description="End date (YYYY-MM-DD)"),
force_refetch: bool = Query(False, description="Delete existing OHLCV data and re-fetch split-adjusted history"),
_user: User = Depends(require_access), _user: User = Depends(require_access),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
): ):
@@ -58,6 +63,26 @@ async def fetch_symbol(
symbol_upper = symbol.strip().upper() symbol_upper = symbol.strip().upper()
sources: dict[str, dict] = {} sources: dict[str, dict] = {}
# If force_refetch is requested, clear old OHLCV and ingestion progress
# so the backfill logic pulls a full year of fresh split-adjusted data.
if force_refetch:
try:
result = await db.execute(
select(Ticker).where(Ticker.symbol == symbol_upper)
)
ticker_obj = result.scalar_one_or_none()
if ticker_obj:
await db.execute(
delete(OHLCVRecord).where(OHLCVRecord.ticker_id == ticker_obj.id)
)
await db.execute(
delete(IngestionProgress).where(IngestionProgress.ticker_id == ticker_obj.id)
)
await db.commit()
logger.info("force_refetch: cleared OHLCV and progress for %s", symbol_upper)
except Exception as exc:
logger.error("force_refetch cleanup failed for %s: %s", symbol_upper, exc)
# --- OHLCV --- # --- OHLCV ---
try: try:
provider = _get_provider() provider = _get_provider()