diff --git a/components/CurrencyCard.tsx b/components/CurrencyCard.tsx
index f4e50de..c8603f7 100644
--- a/components/CurrencyCard.tsx
+++ b/components/CurrencyCard.tsx
@@ -679,78 +679,145 @@ export default function CurrencyCard({
{/* ════ APERÇU ════════════════════════════════════════════════════ */}
{activeTab === "overview" && (
<>
- {/* OIS mini-chart */}
- {ratePath && ratePath.meetings.length > 0 && (
-
-
- OIS · Probabilités de move
- au {ratePath.asOf}
-
-
- ({
- label: m.label,
- prob: m.probMovePct,
- }))}
- margin={{ top: 2, right: 0, left: 0, bottom: 0 }}
- >
-
-
- [`${v.toFixed(0)}%`, "Probabilité"]}
- />
-
-
- {ratePath.peakMeeting && (
- <>
-
-
- Pic : {ratePath.peakMeeting.label}
-
-
- {ratePath.peakMeeting.probMovePct.toFixed(0)}% {ratePath.peakMeeting.probIsCut ? "Cut" : "Hike"}
-
- {ratePath.yearEndImplied !== null && (() => {
- const bps = Math.round((ratePath.yearEndImplied! - ratePath.currentRate) * 100);
- const cls = bps < 0 ? "text-sky-400 font-bold" : bps > 0 ? "text-red-400 font-bold" : "text-slate-500";
- return (
-
- {bps > 0 ? "+" : ""}{bps}bps fin an
-
- );
- })()}
+ {/* ── OIS block ───────────────────────────────────────────── */}
+ {ratePath && ratePath.meetings.length > 0 && (() => {
+ const yearEnd2026 = `${new Date().getFullYear()}-12-31`;
+ const meets2026 = ratePath.meetings.filter(m => m.dateIso <= yearEnd2026);
+ const bpsYE = ratePath.yearEndImplied !== null
+ ? Math.round((ratePath.yearEndImplied - ratePath.currentRate) * 100) : null;
+ const bpsCls = bpsYE === null ? "text-slate-400"
+ : bpsYE < 0 ? "text-sky-400" : bpsYE > 0 ? "text-red-400" : "text-slate-400";
+
+ return (
+
+
+ {/* ── SECTION 1 : SOFR / OIS live ─────────────────────── */}
+
+ {/* header */}
+
+
+ OIS · SOFR Futures
+ LIVE
+
+
au {ratePath.asOf}
- {/* ── Flèches de tendance vs article IL semaine précédente ── */}
- {ratePath.ilDelta && (Math.abs(ratePath.ilDelta.probDelta) >= 3 || Math.abs(ratePath.ilDelta.bpsDelta) >= 10) && (
-
-
- vs sem. préc. :
-
-
+
+
Taux actuel
+
{ratePath.currentRate.toFixed(2)}%
+
+ →
+
+
Fin d'an (Dec)
+
+ {ratePath.yearEndImplied?.toFixed(2) ?? "—"}%
+
+
+ {bpsYE !== null && (
+
+
Δ bps
+
+ {bpsYE > 0 ? "+" : ""}{bpsYE}
+ bps
+
+
+ )}
+
+
+ {/* chart probabilités */}
+
+ ({ label: m.label, prob: m.probMovePct }))}
+ margin={{ top: 2, right: 0, left: 0, bottom: 0 }}
+ >
+
+
+ [`${v.toFixed(0)}%`, "Prob. move"]}
/>
- {ratePath.ilDelta.bpsDelta !== 0 && (
-
- )}
+
+
+
+ {/* tableau des réunions 2026 */}
+ {meets2026.length > 0 && (
+
+ {meets2026.map(m => {
+ const isPeak = m.dateIso === ratePath.peakMeeting?.dateIso;
+ const dir = m.probMovePct < 20 ? "HOLD"
+ : m.probIsCut ? (m.probMovePct >= 50 ? "CUT" : "CUT?")
+ : (m.probMovePct >= 50 ? "HIKE" : "HIKE?");
+ const dirCls = m.probMovePct < 20 ? "text-slate-600"
+ : m.probIsCut ? "text-sky-400" : "text-red-400";
+ return (
+
+
+ {isPeak && ●}{m.label}
+
+ {dir}
+ = 20 ? "text-slate-300" : "text-slate-600"}`}>
+ {m.probMovePct.toFixed(0)}%
+
+ {m.impliedRate.toFixed(3)}%
+
+ );
+ })}
)}
- >
- )}
-
- )}
+
+
+ {/* ── SECTION 2 : Analyste G. Dellamotta ──────────────── */}
+ {ratePath.ilCurrent && (
+
+
+ Analyste · G. Dellamotta
+ {ratePath.ilCurrent.articleDate}
+
+
+ {/* bps year-end analyste */}
+
+
Fin d'an (IL)
+
+ {ratePath.ilCurrent.isCut ? "" : "+"}{ratePath.ilCurrent.bpsYearEnd}
+ bps
+
+
+ {/* prob next meeting analyste */}
+
+
Proch. réunion
+
+ {ratePath.ilCurrent.isNoChange
+ ? {ratePath.ilCurrent.probPct.toFixed(0)}% Hold
+ :
+ {ratePath.ilCurrent.probPct.toFixed(0)}% {ratePath.ilCurrent.isCut ? "Cut" : "Hike"}
+
+ }
+
+
+ {/* delta hebdo */}
+ {ratePath.ilDelta && (Math.abs(ratePath.ilDelta.probDelta) >= 3 || Math.abs(ratePath.ilDelta.bpsDelta) >= 5) && (
+
+
vs sem. préc.
+
+
+
+
+
+ )}
+
+
+ )}
+
+ );
+ })()}
{/* Divergence / convergence signal — expandable */}
{divergenceSignal !== "neutral" && (
diff --git a/lib/rateprobability.ts b/lib/rateprobability.ts
index aef5924..7e0f402 100644
--- a/lib/rateprobability.ts
+++ b/lib/rateprobability.ts
@@ -24,13 +24,22 @@ export interface ILWeeklyDelta {
prevDate: string; // date de l'article de référence (semaine précédente)
}
+export interface ILCurrent {
+ bpsYearEnd: number; // bps fin d'an selon l'article IL courant
+ probPct: number; // probabilité de move à la prochaine réunion (IL)
+ isNoChange: boolean; // l'analyste anticipe un statu quo
+ isCut: boolean; // l'analyste anticipe une baisse
+ articleDate: string; // date de publication de l'article (YYYY-MM-DD)
+}
+
export interface CBRatePath {
currency: Currency;
asOf: string; // "2026-05-31"
currentRate: number;
meetings: RateProbMeeting[];
peakMeeting: RateProbMeeting | null; // réunion avec proba max de mouvement
- yearEndImplied: number | null; // taux impliqué à la dernière réunion connue
+ yearEndImplied: number | null; // taux impliqué à la dernière réunion connue (SOFR)
+ ilCurrent?: ILCurrent; // valeurs absolues de l'article IL courant
ilDelta?: ILWeeklyDelta; // delta vs article IL semaine précédente
}
@@ -256,7 +265,15 @@ export async function fetchAllCBPaths(): Promise
{
};
}
- data[ccy] = { ...path, yearEndImplied, ...(ilDelta ? { ilDelta } : {}) };
+ const ilCurrent: ILCurrent = {
+ bpsYearEnd: ilEntry.bpsYearEnd,
+ probPct: ilEntry.nextMeetingProbPct,
+ isNoChange: ilEntry.nextMeetingIsNoChange,
+ isCut: !ilEntry.nextMeetingIsHike && !ilEntry.nextMeetingIsNoChange,
+ articleDate: ilEntry.publishedDate,
+ };
+
+ data[ccy] = { ...path, yearEndImplied, ilCurrent, ...(ilDelta ? { ilDelta } : {}) };
}
return data;