Files
openbb-invest-api/routes_regulators.py
Yaojia Wang 42ba359c48 feat: add portfolio optimization and congress tracking (TDD)
Portfolio optimization (3 endpoints):
- POST /portfolio/optimize - HRP optimal weights via scipy clustering
- POST /portfolio/correlation - pairwise correlation matrix
- POST /portfolio/risk-parity - inverse-volatility risk parity weights

Congress tracking (2 endpoints):
- GET /regulators/congress/trades - congress member stock trades
- GET /regulators/congress/bills?query= - search congress bills

Implementation:
- portfolio_service.py: HRP with scipy fallback to inverse-vol
- congress_service.py: multi-provider fallback pattern
- 51 new tests (14 portfolio unit, 20 portfolio route, 12 congress
  unit, 7 congress route)
- All 312 tests passing
2026-03-19 22:27:03 +01:00

72 lines
2.2 KiB
Python

"""Routes for regulatory data (CFTC, SEC, Congress)."""
from fastapi import APIRouter, Path, Query
from models import ApiResponse
from route_utils import safe, validate_symbol
import regulators_service
import congress_service
router = APIRouter(prefix="/api/v1/regulators")
@router.get("/cot", response_model=ApiResponse)
@safe
async def cot_report(symbol: str = Query(..., min_length=1, max_length=20)):
"""Commitment of Traders: commercial/speculator positions for futures."""
symbol = validate_symbol(symbol)
data = await regulators_service.get_cot(symbol)
return ApiResponse(data=data)
@router.get("/cot/search", response_model=ApiResponse)
@safe
async def cot_search(query: str = Query(..., min_length=1, max_length=100)):
"""Search COT report symbols."""
data = await regulators_service.cot_search(query)
return ApiResponse(data=data)
@router.get("/sec/litigation", response_model=ApiResponse)
@safe
async def sec_litigation():
"""SEC litigation releases RSS feed."""
data = await regulators_service.get_sec_litigation()
return ApiResponse(data=data)
@router.get("/sec/institutions", response_model=ApiResponse)
@safe
async def sec_institutions(query: str = Query(..., min_length=1, max_length=100)):
"""Search institutional investors filing with SEC."""
data = await regulators_service.search_institutions(query)
return ApiResponse(data=data)
@router.get("/sec/cik-map/{symbol}", response_model=ApiResponse)
@safe
async def sec_cik_map(symbol: str = Path(..., min_length=1, max_length=20)):
"""Map ticker symbol to SEC CIK number."""
symbol = validate_symbol(symbol)
data = await regulators_service.get_cik_map(symbol)
return ApiResponse(data=data)
# --- Congress Trading ---
@router.get("/congress/trades", response_model=ApiResponse)
@safe
async def congress_trades():
"""Recent US congress member stock trades."""
data = await congress_service.get_congress_trades()
return ApiResponse(data=data)
@router.get("/congress/bills", response_model=ApiResponse)
@safe
async def congress_bills(query: str = Query(..., min_length=1, max_length=200)):
"""Search US congress bills by keyword."""
data = await congress_service.search_congress_bills(query)
return ApiResponse(data=data)