diff --git a/backend/routers/instruments_watchlist.py b/backend/routers/instruments_watchlist.py index 0c18149..fb1ee1c 100644 --- a/backend/routers/instruments_watchlist.py +++ b/backend/routers/instruments_watchlist.py @@ -48,13 +48,23 @@ def _saxo_quote(saxo_symbol: str) -> Optional[dict]: def watchlist_quotes(): from services.database import get_instruments_watchlist from services.data_fetcher import get_quote_with_volatility + from services.wavelet_signals import _FRIENDLY_TO_YFINANCE items = [] for row in get_instruments_watchlist(): q = None if row.get("saxo_quote_symbol"): q = _saxo_quote(row["saxo_quote_symbol"]) if q is None: - q = get_quote_with_volatility(row["ticker"]) or {} + # row["ticker"] is the Cockpit's own label for some rows (BRENT, GOLD...), not a + # real yfinance symbol — without this translation yfinance returns nothing and + # the card shows "—" instead of falling back to the last available close, same + # gap already fixed once for the wavelet cache (see _FRIENDLY_TO_YFINANCE there). + yf_ticker = row["ticker"] + if yf_ticker in _FRIENDLY_TO_YFINANCE: + yf_ticker = _FRIENDLY_TO_YFINANCE[yf_ticker] + elif len(yf_ticker) == 6 and yf_ticker.isalpha(): + yf_ticker += "=X" + q = get_quote_with_volatility(yf_ticker) or {} items.append({ **row, "price": q.get("price"), diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 3a5b8b0..302f0b7 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -275,7 +275,7 @@ export default function Dashboard() { return groups } - const { todayEvents, restOfWeekGrouped, nextWeekGrouped } = useMemo(() => { + const { todayEvents, restOfWeekGrouped, nextWeekGrouped, lastPastDayGrouped, isCurrentWeekEmpty } = useMemo(() => { const all: any[] = (ecoCalendarData as any)?.events ?? [] const events = all.filter((ev: any) => ecoImpactFilter.has(ev.impact) && ecoCurrencyFilter.has(ev.currency)) const now = new Date() @@ -295,7 +295,23 @@ export default function Dashboard() { const restOfWeek = events.filter((ev: any) => ev.event_date > todayISO && ev.event_date <= weekEndISO) const nextWeek = events.filter((ev: any) => ev.event_date > weekEndISO && ev.event_date <= nextWeekEndISO) - return { todayEvents: today, restOfWeekGrouped: groupByDate(restOfWeek), nextWeekGrouped: groupByDate(nextWeek) } + // Weekend / dead-week fallback: nothing today and nothing left this week (e.g. Sunday, + // when weekEndISO collapses to todayISO so restOfWeek is structurally always empty) — + // surface the most recent past day that actually had results instead of a blank card. + const currentWeekEmpty = today.length === 0 && restOfWeek.length === 0 + let lastPastDay: any[] = [] + if (currentWeekEmpty) { + const past = events + .filter((ev: any) => ev.event_date < todayISO) + .sort((a: any, b: any) => b.event_date.localeCompare(a.event_date)) + const mostRecentDate = past[0]?.event_date + if (mostRecentDate) lastPastDay = past.filter((ev: any) => ev.event_date === mostRecentDate) + } + + return { + todayEvents: today, restOfWeekGrouped: groupByDate(restOfWeek), nextWeekGrouped: groupByDate(nextWeek), + lastPastDayGrouped: groupByDate(lastPastDay), isCurrentWeekEmpty: currentWeekEmpty, + } }, [ecoCalendarData, ecoImpactFilter, ecoCurrencyFilter]) return ( @@ -660,7 +676,9 @@ export default function Dashboard() { +Next week - {(todayEvents.length > 0 || restOfWeekGrouped.length > 0 || (ecoShowNextWeek && nextWeekGrouped.length > 0)) ? ( + {(todayEvents.length > 0 || restOfWeekGrouped.length > 0 + || (ecoShowNextWeek && nextWeekGrouped.length > 0) + || (isCurrentWeekEmpty && (lastPastDayGrouped.length > 0 || nextWeekGrouped.length > 0))) ? (
{todayEvents.length > 0 && (
@@ -682,7 +700,21 @@ export default function Dashboard() {
))} - {ecoShowNextWeek && nextWeekGrouped.length > 0 && ( + {/* Weekend fallback: nothing today/this week left — show the last day that + actually had results (e.g. Friday, on a Sunday) instead of a blank card. */} + {isCurrentWeekEmpty && lastPastDayGrouped.length > 0 && ( + <> +
+ Derniers résultats ({formatDateShort(lastPastDayGrouped[0].date)}) +
+ {lastPastDayGrouped.map(group => ( +
+ {group.events.map((ev: any, i: number) => )} +
+ ))} + + )} + {(ecoShowNextWeek || isCurrentWeekEmpty) && nextWeekGrouped.length > 0 && ( <>
Next week
{nextWeekGrouped.map(group => (