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
This commit is contained in:
Yaojia Wang
2026-03-19 22:27:03 +01:00
parent 27b131492f
commit 42ba359c48
9 changed files with 1140 additions and 1 deletions

View File

@@ -1,10 +1,11 @@
"""Routes for regulatory data (CFTC, SEC)."""
"""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")
@@ -49,3 +50,22 @@ async def sec_cik_map(symbol: str = Path(..., min_length=1, max_length=20)):
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)