From afd133e027e9b1e54997195b0e735991f4521a55 Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Tue, 17 Mar 2026 11:52:26 -0700 Subject: [PATCH] =?UTF-8?q?refactor(main):=20=EB=A3=A8=ED=8A=B8=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20OpenAPI=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A4=EB=A7=88=EC=97=90=EC=84=9C=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 하드코딩된 330줄 HTML을 제거하고 request.app.openapi()에서 동적으로 엔드포인트 목록을 렌더링하도록 변경. 새 라우터 추가 시 / 페이지를 별도로 수정할 필요 없음. Co-Authored-By: Claude Sonnet 4.6 --- app/main.py | 453 +++++++++++++--------------------------------------- 1 file changed, 111 insertions(+), 342 deletions(-) diff --git a/app/main.py b/app/main.py index a356070..8b2c38a 100644 --- a/app/main.py +++ b/app/main.py @@ -4,7 +4,7 @@ Main FastAPI application import os from contextlib import asynccontextmanager -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse, HTMLResponse @@ -62,350 +62,119 @@ app.add_middleware( # Include API router app.include_router(api_router, prefix=settings.API_PREFIX) -# Root documentation endpoint +# Root documentation endpoint — auto-generated from OpenAPI schema @app.get("/", response_class=HTMLResponse, include_in_schema=False) -async def root_documentation(): - """ - Display comprehensive API documentation at root path - """ +async def root_documentation(request: Request): try: - # Simple working version - simple_html = f""" - - - - - - Stock Oracle API Documentation - - - -

🔮 Stock Oracle API Documentation

-

Comprehensive Investment Data Analysis API

- - + schema = request.app.openapi() + paths = schema.get("paths", {}) + api_prefix = settings.API_PREFIX + + # Collect all tags defined in schema (preserves order) + tag_order = [t["name"] for t in schema.get("tags", [])] + + # Group routes by first tag + from collections import defaultdict + tag_routes: dict = defaultdict(list) + untagged: list = [] + for path, methods in paths.items(): + for method, op in methods.items(): + if method.upper() not in ("GET", "POST", "PUT", "DELETE", "PATCH"): + continue + tags = op.get("tags", []) + entry = { + "method": method.upper(), + "path": path, + "summary": op.get("summary", ""), + "deprecated": op.get("deprecated", False), + } + if tags: + tag_routes[tags[0]].append(entry) + else: + untagged.append(entry) + + # Build tag sections — respect schema tag order, then alphabetical remainder + all_tags = tag_order + sorted(t for t in tag_routes if t not in tag_order) + if untagged: + all_tags.append("other") + tag_routes["other"] = untagged + + method_colors = { + "GET": "#61affe", + "POST": "#49cc90", + "PUT": "#fca130", + "DELETE": "#f93e3e", + "PATCH": "#50e3c2", + } + + sections_html = "" + for tag in all_tags: + routes = tag_routes.get(tag, []) + if not routes: + continue + rows = "" + for r in routes: + color = method_colors.get(r["method"], "#999") + deprecated = " style='opacity:0.5;text-decoration:line-through'" if r["deprecated"] else "" + display_path = r["path"].removeprefix(api_prefix) + rows += ( + f"" + f"{r['method']}" + f"{display_path}" + f"{r['summary']}" + f"" + ) + sections_html += f"

{tag}

{rows}
" + + title = schema.get("info", {}).get("title", "API") + version = schema.get("info", {}).get("version", "") + total = sum(len(v) for v in tag_routes.values()) + + html = f""" + + + + + {title} + + + +

🔮 {title}

+ +

v{version}  ·  Base URL: {api_prefix}  ·  {total} endpoints

+ {sections_html} + + +""" + + return HTMLResponse(content=html) -

🚀 Quick Start

-

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

- -

🎯 Main Endpoints

- -

Health & System

-
    -
  • GET /health - API health status
  • -
  • GET /health/detailed - Detailed system health
  • -
- -

Financial Data

-
    -
  • POST /financial/data - Get comprehensive financial data
  • -
  • GET /financial/data/{{ticker}} - Simple financial data
  • -
  • POST /financial/data/bulk - Bulk financial data
  • -
- -

Price Data

-
    -
  • POST /price/data - Get historical price data (OHLCV)
  • -
  • GET /price/data/{{ticker}} - Simple price data
  • -
  • POST /price/data/bulk - Bulk price data
  • -
  • GET /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)
  • -
- -

Stock Market Data NEW

-
    -
  • GET /stocks/trending - Trending stocks with intelligent parameter coordination (n=500 default)
  • -
  • GET /stocks/most-active - Most actively traded stocks
  • -
  • GET /stocks/52-week-gainers - Top 52-week gaining stocks
  • -
  • GET /stocks/index/{{index_name}} - S&P 500 / Nasdaq 100 constituents from Wikipedia (24h cache) — sp500 | nasdaq100
  • -
- -

FRED Economic Data NEW

-
    -
  • GET /fred/proxy/{{endpoint}} - Universal FRED API proxy with caching
  • -
  • GET /fred/endpoints - List all supported FRED API endpoints
  • -
  • GET /fred/stats/usage - API usage statistics and monitoring
  • -
- -

News & Social Media NEW

-
    -
  • GET /news/{{ticker}} - Complete news and social media data
  • -
  • GET /news/{{ticker}}/news-only - News articles only (faster)
  • -
  • GET /news/{{ticker}}/social-only - Social media posts only
  • -
- -

SEC Filings NEW

-
    -
  • GET /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 filing
  • -
  • GET /filings/exhibit/{{accession_number}} - Extract exhibit content (e.g., EX-99.1 press releases)
  • -
- -

Alpaca Market Data NEW

-
    -
  • GET /alpaca/status - Alpaca connection status and key validity
  • -
  • GET /alpaca/bars/{{ticker}} - Fetch bars directly from Alpaca (raw, no DB)
  • -
- -

FINRA Short Volume NEW

-
    -
  • GET /finra/short-volume/{{symbol}} - Short sale volume data for a symbol
  • -
  • GET /finra/short-ratio/{{symbol}} - Short ratio history (aggregated)
  • -
  • POST /finra/admin/ingest - Manually ingest FINRA data for a date/range
  • -
- -

ETF Holdings

-
    -
  • GET /etf/holdings/{{ticker}} - ETF holdings at date or most recent
  • -
  • POST /etf/admin/refresh-maps - Refresh CUSIP/CIK maps
  • -
- -

Stock Screener NEW

-
    -
  • GET /screener/stocks - Filter stocks by market cap, volume, price, P/E, sector, exchange
  • -
  • GET /screener/fields - Available filter options, sectors, sort fields (metadata)
  • -
- -

Attention Overlay NEW

-
    -
  • 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 24h
  • -
  • GET /overlay/{{symbol}}/headlines - Recent news headlines matched to symbol
  • -
  • GET /overlay/{{symbol}}/youtube - YouTube video mentions from investing channels
  • -
  • GET /overlay/{{symbol}}/wiki - Wikipedia pageview time series
  • -
  • GET /overlay/{{symbol}}/crowding - FINRA short-sale crowding metrics
  • -
  • GET /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 status
  • -
  • POST /overlay/admin/trigger-pipeline - Manually trigger full data collection + scoring
  • -
  • GET /overlay/admin/job-log - Pipeline job execution log
  • -
- -

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

Index Constituents NEW

-
# S&P 500 constituents (~503 stocks, cached 24h)
-curl "http://localhost:18001/api/v1/stocks/index/sp500"
-
-# Nasdaq 100 constituents (~101 stocks, cached 24h)
-curl "http://localhost:18001/api/v1/stocks/index/nasdaq100"
-
-# Force refresh (bypass cache)
-curl "http://localhost:18001/api/v1/stocks/index/sp500?force_refresh=true"
- -

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

SEC Filings NEW

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

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

-
    -
  • SEC EDGAR Data - Official company filings (10-K, 10-Q) with XBRL financial data
  • -
  • SEC Filings Search - Index and search 8-K, 6-K, 20-F, 40-F filings with exhibit extraction
  • -
  • Real-time News - Yahoo Finance + NewsAPI integration
  • -
  • Social Sentiment - Reddit discussions and sentiment analysis
  • -
  • ETF Holdings - Complete ETF portfolio analysis via N-PORT
  • -
  • Price Data - Historical OHLCV data from Yahoo Finance
  • -
  • Investment Metrics - P/E, ROE, debt ratios, growth metrics
  • -
  • Attention Overlay - Multi-source retail interest signal (news burst, Wikipedia views, YouTube mentions, FINRA crowding)
  • -
- -

Attention Overlay Response Example NEW

-
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}}
-  }}
-}}
- -

Alpaca Market Data NEW

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

FINRA Short Volume NEW

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

Stock Screener NEW

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

Attention Overlay NEW

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

🔧 Data Sources

-
    -
  • SEC EDGAR - Official company filings and ETF holdings
  • -
  • Yahoo Finance - Price data, financial news, and RSS headlines
  • -
  • Alpaca - Market price data (OHLCV) with optional API key
  • -
  • FINRA - RegSHO short sale volume data (public CDN, no API key)
  • -
  • Wikimedia - Wikipedia daily page view counts per company
  • -
  • YouTube Data API - Video mentions from curated investing channels
  • -
  • Google Trends - Theme interest data (experimental, opt-in)
  • -
  • NewsAPI - Professional news aggregation
  • -
  • Reddit API - Social media sentiment from investing subreddits
  • -
- - - - - """ - - return HTMLResponse(content=simple_html) - - except Exception as e: - # Fallback to Swagger UI if anything goes wrong + except Exception: return RedirectResponse(url=f"{settings.API_PREFIX}/docs") # Additional metadata for OpenAPI