feat: cockpit
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import math
|
||||
from fastapi import APIRouter, Query
|
||||
from services.database import (
|
||||
get_portfolio_exposure,
|
||||
@@ -11,6 +12,17 @@ from services.database import (
|
||||
router = APIRouter(prefix="/api/risk", tags=["risk"])
|
||||
|
||||
|
||||
def _sanitize(obj):
|
||||
"""Replace NaN/Inf with None recursively for JSON compliance."""
|
||||
if isinstance(obj, dict):
|
||||
return {k: _sanitize(v) for k, v in obj.items()}
|
||||
if isinstance(obj, list):
|
||||
return [_sanitize(v) for v in obj]
|
||||
if isinstance(obj, float) and (math.isnan(obj) or math.isinf(obj)):
|
||||
return None
|
||||
return obj
|
||||
|
||||
|
||||
@router.get("/exposure")
|
||||
def portfolio_exposure():
|
||||
"""Exposure by asset class + risk factor for open positions."""
|
||||
@@ -49,3 +61,10 @@ def kelly_sizing(
|
||||
def risk_dashboard():
|
||||
"""Full portfolio risk snapshot: concentration, diversification, expected drawdown, recommendation."""
|
||||
return get_risk_dashboard()
|
||||
|
||||
|
||||
@router.get("/radar")
|
||||
def risk_radar():
|
||||
"""5-axis risk radar (Concentration/Volatility/Correlation/Exposure/Drawdown) for the real portfolio."""
|
||||
from services.portfolio_risk import compute_real_portfolio_risk_radar
|
||||
return _sanitize(compute_real_portfolio_risk_radar())
|
||||
|
||||
Reference in New Issue
Block a user