""" 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 # Import to register 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) yield # Shutdown 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""" Stock Oracle API Documentation

🔮 Stock Oracle API Documentation

Comprehensive Investment Data Analysis API

🚀 Quick Start

Base URL: http://localhost:18001/api/v1

🎯 Main Endpoints

Health & System

Financial Data

Price Data

Stock Market Data NEW

FRED Economic Data NEW

News & Social Media NEW

ETF Holdings

📊 Example Requests

Financial Data

curl -X POST "http://localhost:18001/api/v1/financial/data" \\
  -H "Content-Type: application/json" \\
  -d '{{"ticker": "AAPL", "period": "1y", "include_metrics": true}}'

Trending Stocks NEW

# 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"

FRED Economic Data NEW

# 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"

News & Social Data NEW

curl "http://localhost:18001/api/v1/news/AAPL?days_back=7&max_articles=20"

Price - Quote/Intraday/Today NEW

# 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"

ETF Holdings

curl "http://localhost:18001/api/v1/etf/holdings/QQQ"

🐍 Python Client

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)

📈 Key Features

🔧 Data Sources

""" return HTMLResponse(content=simple_html) except Exception as e: # Fallback to Swagger UI if anything goes wrong return RedirectResponse(url=f"{settings.API_PREFIX}/docs") # Additional metadata for OpenAPI app.openapi_tags = [ { "name": "health", "description": "Health check endpoints" }, { "name": "financial", "description": "Financial data retrieval endpoints" }, { "name": "price", "description": "Price data endpoints (OHLCV)" }, { "name": "news", "description": "News and social media endpoints" }, { "name": "metadata", "description": "Data catalog and metadata endpoints" }, { "name": "etf", "description": "ETF holdings endpoints" }, { "name": "admin", "description": "Administrative endpoints (migration, etc.)" } ] if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host="0.0.0.0", port=settings.API_PORT, reload=settings.DEBUG )