feat: Phase 3 — Portfolio Risk Engine (Exposition, Clusters, Kelly, Risk Dashboard)

Sprint 3.1 — Vue Portefeuille Consolidée
- database.py: get_portfolio_exposure() — exposition par classe d'actif + facteur de risque
- database.py: get_pnl_timeline() — courbe P&L cumulé pour equity curve
- Alertes concentration automatiques (>40% par classe, >50% par facteur)
- _RISK_FACTOR_MAP: classification géopolitique/inflation/récession/liquidité/dollar

Sprint 3.2 — Risk Cluster Engine
- database.py: get_risk_clusters() — saturation par facteur + risk_prompt_context
- database.py: get_pattern_correlations() — matrice Pearson sur trades matures
- auto_cycle.py: injection du contexte risque dans le prompt de scoring (Step 3.5)
- ai_analyzer.py: paramètre risk_context dans score_patterns_with_context()
- Pénalisation automatique des patterns sur facteurs saturés dans le scoring GPT

Sprint 3.3 — Position Sizing Kelly Fractionnel
- database.py: compute_kelly_sizing() — f* = (p×G - (1-p))/G, Kelly ×33% par défaut
- Ajustement cluster: sizing ÷2 si facteur saturé
- Ajustement fiabilité: sizing ÷2 si win_rate historique <40% (≥5 trades)
- JournalDeBord.tsx: colonne "Kelly" avec KellyCell (% + €, ajustements signalés)
- routers/risk.py: GET /api/risk/kelly/{pattern_id}

Sprint 3.4 — Tableau de Bord Risque Global
- database.py: get_risk_dashboard() — HHI, score diversification, drawdown attendu, recommandation
- database.py: _build_risk_recommendation() — alerte Risk Committee automatique
- RiskDashboard.tsx: nouvelle page — jauges concentration, courbe P&L, corrélations, recommandation
- Dashboard.tsx: banner d'alerte concentration sur le Cockpit avec lien vers /risk
- routers/risk.py: GET /api/risk/exposure|timeline|clusters|correlations|dashboard
- App.tsx + Sidebar.tsx: route /risk + entrée menu Risk Dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-17 17:18:36 +02:00
parent f09c5b8ee7
commit e44c8799b9
11 changed files with 962 additions and 7 deletions

View File

@@ -629,3 +629,49 @@ export const useCalibration = (days = 365) =>
queryFn: () => api.get('/analytics/calibration', { params: { days } }).then(r => r.data),
staleTime: 10 * 60_000,
})
// ── Risk Engine (Phase 3) ─────────────────────────────────────────────────────
export const useRiskExposure = () =>
useQuery({
queryKey: ['risk-exposure'],
queryFn: () => api.get('/risk/exposure').then(r => r.data),
staleTime: 2 * 60_000,
})
export const usePnlTimeline = (days = 90) =>
useQuery({
queryKey: ['pnl-timeline', days],
queryFn: () => api.get('/risk/timeline', { params: { days } }).then(r => r.data),
staleTime: 5 * 60_000,
})
export const useRiskClusters = () =>
useQuery({
queryKey: ['risk-clusters'],
queryFn: () => api.get('/risk/clusters').then(r => r.data),
staleTime: 2 * 60_000,
})
export const usePatternCorrelations = () =>
useQuery({
queryKey: ['pattern-correlations'],
queryFn: () => api.get('/risk/correlations').then(r => r.data),
staleTime: 10 * 60_000,
})
export const useKellySizing = (patternId: string, capital = 10000) =>
useQuery({
queryKey: ['kelly', patternId, capital],
queryFn: () => api.get(`/risk/kelly/${encodeURIComponent(patternId)}`, { params: { capital } }).then(r => r.data),
enabled: !!patternId,
staleTime: 5 * 60_000,
})
export const useRiskDashboard = () =>
useQuery({
queryKey: ['risk-dashboard'],
queryFn: () => api.get('/risk/dashboard').then(r => r.data),
staleTime: 2 * 60_000,
refetchInterval: 5 * 60_000,
})