diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
index f7776aa..e96e4b9 100644
--- a/frontend/src/pages/Dashboard.tsx
+++ b/frontend/src/pages/Dashboard.tsx
@@ -3,7 +3,7 @@ import {
useGeoRiskScore, useAllQuotes,
useCalendar, usePortfolioSummary, useLastScores, useAllPatterns, useMacroRegime,
useTradeMtm, useRiskDashboard, useGeoNews,
- useSimPortfolioRisk, useCycleStatus, useKnowledgeState,
+ useSimPortfolioRisk, useCycleStatus,
} from '../hooks/useApi'
import { Clock, Globe, ShieldAlert, ArrowUpRight, Brain, Newspaper } from 'lucide-react'
import { Link } from 'react-router-dom'
@@ -86,7 +86,6 @@ export default function Dashboard() {
const { data: riskDashboard } = useRiskDashboard()
const { data: simRisk } = useSimPortfolioRisk()
const { data: cycleStatusData } = useCycleStatus()
- const { data: knowledgeState } = useKnowledgeState()
const { data: geoNews } = useGeoNews()
const [pnlView, setPnlView] = useState<'simulated' | 'portfolio'>(() =>
@@ -262,9 +261,13 @@ export default function Dashboard() {
? Math.max(rawScore ?? 0, ...(sp.trade_rankings ?? []).map((r: any) =>
Math.max(0, Math.min(100, (rawScore ?? 0) + (r.score_delta ?? 0)))))
: null
+ const addedDate = p.created_at ? p.created_at.slice(0, 10) : null
return (
-
-
{p.name}
+
+
+ {p.name}
+ {addedDate && {addedDate}}
+
{bestEff !== null ? (
{bestEff}
) : (
@@ -571,29 +574,44 @@ export default function Dashboard() {
{/* ── Command Center: Intelligence & Contexte ── */}
- {/* Super Contexte IA */}
+ {/* Top 5 trades loggés */}
{(() => {
- const state = (knowledgeState as any)?.state
- const synthesis = state?.synthesis
- const insights = (synthesis?.regime_insights?.length ?? 0)
- + (synthesis?.pattern_insights?.length ?? 0)
- + (synthesis?.recurring_mistakes?.length ?? 0)
- const priority = synthesis?.strategic_priorities?.[0]
- const excerpt = typeof priority === 'string' ? priority
- : typeof state?.narrative === 'string' ? state.narrative.slice(0, 90)
- : null
+ const top5 = [...mtmTrades]
+ .sort((a, b) => (b.pnl_pct ?? -999) - (a.pnl_pct ?? -999))
+ .slice(0, 5)
return (
-
+
-
🧠 Super Contexte
+
🏆 Top Trades
-
- {state ? `${insights} insights actifs` : 'Aucune synthèse'}
-
-
- {excerpt ?? 'Lancer une synthèse dans Super Contexte'}
-
+ {top5.length > 0 ? (
+
+ {top5.map((t: any, i: number) => {
+ const pnl: number | null = t.pnl_pct ?? null
+ const isBear = t.strategy?.toLowerCase().includes('put') || t.strategy?.toLowerCase().includes('bear')
+ const entryDate = t.entry_date ? t.entry_date.slice(0, 10) : null
+ return (
+
+ {i + 1}
+ {isBear ? '🐻' : '🐂'}
+ {t.underlying ?? '—'}
+ {t.strategy ?? ''}
+ {entryDate && {entryDate}}
+ {pnl !== null ? (
+ = 0 ? 'text-emerald-400' : 'text-red-400')}>
+ {pnl >= 0 ? '+' : ''}{pnl.toFixed(1)}%
+
+ ) : (
+ —
+ )}
+
+ )
+ })}
+
+ ) : (
+
Aucun trade loggé
+ )}
)
})()}
diff --git a/frontend/src/pages/GeoRadar.tsx b/frontend/src/pages/GeoRadar.tsx
index d599f76..327e015 100644
--- a/frontend/src/pages/GeoRadar.tsx
+++ b/frontend/src/pages/GeoRadar.tsx
@@ -252,17 +252,49 @@ function PatternRelevanceCard({ p }: { p: any }) {
)
}
+type SortMode = 'impact_desc' | 'impact_asc' | 'date_desc' | 'date_asc'
+type DateRange = 'all' | 'today' | '7d' | '30d'
+
+const DATE_RANGE_LABELS: Record
= {
+ all: 'Toutes', today: "Aujourd'hui", '7d': '7 jours', '30d': '30 jours',
+}
+const SORT_LABELS: Record = {
+ impact_desc: 'Impact ↓', impact_asc: 'Impact ↑', date_desc: 'Récentes ↓', date_asc: 'Anciennes ↑',
+}
+
+function isWithinRange(dateStr: string, range: DateRange): boolean {
+ if (range === 'all') return true
+ const d = new Date(dateStr)
+ const now = new Date()
+ const diffMs = now.getTime() - d.getTime()
+ if (range === 'today') return diffMs < 86_400_000
+ if (range === '7d') return diffMs < 7 * 86_400_000
+ if (range === '30d') return diffMs < 30 * 86_400_000
+ return true
+}
+
export default function GeoRadar() {
const { data: news, isLoading } = useGeoNews()
const { data: riskScore } = useGeoRiskScore()
const [filterCat, setFilterCat] = useState('all')
+ const [sortMode, setSortMode] = useState('impact_desc')
+ const [dateRange, setDateRange] = useState('all')
const [tab, setTab] = useState<'news' | 'patterns'>('news')
const [days, setDays] = useState(2)
const { data: patternRelevance, isLoading: relLoading } = usePatternRelevance(days)
const categories = ['all', ...Array.from(new Set(news?.map(n => n.category) ?? []))]
- const filtered = filterCat === 'all' ? news : news?.filter(n => n.category === filterCat)
+
+ const filtered = (news ?? [])
+ .filter(n => filterCat === 'all' || n.category === filterCat)
+ .filter(n => isWithinRange(n.date, dateRange))
+ .sort((a, b) => {
+ if (sortMode === 'impact_desc') return b.impact_score - a.impact_score
+ if (sortMode === 'impact_asc') return a.impact_score - b.impact_score
+ if (sortMode === 'date_desc') return new Date(b.date).getTime() - new Date(a.date).getTime()
+ return new Date(a.date).getTime() - new Date(b.date).getTime()
+ })
const patternsWithNews = (patternRelevance ?? []).filter((p: any) => p.matching_news?.length > 0).length
const totalPatterns = patternRelevance?.length ?? 0
@@ -333,25 +365,63 @@ export default function GeoRadar() {
{/* News tab */}
{tab === 'news' && (
<>
-
- {categories.slice(0, 8).map(cat => (
-
- ))}
+ {/* Filters row */}
+
+ {/* Category filter */}
+
+ {categories.slice(0, 8).map(cat => (
+
+ ))}
+
+
+ {/* Sort + date range row */}
+
+
+
Période :
+
+ {(['today', '7d', '30d', 'all'] as DateRange[]).map(r => (
+
+ ))}
+
+
+
+
Tri :
+
+ {(['impact_desc', 'impact_asc', 'date_desc', 'date_asc'] as SortMode[]).map(s => (
+
+ ))}
+
+
+
{filtered.length} news
+
+
{isLoading ? (
) : (
- {filtered?.map((n, i) =>
)}
- {(!filtered || filtered.length === 0) && (
+ {filtered.map((n, i) =>
)}
+ {filtered.length === 0 && (
Démarrer le backend pour charger les actualités