""" Main FastAPI application """ import os from contextlib import asynccontextmanager from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse, HTMLResponse from app.core.config import settings from app.api.v1.api import api_router from app.core.database import engine, Base from app.middleware.error_logger import ErrorLoggingMiddleware from app.models import error_log, request_log, fred_data, filing, finra_short_volume, alpaca_price # Import to register models from app.models import overlay_registry, overlay_raw_event, overlay_feature # Overlay models # Create database tables @asynccontextmanager async def lifespan(app: FastAPI): # Startup - ensure tables exist async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) # Start overlay batch scheduler (graceful no-op if apscheduler not installed) try: from app.services.overlay.scheduler import start_scheduler start_scheduler() except Exception: pass yield # Shutdown try: from app.services.overlay.scheduler import stop_scheduler stop_scheduler() except Exception: pass await engine.dispose() # Create FastAPI app app = FastAPI( title=settings.APP_NAME, version=settings.APP_VERSION, openapi_url=f"{settings.API_PREFIX}/openapi.json", docs_url=f"{settings.API_PREFIX}/docs", redoc_url=f"{settings.API_PREFIX}/redoc", lifespan=lifespan ) # Add error logging middleware app.add_middleware(ErrorLoggingMiddleware) # Set up CORS - use configured origins if available, otherwise allow all cors_origins = [str(o) for o in settings.BACKEND_CORS_ORIGINS] if settings.BACKEND_CORS_ORIGINS else ["*"] app.add_middleware( CORSMiddleware, allow_origins=cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include API router app.include_router(api_router, prefix=settings.API_PREFIX) # Root documentation endpoint @app.get("/", response_class=HTMLResponse, include_in_schema=False) async def root_documentation(): """ Display comprehensive API documentation at root path """ try: # Simple working version simple_html = f"""
Comprehensive Investment Data Analysis API
Base URL: http://localhost:18001/api/v1
GET /health - API health statusGET /health/detailed - Detailed system healthPOST /financial/data - Get comprehensive financial dataGET /financial/data/{{ticker}} - Simple financial dataPOST /financial/data/bulk - Bulk financial dataPOST /price/data - Get historical price data (OHLCV)GET /price/data/{{ticker}} - Simple price dataPOST /price/data/bulk - Bulk price dataGET /price/quote/{{ticker}} - Latest quote (regular/pre/post market)GET /price/intraday/{{ticker}} - Intraday candles (interval, period)GET /price/today/{{ticker}} - Today's OHLC (daily or 1m aggregate)GET /stocks/trending - Trending stocks with intelligent parameter coordination (n=500 default)GET /stocks/most-active - Most actively traded stocksGET /stocks/52-week-gainers - Top 52-week gaining stocksGET /fred/proxy/{{endpoint}} - Universal FRED API proxy with cachingGET /fred/endpoints - List all supported FRED API endpointsGET /fred/stats/usage - API usage statistics and monitoringGET /news/{{ticker}} - Complete news and social media dataGET /news/{{ticker}}/news-only - News articles only (faster)GET /news/{{ticker}}/social-only - Social media posts onlyGET /filings/search/{{ticker}} - Search SEC filings (8-K, 6-K, 20-F, 40-F, 10-K, 10-Q)GET /filings/documents/{{accession_number}} - List all documents in a filingGET /filings/exhibit/{{accession_number}} - Extract exhibit content (e.g., EX-99.1 press releases)GET /alpaca/status - Alpaca connection status and key validityGET /alpaca/bars/{{ticker}} - Fetch bars directly from Alpaca (raw, no DB)GET /finra/short-volume/{{symbol}} - Short sale volume data for a symbolGET /finra/short-ratio/{{symbol}} - Short ratio history (aggregated)POST /finra/admin/ingest - Manually ingest FINRA data for a date/rangeGET /etf/holdings/{{ticker}} - ETF holdings at date or most recentPOST /etf/admin/refresh-maps - Refresh CUSIP/CIK mapsGET /screener/stocks - Filter stocks by market cap, volume, price, P/E, sector, exchangeGET /screener/fields - Available filter options, sectors, sort fields (metadata)GET /overlay/{{symbol}} - Overlay score + features + source details (0~1 score, band, hints)GET /overlay/bulk?symbols=AAPL,TSLA,NVDA - Bulk overlay scores (max 50 symbols)GET /overlay/top-movers - Symbols with highest overlay scores in last 24hGET /overlay/{{symbol}}/headlines - Recent news headlines matched to symbolGET /overlay/{{symbol}}/youtube - YouTube video mentions from investing channelsGET /overlay/{{symbol}}/wiki - Wikipedia pageview time seriesGET /overlay/{{symbol}}/crowding - FINRA short-sale crowding metricsGET /overlay/{{symbol}}/trends - Google Trends interest data (if enabled)GET /overlay/{{symbol}}/history - Historical overlay scores (backtesting)GET /overlay/admin/health - Data source health and last collection statusPOST /overlay/admin/trigger-pipeline - Manually trigger full data collection + scoringGET /overlay/admin/job-log - Pipeline job execution logcurl -X POST "http://localhost:18001/api/v1/financial/data" \\
-H "Content-Type: application/json" \\
-d '{{"ticker": "AAPL", "period": "1y", "include_metrics": true}}'
# Get trending stocks (default: 500 total stocks with intelligent coordination)
curl "http://localhost:18001/api/v1/stocks/trending"
# Custom total count
curl "http://localhost:18001/api/v1/stocks/trending?n=200"
# Get GDP series information
curl "http://localhost:18001/api/v1/fred/proxy/series?series_id=GDP"
# Get unemployment rate observations
curl "http://localhost:18001/api/v1/fred/proxy/series/observations?series_id=UNRATE&limit=12"
curl "http://localhost:18001/api/v1/news/AAPL?days_back=7&max_articles=20"
# Quote (latest regular/pre/post)
curl "http://localhost:18001/api/v1/price/quote/AAPL?use_prepost=true"
# Intraday 1m candles for 1 day
curl "http://localhost:18001/api/v1/price/intraday/AAPL?interval=1m&period=1d"
# Today's OHLC (daily if available; otherwise 1m aggregate)
curl "http://localhost:18001/api/v1/price/today/AAPL"
# Search AAPL 8-K filings (earnings announcements, material events)
curl "http://localhost:18001/api/v1/filings/search/AAPL?form_type=8-K&limit=5"
# Search foreign issuer filings
curl "http://localhost:18001/api/v1/filings/search/TSM?form_type=20-F"
curl "http://localhost:18001/api/v1/filings/search/SAP?form_type=6-K"
# List all documents in a filing
curl "http://localhost:18001/api/v1/filings/documents/0000320193-26-000005"
# Extract press release (Exhibit 99.1) from an 8-K
curl "http://localhost:18001/api/v1/filings/exhibit/0000320193-26-000005?exhibit_type=EX-99.1"
curl "http://localhost:18001/api/v1/etf/holdings/QQQ"
from stock_oracle_client import StockOracleClient
client = StockOracleClient("http://localhost:18001")
# Check health
health = client.get_health()
print("API Status:", health["status"])
# Get financial data
data = client.get_financial_data("AAPL", period="1y")
# Get news data (NEW!)
news = client.get_news_social_data("AAPL", days_back=7)
GET /api/v1/overlay/AAPL
{{
"symbol": "AAPL",
"as_of_ts": "2026-03-13T20:30:00Z",
"overlay_score": 0.72, // 0~1 (higher = more retail attention)
"overlay_confidence": 0.80, // fraction of sources with data
"overlay_band": "supportive", // silent / tepid / supportive / loud / frenzied
"hold_extension_hint": "neutral", // extend / neutral / trim
"add_on_eligibility": false,
"features": {{
"headline_burst_z": 1.2, // z-score vs 30-day window
"youtube_influence_z": 0.8,
"wiki_attention_z": null,
"theme_heat_z": null,
"crowding_stress_z": -0.3
}},
"source_presence": {{
"yahoo": true, "youtube": true,
"wikimedia": false, "google_trends": false, "finra": true
}},
"source_details": {{
"yahoo": {{"headline_count_6h": 5, "headline_count_24h": 12, "publisher_breadth_24h": 4}},
"finra": {{"short_volume_ratio": 0.42, "short_volume_spike_zscore": -0.3}}
}}
}}
# Check Alpaca connection status
curl "http://localhost:18001/api/v1/alpaca/status"
# Get daily bars from Alpaca
curl "http://localhost:18001/api/v1/alpaca/bars/AAPL?interval=1d&start_date=2025-01-01&end_date=2025-01-31"
# Ingest FINRA data for a specific date
curl -X POST "http://localhost:18001/api/v1/finra/admin/ingest?date=2025-03-10"
# Get short volume for AAPL (last 30 days)
curl "http://localhost:18001/api/v1/finra/short-volume/AAPL?days=30"
# Get short ratio history
curl "http://localhost:18001/api/v1/finra/short-ratio/AAPL?days=60"
# Small/mid-cap stocks on NYSE+NASDAQ with avg volume > 500K, sorted by market cap
curl "http://localhost:18001/api/v1/screener/stocks?market_cap_min=500000000&market_cap_max=10000000000&exchange=NYSE,NASDAQ&min_avg_volume=500000&exclude_types=ETF,FUND"
# Technology sector only
curl "http://localhost:18001/api/v1/screener/stocks?market_cap_min=500000000&exchange=NASDAQ§or=Technology&page=1&page_size=50"
# Available filter metadata
curl "http://localhost:18001/api/v1/screener/fields"
# Overlay score for a single symbol
curl "http://localhost:18001/api/v1/overlay/AAPL"
# Bulk scores (comma-separated, max 50)
curl "http://localhost:18001/api/v1/overlay/bulk?symbols=AAPL,TSLA,NVDA,AMD,META"
# Top movers by overlay score (last 24h)
curl "http://localhost:18001/api/v1/overlay/top-movers?limit=10"
# Recent headlines matched to AAPL
curl "http://localhost:18001/api/v1/overlay/AAPL/headlines?hours=24"
# Wikipedia pageview trend (last 30 days)
curl "http://localhost:18001/api/v1/overlay/AAPL/wiki?days=30"
# FINRA crowding metrics
curl "http://localhost:18001/api/v1/overlay/AAPL/crowding"
# Historical overlay scores (backtesting)
curl "http://localhost:18001/api/v1/overlay/AAPL/history?days=90"
# Manually trigger full pipeline
curl -X POST "http://localhost:18001/api/v1/overlay/admin/trigger-pipeline"