auto: sync 2026-06-03 00:02

This commit is contained in:
Capucine Gest
2026-06-03 00:02:09 +02:00
parent 7874ff16ff
commit fa7f24715c
4 changed files with 40 additions and 7 deletions
+12 -4
View File
@@ -608,13 +608,21 @@ export default function CurrencyCard({
</ResponsiveContainer> </ResponsiveContainer>
{ratePath.peakMeeting && ( {ratePath.peakMeeting && (
<div className="flex items-center justify-between mt-1 text-[10px]"> <div className="flex items-center justify-between mt-1 text-[10px]">
<span className="text-slate-600">Pic : <span className="text-slate-400">{ratePath.peakMeeting.label}</span></span> <span className="text-slate-600">
Pic : <span className="text-slate-400">{ratePath.peakMeeting.label}</span>
</span>
<span className={ratePath.peakMeeting.probIsCut ? "text-sky-400 font-bold" : "text-red-400 font-bold"}> <span className={ratePath.peakMeeting.probIsCut ? "text-sky-400 font-bold" : "text-red-400 font-bold"}>
{ratePath.peakMeeting.probMovePct.toFixed(0)}% {ratePath.peakMeeting.probIsCut ? "Cut" : "Hike"} {ratePath.peakMeeting.probMovePct.toFixed(0)}% {ratePath.peakMeeting.probIsCut ? "Cut" : "Hike"}
</span> </span>
{ratePath.yearEndImplied !== null && ( {ratePath.yearEndImplied !== null && (() => {
<span className="text-slate-600">fin an: {ratePath.yearEndImplied.toFixed(2)}%</span> 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 (
<span className={cls} title={`Taux actuel: ${ratePath.currentRate.toFixed(2)}% → fin an: ${ratePath.yearEndImplied!.toFixed(2)}%`}>
{bps > 0 ? "+" : ""}{bps}bps fin an
</span>
);
})()}
</div> </div>
)} )}
</div> </div>
+12 -2
View File
@@ -64,7 +64,12 @@ function parseArticleBody(text: string, publishedDate: string): ILExpectationsMa
// Matches: "RBNZ: 75 bps (79% probability of rate hike at the next meeting)" // Matches: "RBNZ: 75 bps (79% probability of rate hike at the next meeting)"
// "Fed: 13 bps (99% probability of no change at the next meeting)" // "Fed: 13 bps (99% probability of no change at the next meeting)"
const linePattern = /([A-Za-z]+)\s*:\s*(\d+)\s*bps\s*\(\s*(\d+)%\s*probability\s+of\s+(rate\s+(?:hike|cut)|no\s+change)\s+at\s+the\s+next\s+meeting\)/gi; // "ECB: 53 bps (99% probability of rate cut at the next meeting)"
// Note: bps value in the article is always unsigned — sign is inferred from direction.
// rate hike → positive bps (rate going up)
// rate cut → negative bps (rate going down)
// no change → keep unsigned (residual expectation for later meetings)
const linePattern = /([A-Za-z]+)\s*:\s*(-?\d+)\s*bps\s*\(\s*(\d+)%\s*probability\s+of\s+(rate\s+(?:hike|cut)|no\s+change)\s+at\s+the\s+next\s+meeting\)/gi;
let m: RegExpExecArray | null; let m: RegExpExecArray | null;
while ((m = linePattern.exec(text)) !== null) { while ((m = linePattern.exec(text)) !== null) {
@@ -72,11 +77,16 @@ function parseArticleBody(text: string, publishedDate: string): ILExpectationsMa
const ccy = CB_TO_CCY[cbRaw.toLowerCase()]; const ccy = CB_TO_CCY[cbRaw.toLowerCase()];
if (!ccy) continue; if (!ccy) continue;
const bpsYearEnd = parseInt(bpsStr);
const probPct = parseInt(probStr); const probPct = parseInt(probStr);
const direction = directionRaw.toLowerCase(); const direction = directionRaw.toLowerCase();
const nextMeetingIsNoChange = direction === "no change"; const nextMeetingIsNoChange = direction === "no change";
const nextMeetingIsHike = !nextMeetingIsNoChange && direction.includes("hike"); const nextMeetingIsHike = !nextMeetingIsNoChange && direction.includes("hike");
const nextMeetingIsCut = !nextMeetingIsNoChange && direction.includes("cut");
// Apply sign: if direction is cut and value is positive, negate it
let bpsYearEnd = parseInt(bpsStr);
if (nextMeetingIsCut && bpsYearEnd > 0) bpsYearEnd = -bpsYearEnd;
// Probability of change = 100 - probNoChange OR directProb if it's a hike/cut // Probability of change = 100 - probNoChange OR directProb if it's a hike/cut
const nextMeetingProbPct = nextMeetingIsNoChange ? 100 - probPct : probPct; const nextMeetingProbPct = nextMeetingIsNoChange ? 100 - probPct : probPct;
+15
View File
@@ -214,6 +214,21 @@ export async function fetchAllCBPaths(): Promise<RateProbData> {
if (snbPath) data["CHF"] = snbPath; if (snbPath) data["CHF"] = snbPath;
} }
// Enrichir yearEndImplied avec bpsYearEnd de IL (Giuseppe Dellamotta — source humaine)
// pour toutes les devises où IL a une donnée ET rateprobability.com a réussi.
// Règle : pour les hikes (bpsYearEnd > 0) et cuts (bpsYearEnd < 0), mettre à jour.
// Pour "no change" (bpsYearEnd proche de 0), garder la valeur rateprobability.com.
for (const [ccyStr, ilEntry] of Object.entries(ilData)) {
const ccy = ccyStr as keyof RateProbData;
const path = data[ccy];
if (!path) continue;
if (typeof ilEntry.bpsYearEnd !== "number") continue;
if (ilEntry.nextMeetingIsNoChange && Math.abs(ilEntry.bpsYearEnd) < 10) continue; // garder RP si "no change" + bps résiduel faible
const ilYearEnd = parseFloat((path.currentRate + ilEntry.bpsYearEnd / 100).toFixed(4));
data[ccy] = { ...path, yearEndImplied: ilYearEnd };
}
return data; return data;
} }
+1 -1
View File
File diff suppressed because one or more lines are too long