Files
openbb-invest-api/congress_service.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

69 lines
1.8 KiB
Python

"""Congress trading data: member trades and bill search."""
import asyncio
import logging
from typing import Any
from openbb import obb
from obb_utils import to_list
logger = logging.getLogger(__name__)
async def _try_obb_call(fn, *args, **kwargs) -> list[dict[str, Any]] | None:
"""Attempt a single OBB call and return to_list result, or None on failure."""
try:
result = await asyncio.to_thread(fn, *args, **kwargs)
return to_list(result)
except Exception as exc:
logger.debug("OBB call failed: %s", exc)
return None
def _get_congress_fn():
"""Resolve the congress trading OBB function safely."""
try:
return obb.regulators.government_us.congress_trading
except AttributeError:
logger.debug("obb.regulators.government_us.congress_trading not available")
return None
async def get_congress_trades() -> list[dict[str, Any]]:
"""Get recent US congress member stock trades.
Returns an empty list if the data provider is unavailable.
"""
fn = _get_congress_fn()
if fn is None:
return []
providers = ["quiverquant", "fmp"]
for provider in providers:
data = await _try_obb_call(fn, provider=provider)
if data is not None:
return data
logger.warning("All congress trades providers failed")
return []
async def search_congress_bills(query: str) -> list[dict[str, Any]]:
"""Search US congress bills by keyword.
Returns an empty list if the data provider is unavailable.
"""
fn = _get_congress_fn()
if fn is None:
return []
providers = ["quiverquant", "fmp"]
for provider in providers:
data = await _try_obb_call(fn, query, provider=provider)
if data is not None:
return data
logger.warning("All congress bills providers failed for query: %s", query)
return []