mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-07-27 20:37:45 +00:00
feat: remplace Atlanta Fed par des futures Euribor/SONIA réels pour EUR/GBP
- Retire l'onglet Atlanta Fed MPT (USD) : jugé sans valeur ajoutée réelle. - EUR/GBP n'avaient qu'un unique point synthétique (agrégat year-end InvestingLive) gonflé en fausses réunions plates à 0% sur Courbe/ Probabilités/Réunions — d'où l'aspect cassé. Investing.com n'a de Rate Monitor pré-calculé (comme pour la Fed) ni pour la BCE ni pour la BoE (404 confirmé), donc pas d'équivalent direct au pipeline USD. - Remplace ce point unique par un vrai scrape des futures Euribor 3M (Eurex) et Three-Month SONIA (ICE), cotés sur investing.com (delayed, gratuit, pas de login) : conversion prix→taux (100−prix), mapping sur le calendrier réel BCE/BoE (échéance la plus proche ≥ date de réunion, fenêtre de grâce de 60j au-delà du dernier contrat coté, sinon on s'arrête plutôt que d'inventer), probabilité approximée avec la convention bps/25 déjà utilisée pour le fallback InvestingLive. - Résolution plus grossière que l'USD (mensuelle EUR, trimestrielle GBP) et clairement étiquetée comme telle dans un footnote dédié. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,166 +0,0 @@
|
|||||||
// Atlanta Fed Market Probability Tracker (MPT) — méthodologie alternative à
|
|
||||||
// Investing.com Fed Rate Monitor : au lieu des 30-day Fed Fund Futures, la
|
|
||||||
// Fed d'Atlanta déduit une distribution de probabilité du niveau du taux Fed
|
|
||||||
// à partir des OPTIONS sur futures SOFR 3 mois cotées au CME (le rationnel :
|
|
||||||
// la Fed conduit sa politique via des opérations repo, donc la distribution
|
|
||||||
// implicite du SOFR composé sur la fenêtre de référence du contrat permet de
|
|
||||||
// déduire les anticipations sur la fourchette cible du FOMC).
|
|
||||||
// Doc + téléchargements : https://www.atlantafed.org/cenfis/market-probability-tracker
|
|
||||||
//
|
|
||||||
// Format du fichier xl/worksheets/sheet3.xml (vérifié 2026-07-08) — format
|
|
||||||
// long, une ligne par (date, reference_start, target_range, field) :
|
|
||||||
// date : date d'observation (YYYY-MM-DD), publiée quotidiennement
|
|
||||||
// reference_start : date de début de la fenêtre de 3 mois référencée par le
|
|
||||||
// contrat SOFR (trimestrielle, style IMM)
|
|
||||||
// target_range : pour les champs agrégés (Rate:*, Prob: cut, Prob: hike)
|
|
||||||
// = fourchette cible ACTUELLE (contexte) ; pour les champs
|
|
||||||
// "Prob: XXXbps - YYYbps" = LA fourchette évaluée
|
|
||||||
// field / value : nom du champ + valeur (en bps, ex. "373.91" = 3.7391%)
|
|
||||||
//
|
|
||||||
// Pas de dépendance xlsx npm (le paquet du registre public a des CVE critiques
|
|
||||||
// non patchées depuis que SheetJS a arrêté d'y publier) — on lit le zip et le
|
|
||||||
// XML OOXML directement avec les modules Node natifs (zlib + regex).
|
|
||||||
|
|
||||||
import { writeFileSync, mkdirSync } from "fs";
|
|
||||||
import { inflateRawSync } from "zlib";
|
|
||||||
|
|
||||||
const XLSX_URL = "https://www.atlantafed.org/-/media/Project/Atlanta/FRBA/Documents/cenfis/market-probability-tracker/mpt_histdata.xlsx";
|
|
||||||
|
|
||||||
// ── Lecteur ZIP minimal (central directory + inflate raw deflate) ────────────
|
|
||||||
|
|
||||||
function readZip(buf) {
|
|
||||||
let eocdOff = -1;
|
|
||||||
for (let i = buf.length - 22; i >= Math.max(0, buf.length - 22 - 65536); i--) {
|
|
||||||
if (buf.readUInt32LE(i) === 0x06054b50) { eocdOff = i; break; }
|
|
||||||
}
|
|
||||||
if (eocdOff === -1) throw new Error("ZIP: End Of Central Directory introuvable");
|
|
||||||
const cdEntries = buf.readUInt16LE(eocdOff + 10);
|
|
||||||
const cdOffset = buf.readUInt32LE(eocdOff + 16);
|
|
||||||
|
|
||||||
const entries = {};
|
|
||||||
let p = cdOffset;
|
|
||||||
for (let i = 0; i < cdEntries; i++) {
|
|
||||||
if (buf.readUInt32LE(p) !== 0x02014b50) throw new Error(`ZIP: central directory corrompue à l'offset ${p}`);
|
|
||||||
const compMethod = buf.readUInt16LE(p + 10);
|
|
||||||
const compSize = buf.readUInt32LE(p + 20);
|
|
||||||
const nameLen = buf.readUInt16LE(p + 28);
|
|
||||||
const extraLen = buf.readUInt16LE(p + 30);
|
|
||||||
const commentLen = buf.readUInt16LE(p + 32);
|
|
||||||
const lfhOffset = buf.readUInt32LE(p + 42);
|
|
||||||
const name = buf.toString("utf8", p + 46, p + 46 + nameLen);
|
|
||||||
entries[name] = { compMethod, compSize, lfhOffset };
|
|
||||||
p += 46 + nameLen + extraLen + commentLen;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
read(name) {
|
|
||||||
const e = entries[name];
|
|
||||||
if (!e) return null;
|
|
||||||
const nameLen = buf.readUInt16LE(e.lfhOffset + 26);
|
|
||||||
const extraLen = buf.readUInt16LE(e.lfhOffset + 28);
|
|
||||||
const dataStart = e.lfhOffset + 30 + nameLen + extraLen;
|
|
||||||
const raw = buf.subarray(dataStart, dataStart + e.compSize);
|
|
||||||
return e.compMethod === 0 ? raw : inflateRawSync(raw);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSharedStrings(xml) {
|
|
||||||
return Array.from(xml.matchAll(/<si>(?:<t[^>]*>([^<]*)<\/t>|<r>[\s\S]*?<\/r>)*<\/si>/g))
|
|
||||||
.map(m => m[0].match(/<t[^>]*>([^<]*)<\/t>/g)?.map(t => t.replace(/<[^>]+>/g, "")).join("") ?? "");
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSheetRows(xml, strings) {
|
|
||||||
const rowRe = /<row r="\d+"[^>]*>([\s\S]*?)<\/row>/g;
|
|
||||||
const cellRe = /<c r="([A-Z]+)\d+"(?:\s+t="([a-z]+)")?[^>]*>(?:<v>([^<]*)<\/v>)?<\/c>/g;
|
|
||||||
const rows = [];
|
|
||||||
let rm, first = true;
|
|
||||||
while ((rm = rowRe.exec(xml)) !== null) {
|
|
||||||
if (first) { first = false; continue; } // ligne d'en-tête
|
|
||||||
const cells = {};
|
|
||||||
let cm; cellRe.lastIndex = 0;
|
|
||||||
while ((cm = cellRe.exec(rm[1])) !== null) {
|
|
||||||
const [, ref, type, val] = cm;
|
|
||||||
cells[ref] = val === undefined ? null : (type === "s" ? strings[+val] : val);
|
|
||||||
}
|
|
||||||
rows.push(cells);
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
function excelSerialToIso(serial) {
|
|
||||||
const epoch = Date.UTC(1899, 11, 30);
|
|
||||||
return new Date(epoch + Number(serial) * 86400000).toISOString().slice(0, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Fetch + parse ─────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
async function fetchAtlantaMpt() {
|
|
||||||
const res = await fetch(XLSX_URL, {
|
|
||||||
headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" },
|
|
||||||
});
|
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
||||||
const buf = Buffer.from(await res.arrayBuffer());
|
|
||||||
|
|
||||||
const zip = readZip(buf);
|
|
||||||
const strings = parseSharedStrings(zip.read("xl/sharedStrings.xml").toString("utf8"));
|
|
||||||
const rows = parseSheetRows(zip.read("xl/worksheets/sheet3.xml").toString("utf8"), strings);
|
|
||||||
|
|
||||||
// { A: date, B: reference_start (serial), C: target_range, D: field, E: value }
|
|
||||||
const records = rows
|
|
||||||
.filter(r => r.A && r.B && r.D && r.E !== null)
|
|
||||||
.map(r => ({ date: r.A, ref: Number(r.B), range: r.C, field: r.D, value: parseFloat(String(r.E).trim()) }));
|
|
||||||
|
|
||||||
if (!records.length) throw new Error("aucune ligne exploitable trouvée dans sheet3");
|
|
||||||
|
|
||||||
const maxDate = records.reduce((m, r) => (r.date > m ? r.date : m), "");
|
|
||||||
const latest = records.filter(r => r.date === maxDate);
|
|
||||||
const refStarts = [...new Set(latest.map(r => r.ref))].sort((a, b) => a - b);
|
|
||||||
|
|
||||||
const windows = refStarts.map(ref => {
|
|
||||||
const windowRows = latest.filter(r => r.ref === ref);
|
|
||||||
const get = (field) => windowRows.find(r => r.field === field)?.value ?? null;
|
|
||||||
const anchorRange = windowRows.find(r => r.field === "Prob: hike")?.range ?? null;
|
|
||||||
// La colonne "range" (C) vaut toujours la fourchette ACTUELLE/ancre pour
|
|
||||||
// toutes les lignes de la fenêtre (y compris les lignes de distribution) —
|
|
||||||
// la fourchette évaluée par chaque bucket est encodée dans le nom du champ
|
|
||||||
// lui-même ("Prob: 375bps - 400bps"), pas dans la colonne range.
|
|
||||||
const distribution = windowRows
|
|
||||||
.filter(r => r.field.startsWith("Prob: ") && r.field !== "Prob: cut" && r.field !== "Prob: hike")
|
|
||||||
.map(r => ({ rangeLabel: r.field.replace(/^Prob:\s*/, ""), probPct: r.value }))
|
|
||||||
.sort((a, b) => parseInt(a.rangeLabel) - parseInt(b.rangeLabel));
|
|
||||||
return {
|
|
||||||
windowStartIso: excelSerialToIso(ref),
|
|
||||||
anchorRange,
|
|
||||||
probCutPct: get("Prob: cut"),
|
|
||||||
probHikePct: get("Prob: hike"),
|
|
||||||
rate25: get("Rate: 25th percentile"),
|
|
||||||
rateMean: get("Rate: mean"),
|
|
||||||
rateMode: get("Rate: mode"),
|
|
||||||
rate75: get("Rate: 75th percentile"),
|
|
||||||
distribution,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return { asOf: maxDate, windows };
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log("Fetching Atlanta Fed MPT historical data…");
|
|
||||||
const data = await fetchAtlantaMpt();
|
|
||||||
console.log(`✓ asOf=${data.asOf}, ${data.windows.length} fenêtres trimestrielles`);
|
|
||||||
console.log(` front window: ${data.windows[0].windowStartIso} — hike=${data.windows[0].probHikePct}% cut=${data.windows[0].probCutPct}%`);
|
|
||||||
|
|
||||||
mkdirSync("data", { recursive: true });
|
|
||||||
writeFileSync("data/atlanta-fed-mpt.json", JSON.stringify({
|
|
||||||
updated_at: new Date().toISOString().slice(0, 10),
|
|
||||||
source: "https://www.atlantafed.org/cenfis/market-probability-tracker",
|
|
||||||
note: "Probabilités dérivées des options sur futures SOFR 3 mois (CME) — méthodologie Atlanta Fed, mise à jour quotidienne. Fourchettes exprimées en bps (350bps-375bps = 3.50%-3.75%). Alternative aux 30-day Fed Fund Futures (Investing.com Fed Rate Monitor).",
|
|
||||||
...data,
|
|
||||||
}, null, 2) + "\n");
|
|
||||||
console.log("✓ Saved data/atlanta-fed-mpt.json");
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`✗ Atlanta Fed MPT fetch failed: ${e.message}`);
|
|
||||||
process.exit(0); // échec silencieux — ne bloque pas le workflow, données précédentes conservées
|
|
||||||
}
|
|
||||||
@@ -303,6 +303,140 @@ function parseRateMonitorTable(ccy, html) {
|
|||||||
return { today: { midpoint: currentRate, rows } };
|
return { today: { midpoint: currentRate, rows } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 1bis. Investing.com futures strips (EUR/GBP) ──────────────────────────────
|
||||||
|
// Investing.com n'a de Rate Monitor (probabilité pré-calculée par réunion) que
|
||||||
|
// pour la Fed (voir note en tête de fichier — ecb/boe-rate-monitor → 404). Mais
|
||||||
|
// Investing.com sert bien les prix (delayed) des futures Euribor 3M (Eurex) et
|
||||||
|
// Three-Month SONIA (ICE) — la référence que les praticiens utilisent pour lire
|
||||||
|
// les anticipations BCE/BoE en l'absence d'un outil équivalent au Fed Rate
|
||||||
|
// Monitor. Contrairement à ce dernier, il n'y a PAS de distribution de
|
||||||
|
// probabilité publiée par contrat : on déduit nous-mêmes une probabilité
|
||||||
|
// approximative (même convention bps/25 déjà utilisée pour le fallback
|
||||||
|
// InvestingLive plus bas), en mappant chaque échéance de future sur le
|
||||||
|
// calendrier réel de réunions (réunion → échéance la plus proche ≥ sa date).
|
||||||
|
// Au-delà de la dernière échéance réellement cotée, on prolonge à plat sur une
|
||||||
|
// fenêtre de grâce (FUTURES_GRACE_DAYS) ; au-delà, on s'arrête — pas de réunion
|
||||||
|
// affichée plutôt qu'une valeur inventée.
|
||||||
|
//
|
||||||
|
// Résolution intrinsèquement plus grossière que l'USD : Euribor cote ~mensuel
|
||||||
|
// (contrats vus : Jul/Aug/Sep/Oct 26), SONIA cote trimestriel (Jun/Sep 26
|
||||||
|
// seulement, 2 contrats dispo sur investing.com) — donc plusieurs réunions
|
||||||
|
// rapprochées peuvent partager la même valeur implicite.
|
||||||
|
//
|
||||||
|
// Calendriers dupliqués depuis lib/rateprobability.ts (ce script est un .mjs
|
||||||
|
// autonome sans accès aux imports TS de l'app) — à garder synchronisés, même
|
||||||
|
// cadence de maintenance qu'indiqué là-bas (~1x/an, à la publication de
|
||||||
|
// chaque banque centrale).
|
||||||
|
const ECB_MEETINGS = [
|
||||||
|
"2026-07-23", "2026-09-10", "2026-10-29", "2026-12-17",
|
||||||
|
"2027-02-04", "2027-03-18", "2027-04-29", "2027-06-10",
|
||||||
|
"2027-07-22", "2027-09-09", "2027-10-28", "2027-12-16",
|
||||||
|
];
|
||||||
|
const BOE_MEETINGS = [
|
||||||
|
"2026-07-30", "2026-09-17", "2026-11-05", "2026-12-17",
|
||||||
|
"2027-02-04", "2027-03-18", "2027-04-29", "2027-06-17",
|
||||||
|
"2027-07-29", "2027-09-16", "2027-11-04", "2027-12-16",
|
||||||
|
];
|
||||||
|
|
||||||
|
const FUTURES_STRIP_CONFIG = {
|
||||||
|
EUR: { overviewUrl: "https://www.investing.com/rates-bonds/euribor-futures", prefix: "FEU3c", meetings: ECB_MEETINGS },
|
||||||
|
GBP: { overviewUrl: "https://www.investing.com/rates-bonds/three-month-sonia-futures", prefix: "SON3c", meetings: BOE_MEETINGS },
|
||||||
|
};
|
||||||
|
const FUTURES_GRACE_DAYS = 60;
|
||||||
|
|
||||||
|
// La page overview liste les contrats liés dans un tableau "relative-table" —
|
||||||
|
// chaque ligne est un <a href="...?cid=NNNN" title="FEU3c1">. On (re)découvre
|
||||||
|
// cette liste à chaque run plutôt que de figer des cid en dur : les contrats
|
||||||
|
// expirent (mensuel/trimestriel) et le cid pertinent change avec le temps.
|
||||||
|
async function fetchInvestingComContractList(overviewUrl, prefix) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(overviewUrl, { headers: CHROME_HEADERS });
|
||||||
|
if (!res.ok) { console.error(`[futures] ${overviewUrl} → ${res.status}`); return []; }
|
||||||
|
const html = await res.text();
|
||||||
|
if (/just a moment|cf-browser-verification|enable javascript/i.test(html)) {
|
||||||
|
console.error(`[futures] Cloudflare challenge on ${overviewUrl}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const re = /<a href="([^"]+)"\s+class="[^"]*"\s+title="([A-Za-z0-9]+)">/g;
|
||||||
|
const seen = new Map();
|
||||||
|
let m;
|
||||||
|
while ((m = re.exec(html)) !== null) {
|
||||||
|
const [, href, label] = m;
|
||||||
|
if (!label.startsWith(prefix) || seen.has(label)) continue;
|
||||||
|
seen.set(label, href);
|
||||||
|
}
|
||||||
|
return [...seen.entries()]
|
||||||
|
.map(([label, url]) => ({ label, url, n: parseInt(label.slice(prefix.length), 10) }))
|
||||||
|
.filter(c => Number.isFinite(c.n))
|
||||||
|
.sort((a, b) => a.n - b.n);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[futures] ${overviewUrl} error: ${e.message}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chaque page contrat (?cid=NNNN) rend son propre prix + échéance server-side
|
||||||
|
// (vérifié : pas besoin d'exécuter le JS client). Convention Eurex/ICE "100 −
|
||||||
|
// taux", identique à Eurodollar/Fed Funds.
|
||||||
|
async function fetchContractQuote(url) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, { headers: CHROME_HEADERS });
|
||||||
|
if (!res.ok) return null;
|
||||||
|
const html = await res.text();
|
||||||
|
const settlement = html.match(/data-test="settlement_date"[^>]*>(\d{2})\/(\d{2})\/(\d{4})</);
|
||||||
|
const price = html.match(/data-test="instrument-price-last"[^>]*>([\d.]+)</);
|
||||||
|
if (!settlement || !price) return null;
|
||||||
|
const [, mm, dd, yyyy] = settlement;
|
||||||
|
return { dateIso: `${yyyy}-${mm}-${dd}`, price: parseFloat(price[1]) };
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[futures] contract fetch error: ${e.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchFuturesStrip(ccy) {
|
||||||
|
const cfg = FUTURES_STRIP_CONFIG[ccy];
|
||||||
|
if (!cfg) return null;
|
||||||
|
|
||||||
|
const contracts = await fetchInvestingComContractList(cfg.overviewUrl, cfg.prefix);
|
||||||
|
if (contracts.length < 2) { console.warn(`[futures/${ccy}] only ${contracts.length} contract(s) listed`); return null; }
|
||||||
|
|
||||||
|
const points = [];
|
||||||
|
for (const c of contracts) {
|
||||||
|
const q = await fetchContractQuote(c.url);
|
||||||
|
if (q) points.push(q);
|
||||||
|
await new Promise(r => setTimeout(r, 400));
|
||||||
|
}
|
||||||
|
if (points.length < 2) { console.warn(`[futures/${ccy}] only ${points.length} contract(s) priced`); return null; }
|
||||||
|
points.sort((a, b) => a.dateIso.localeCompare(b.dateIso));
|
||||||
|
|
||||||
|
const currentRate = FALLBACK_RATES[ccy] ?? 0;
|
||||||
|
const nowIso = new Date().toISOString().slice(0, 10);
|
||||||
|
const graceIso = new Date(new Date(points.at(-1).dateIso).getTime() + FUTURES_GRACE_DAYS * 86400000)
|
||||||
|
.toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
for (const meetingIso of cfg.meetings) {
|
||||||
|
if (meetingIso < nowIso) continue;
|
||||||
|
if (meetingIso > graceIso) break; // hors horizon réel couvert par les futures : on s'arrête plutôt que d'inventer
|
||||||
|
const point = points.find(p => p.dateIso >= meetingIso) ?? points.at(-1);
|
||||||
|
const impliedRate = parseFloat((100 - point.price).toFixed(4));
|
||||||
|
const cumulBps = parseFloat(((impliedRate - currentRate) * 100).toFixed(2));
|
||||||
|
rows.push({
|
||||||
|
meeting: new Date(meetingIso + "T12:00:00Z").toLocaleDateString("en-US", { month: "short", day: "numeric" }),
|
||||||
|
meeting_iso: meetingIso,
|
||||||
|
implied_rate_post_meeting: impliedRate,
|
||||||
|
prob_move_pct: Math.min(100, Math.round(Math.abs(cumulBps) / 25 * 100)),
|
||||||
|
prob_is_cut: cumulBps < 0,
|
||||||
|
change_bps: cumulBps,
|
||||||
|
num_moves: parseFloat((cumulBps / 25).toFixed(3)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!rows.length) return null;
|
||||||
|
console.log(`[futures/${ccy}] ✓ ${points.length} contrats réels (${points.map(p => p.dateIso).join(", ")}) → ${rows.length} réunions`);
|
||||||
|
return { today: { midpoint: currentRate, rows } };
|
||||||
|
}
|
||||||
|
|
||||||
// ── 2. InvestingLive fallback (Giuseppe Dellamotta, hebdomadaire) ─────────────
|
// ── 2. InvestingLive fallback (Giuseppe Dellamotta, hebdomadaire) ─────────────
|
||||||
|
|
||||||
const IL_CB_MAP = {
|
const IL_CB_MAP = {
|
||||||
@@ -440,6 +574,22 @@ for (const ccy of IC_SUPPORTED) {
|
|||||||
await new Promise(r => setTimeout(r, 600));
|
await new Promise(r => setTimeout(r, 600));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1bis — Investing.com futures strips (Euribor 3M / SONIA 3M) → EUR/GBP
|
||||||
|
// (voir doc détaillée plus haut, section "1bis. Investing.com futures strips")
|
||||||
|
console.log("\n=== Investing.com Futures Strips (EUR/GBP) ===");
|
||||||
|
for (const ccy of Object.keys(FUTURES_STRIP_CONFIG)) {
|
||||||
|
let data = null;
|
||||||
|
for (let attempt = 1; attempt <= 3 && !data; attempt++) {
|
||||||
|
if (attempt > 1) {
|
||||||
|
console.log(`[futures/${ccy}] retry ${attempt}/3…`);
|
||||||
|
await new Promise(r => setTimeout(r, 2000 * attempt));
|
||||||
|
}
|
||||||
|
data = await fetchFuturesStrip(ccy);
|
||||||
|
}
|
||||||
|
if (data) results[ccy] = data;
|
||||||
|
await new Promise(r => setTimeout(r, 600));
|
||||||
|
}
|
||||||
|
|
||||||
// 2 — InvestingLive → fallback for any missing CB
|
// 2 — InvestingLive → fallback for any missing CB
|
||||||
const missing = CCYS.filter(c => !results[c]);
|
const missing = CCYS.filter(c => !results[c]);
|
||||||
if (missing.length) {
|
if (missing.length) {
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
name: Fetch Atlanta Fed Market Probability Tracker
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '30 11 * * *' # quotidien 11h30 UTC (donnée mise à jour ~1x/jour par l'Atlanta Fed)
|
|
||||||
workflow_dispatch: # déclenchement manuel
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
fetch:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
persist-credentials: true
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Fetch Atlanta Fed MPT (options SOFR)
|
|
||||||
run: node .github/scripts/fetch-atlanta-mpt.mjs
|
|
||||||
|
|
||||||
- name: Commit updated data (if changed)
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git add data/atlanta-fed-mpt.json
|
|
||||||
git diff --staged --quiet || git commit -m "chore: update Atlanta Fed MPT data [skip ci]"
|
|
||||||
git push
|
|
||||||
@@ -6,7 +6,6 @@ export const dynamic = "force-dynamic";
|
|||||||
import cpiOverridesRaw from "@/data/cpi_overrides.json";
|
import cpiOverridesRaw from "@/data/cpi_overrides.json";
|
||||||
import rateDecisionsRaw from "@/data/rate_decisions.json";
|
import rateDecisionsRaw from "@/data/rate_decisions.json";
|
||||||
import moneySupplyM3Raw from "@/data/money-supply-m3.json";
|
import moneySupplyM3Raw from "@/data/money-supply-m3.json";
|
||||||
import { getAtlantaFedMpt } from "@/lib/atlantaFedMpt";
|
|
||||||
import { fetchFFThisWeek, fetchFFEvents } from "@/lib/forexfactory";
|
import { fetchFFThisWeek, fetchFFEvents } from "@/lib/forexfactory";
|
||||||
import type { FFEvent } from "@/lib/forexfactory";
|
import type { FFEvent } from "@/lib/forexfactory";
|
||||||
import { fetchTECoreInflation, fetchTEMoMInflation, fetchTEInflationYoY, fetchTECoreCPIMoM, fetchTECoreConsumerPricesIndex, fetchTEPPIMoM, fetchTECoreInflationPages, fetchTEInflationYoYPages, fetchTEAUDCommodityYoY, fetchTEGDPGrowthRate, fetchTEUnemploymentRate, fetchTESTIRRate, fetchTEEmploymentChange } from "@/lib/tecpi";
|
import { fetchTECoreInflation, fetchTEMoMInflation, fetchTEInflationYoY, fetchTECoreCPIMoM, fetchTECoreConsumerPricesIndex, fetchTEPPIMoM, fetchTECoreInflationPages, fetchTEInflationYoYPages, fetchTEAUDCommodityYoY, fetchTEGDPGrowthRate, fetchTEUnemploymentRate, fetchTESTIRRate, fetchTEEmploymentChange } from "@/lib/tecpi";
|
||||||
@@ -1427,7 +1426,6 @@ export async function GET(req: NextRequest) {
|
|||||||
const data = {
|
const data = {
|
||||||
currency, indicators,
|
currency, indicators,
|
||||||
moneySupplyM3: getMoneySupplyM3(currency),
|
moneySupplyM3: getMoneySupplyM3(currency),
|
||||||
atlantaFedMpt: currency === "USD" ? getAtlantaFedMpt() : null,
|
|
||||||
forecasts: {
|
forecasts: {
|
||||||
// CPI — TE calendar forecast (priorité) puis ForexFactory
|
// CPI — TE calendar forecast (priorité) puis ForexFactory
|
||||||
cpi: parseTeF(teCpiForecast?.cpiYoY) ?? ffForecasts.cpi ?? null,
|
cpi: parseTeF(teCpiForecast?.cpiYoY) ?? ffForecasts.cpi ?? null,
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ export default function Dashboard() {
|
|||||||
const [globalMacroSlide, setGlobalMacroSlide] = useState<"mon"|"infl"|"cro"|"empl">("mon");
|
const [globalMacroSlide, setGlobalMacroSlide] = useState<"mon"|"infl"|"cro"|"empl">("mon");
|
||||||
const [globalCardTab, setGlobalCardTab] = useState<"overview"|"mispricing"|"focus">("overview");
|
const [globalCardTab, setGlobalCardTab] = useState<"overview"|"mispricing"|"focus">("overview");
|
||||||
const [globalSignauxSlide, setGlobalSignauxSlide] = useState<"ois"|"cot"|"sent">("ois");
|
const [globalSignauxSlide, setGlobalSignauxSlide] = useState<"ois"|"cot"|"sent">("ois");
|
||||||
const [globalOisChartTab, setGlobalOisChartTab] = useState<"curve"|"probas"|"meetings"|"atlanta">("curve");
|
const [globalOisChartTab, setGlobalOisChartTab] = useState<"curve"|"probas"|"meetings">("curve");
|
||||||
const [macroSyncEnabled, setMacroSyncEnabled] = useState(false);
|
const [macroSyncEnabled, setMacroSyncEnabled] = useState(false);
|
||||||
|
|
||||||
// ── Sentiment multi-paires Myfxbook → {CCY: {longPct, shortPct, pair}} ──────
|
// ── Sentiment multi-paires Myfxbook → {CCY: {longPct, shortPct, pair}} ──────
|
||||||
|
|||||||
+12
-75
@@ -16,7 +16,6 @@ import { biasLabel, calcMacroScore } from "@/lib/scoring";
|
|||||||
import { saveCache, loadCache, formatCacheDate } from "@/lib/localCache";
|
import { saveCache, loadCache, formatCacheDate } from "@/lib/localCache";
|
||||||
import type { Currency, BiasPhase, RateExpectation, MacroSection } from "@/lib/types";
|
import type { Currency, BiasPhase, RateExpectation, MacroSection } from "@/lib/types";
|
||||||
import type { CBRatePath, ILWeeklyDelta } from "@/lib/rateprobability";
|
import type { CBRatePath, ILWeeklyDelta } from "@/lib/rateprobability";
|
||||||
import type { AtlantaFedMpt } from "@/lib/atlantaFedMpt";
|
|
||||||
import type { SentimentEntry, CotEntry } from "@/lib/types";
|
import type { SentimentEntry, CotEntry } from "@/lib/types";
|
||||||
import type { CalendarEvent } from "@/app/api/calendar/route";
|
import type { CalendarEvent } from "@/app/api/calendar/route";
|
||||||
import NarrativeButton from "./NarrativeButton";
|
import NarrativeButton from "./NarrativeButton";
|
||||||
@@ -49,7 +48,6 @@ interface MacroData {
|
|||||||
indicators: Record<string, Ind | null>;
|
indicators: Record<string, Ind | null>;
|
||||||
forecasts?: MacroForecasts | null;
|
forecasts?: MacroForecasts | null;
|
||||||
moneySupplyM3?: MoneySupplyM3 | null;
|
moneySupplyM3?: MoneySupplyM3 | null;
|
||||||
atlantaFedMpt?: AtlantaFedMpt | null;
|
|
||||||
fetchedAt: string;
|
fetchedAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +67,8 @@ interface Props {
|
|||||||
onCardTabChange?: (id: "overview" | "mispricing" | "focus") => void;
|
onCardTabChange?: (id: "overview" | "mispricing" | "focus") => void;
|
||||||
syncSignauxSlide?: "ois" | "cot" | "sent";
|
syncSignauxSlide?: "ois" | "cot" | "sent";
|
||||||
onSignauxSlideChange?: (id: "ois" | "cot" | "sent") => void;
|
onSignauxSlideChange?: (id: "ois" | "cot" | "sent") => void;
|
||||||
syncOisChartTab?: "curve" | "probas" | "meetings" | "atlanta";
|
syncOisChartTab?: "curve" | "probas" | "meetings";
|
||||||
onOisChartTabChange?: (id: "curve" | "probas" | "meetings" | "atlanta") => void;
|
onOisChartTabChange?: (id: "curve" | "probas" | "meetings") => void;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,15 +504,14 @@ const STIR_INSTRUMENT: Partial<Record<string, { instrument: string; exchange: st
|
|||||||
NZD: { instrument: "OIS NZD (swaps)", exchange: "ASX OTC / Bloomberg NDOIS1M", convention: "maturité exacte / réunion", note: "Pas de futures standardisés. RBNZ publie les probas dans ses MPS." },
|
NZD: { instrument: "OIS NZD (swaps)", exchange: "ASX OTC / Bloomberg NDOIS1M", convention: "maturité exacte / réunion", note: "Pas de futures standardisés. RBNZ publie les probas dans ses MPS." },
|
||||||
};
|
};
|
||||||
|
|
||||||
function OISEnhancedBlock({ ratePath, syncChartTab, onChartTabChange, atlantaMpt }: {
|
function OISEnhancedBlock({ ratePath, syncChartTab, onChartTabChange }: {
|
||||||
ratePath: CBRatePath;
|
ratePath: CBRatePath;
|
||||||
syncChartTab?: "curve" | "probas" | "meetings" | "atlanta";
|
syncChartTab?: "curve" | "probas" | "meetings";
|
||||||
onChartTabChange?: (id: "curve" | "probas" | "meetings" | "atlanta") => void;
|
onChartTabChange?: (id: "curve" | "probas" | "meetings") => void;
|
||||||
atlantaMpt?: AtlantaFedMpt | null;
|
|
||||||
}) {
|
}) {
|
||||||
const [localChartTab, setLocalChartTab] = useState<"curve" | "probas" | "meetings" | "atlanta">("curve");
|
const [localChartTab, setLocalChartTab] = useState<"curve" | "probas" | "meetings">("curve");
|
||||||
const chartTab = syncChartTab ?? localChartTab;
|
const chartTab = syncChartTab ?? localChartTab;
|
||||||
const setChartTab = (id: "curve" | "probas" | "meetings" | "atlanta") => {
|
const setChartTab = (id: "curve" | "probas" | "meetings") => {
|
||||||
setLocalChartTab(id);
|
setLocalChartTab(id);
|
||||||
onChartTabChange?.(id);
|
onChartTabChange?.(id);
|
||||||
};
|
};
|
||||||
@@ -626,7 +623,6 @@ function OISEnhancedBlock({ ratePath, syncChartTab, onChartTabChange, atlantaMpt
|
|||||||
{ id: "curve" as const, label: "Courbe" },
|
{ id: "curve" as const, label: "Courbe" },
|
||||||
{ id: "probas" as const, label: "Probabilités" },
|
{ id: "probas" as const, label: "Probabilités" },
|
||||||
{ id: "meetings" as const, label: "Réunions" },
|
{ id: "meetings" as const, label: "Réunions" },
|
||||||
...(ratePath.currency === "USD" && atlantaMpt ? [{ id: "atlanta" as const, label: "Atlanta Fed" }] : []),
|
|
||||||
]).map(t => (
|
]).map(t => (
|
||||||
<button
|
<button
|
||||||
key={t.id}
|
key={t.id}
|
||||||
@@ -824,72 +820,14 @@ function OISEnhancedBlock({ ratePath, syncChartTab, onChartTabChange, atlantaMpt
|
|||||||
Probabilités = somme des % associés à chaque fourchette de taux au-dessus/en-dessous de la fourchette actuelle · Investing.com Fed Rate Monitor, calculées à partir des 30-day Fed Fund Futures (CME).
|
Probabilités = somme des % associés à chaque fourchette de taux au-dessus/en-dessous de la fourchette actuelle · Investing.com Fed Rate Monitor, calculées à partir des 30-day Fed Fund Futures (CME).
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
{(ratePath.currency === "EUR" || ratePath.currency === "GBP") && (
|
||||||
|
<p className="mt-1.5 text-[7px] text-slate-700 leading-snug">
|
||||||
|
Taux implicite déduit des futures {ratePath.currency === "EUR" ? "Euribor 3M (Eurex)" : "SONIA 3M (ICE)"}, cotés sur Investing.com — pas de Rate Monitor pré-calculé comme pour l'USD (inexistant pour la BCE/BoE), donc résolution {ratePath.currency === "EUR" ? "mensuelle (4 échéances cotées)" : "trimestrielle (2 échéances cotées)"} plutôt que par réunion : les réunions rapprochées peuvent partager la même valeur. Probabilité approximée (variation cumulée / 25bps), pas une distribution officielle.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Atlanta Fed MPT — méthodologie alternative (options sur futures SOFR) */}
|
|
||||||
{chartTab === "atlanta" && atlantaMpt && (() => {
|
|
||||||
const front = atlantaMpt.windows[0];
|
|
||||||
if (!front) return null;
|
|
||||||
const holdPct = front.probHikePct !== null && front.probCutPct !== null
|
|
||||||
? Math.max(0, +(100 - front.probHikePct - front.probCutPct).toFixed(1))
|
|
||||||
: null;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="flex items-center justify-between mb-1.5">
|
|
||||||
<span className="text-[7px] text-slate-600 uppercase tracking-wider">Fenêtre SOFR 3M — {front.windowStartIso}</span>
|
|
||||||
<span className="text-[7px] text-slate-700">au {atlantaMpt.asOf}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex h-[6px] rounded-full overflow-hidden bg-slate-700/20 mb-1.5">
|
|
||||||
{front.probCutPct !== null && front.probCutPct > 0 && (
|
|
||||||
<div className="h-full bg-sky-500/60" style={{ width: `${front.probCutPct}%` }} title={`Cut ${front.probCutPct}%`} />
|
|
||||||
)}
|
|
||||||
{holdPct !== null && holdPct > 0 && (
|
|
||||||
<div className="h-full bg-slate-500/40" style={{ width: `${holdPct}%` }} title={`Hold ${holdPct}%`} />
|
|
||||||
)}
|
|
||||||
{front.probHikePct !== null && front.probHikePct > 0 && (
|
|
||||||
<div className="h-full bg-red-500/60" style={{ width: `${front.probHikePct}%` }} title={`Hike ${front.probHikePct}%`} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-3 text-[9px] mb-2">
|
|
||||||
<span className="text-sky-400 font-semibold">Cut {front.probCutPct?.toFixed(1) ?? "—"}%</span>
|
|
||||||
<span className="text-slate-400 font-semibold">Hold {holdPct?.toFixed(1) ?? "—"}%</span>
|
|
||||||
<span className="text-red-400 font-semibold">Hike {front.probHikePct?.toFixed(1) ?? "—"}%</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{front.rate25 !== null && front.rate75 !== null && (
|
|
||||||
<div className="text-[9px] text-slate-500 mb-2">
|
|
||||||
Taux SOFR composé implicite : <span className="text-slate-200 font-mono font-semibold">{(front.rate25 / 100).toFixed(2)}%</span> – <span className="text-slate-200 font-mono font-semibold">{(front.rate75 / 100).toFixed(2)}%</span>
|
|
||||||
<span className="text-slate-600"> (25e–75e percentile{front.rateMode !== null ? `, mode ${(front.rateMode / 100).toFixed(2)}%` : ""})</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<span className="text-[7px] text-slate-600 uppercase tracking-wider">Distribution complète (fenêtre)</span>
|
|
||||||
<div className="space-y-[2px] mt-1">
|
|
||||||
{front.distribution.map(b => {
|
|
||||||
const m = b.rangeLabel.match(/(\d+)bps\s*-\s*(\d+)bps/);
|
|
||||||
const label = m ? `${(parseInt(m[1]) / 100).toFixed(2)}-${(parseInt(m[2]) / 100).toFixed(2)}%` : b.rangeLabel;
|
|
||||||
const isAnchor = b.rangeLabel === front.anchorRange;
|
|
||||||
return (
|
|
||||||
<div key={b.rangeLabel} className={`flex items-center gap-1.5 px-1 py-[2px] rounded ${isAnchor ? "bg-amber-500/8" : ""}`}>
|
|
||||||
<span className={`text-[8px] w-[70px] shrink-0 font-mono tabular-nums ${isAnchor ? "text-amber-300 font-bold" : "text-slate-500"}`}>{label}</span>
|
|
||||||
<div className="flex-1 bg-slate-700/20 rounded-full h-[4px] overflow-hidden">
|
|
||||||
<div className="h-full rounded-full bg-amber-500/50" style={{ width: `${b.probPct}%` }} />
|
|
||||||
</div>
|
|
||||||
<span className="text-[8px] text-slate-400 w-[32px] text-right tabular-nums shrink-0">{b.probPct.toFixed(1)}%</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="mt-1.5 text-[7px] text-slate-700 leading-snug">
|
|
||||||
Distribution déduite des options sur futures SOFR 3 mois (CME), taux SOFR composé sur la fenêtre — méthodologie Atlanta Fed (Market Probability Tracker), alternative aux 30-day Fed Fund Futures. Mise à jour quotidienne.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── IL footer (analyste InvestingLive) + source STIR ───────────────── */}
|
{/* ── IL footer (analyste InvestingLive) + source STIR ───────────────── */}
|
||||||
@@ -1885,7 +1823,6 @@ export default function CurrencyCard({
|
|||||||
ratePath={ratePath}
|
ratePath={ratePath}
|
||||||
syncChartTab={syncOisChartTab}
|
syncChartTab={syncOisChartTab}
|
||||||
onChartTabChange={onOisChartTabChange}
|
onChartTabChange={onOisChartTabChange}
|
||||||
atlantaMpt={data?.atlantaFedMpt}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* OIS — état indisponible */}
|
{/* OIS — état indisponible */}
|
||||||
|
|||||||
@@ -1,324 +0,0 @@
|
|||||||
{
|
|
||||||
"updated_at": "2026-07-08",
|
|
||||||
"source": "https://www.atlantafed.org/cenfis/market-probability-tracker",
|
|
||||||
"note": "Probabilités dérivées des options sur futures SOFR 3 mois (CME) — méthodologie Atlanta Fed, mise à jour quotidienne. Fourchettes exprimées en bps (350bps-375bps = 3.50%-3.75%). Alternative aux 30-day Fed Fund Futures (Investing.com Fed Rate Monitor).",
|
|
||||||
"asOf": "2026-07-07",
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"windowStartIso": "2026-09-16",
|
|
||||||
"anchorRange": "350bps - 375bps",
|
|
||||||
"probCutPct": 1.11,
|
|
||||||
"probHikePct": 72.36,
|
|
||||||
"rate25": 373.91,
|
|
||||||
"rateMean": 389.01,
|
|
||||||
"rateMode": 377.79,
|
|
||||||
"rate75": 402.99,
|
|
||||||
"distribution": [
|
|
||||||
{
|
|
||||||
"rangeLabel": "350bps - 375bps",
|
|
||||||
"probPct": 27.21
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "375bps - 400bps",
|
|
||||||
"probPct": 45.73
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "400bps - 425bps",
|
|
||||||
"probPct": 21.41
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "425bps - 450bps",
|
|
||||||
"probPct": 5.65
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2026-12-16",
|
|
||||||
"anchorRange": "350bps - 375bps",
|
|
||||||
"probCutPct": 6.94,
|
|
||||||
"probHikePct": 74.76,
|
|
||||||
"rate25": 374.76,
|
|
||||||
"rateMean": 402.98,
|
|
||||||
"rateMode": 380.27,
|
|
||||||
"rate75": 430.76,
|
|
||||||
"distribution": [
|
|
||||||
{
|
|
||||||
"rangeLabel": "325bps - 350bps",
|
|
||||||
"probPct": 5.09
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "350bps - 375bps",
|
|
||||||
"probPct": 19.04
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "375bps - 400bps",
|
|
||||||
"probPct": 24.57
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "400bps - 425bps",
|
|
||||||
"probPct": 22.23
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "425bps - 450bps",
|
|
||||||
"probPct": 18.38
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "450bps - 475bps",
|
|
||||||
"probPct": 7.52
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "475bps - 500bps",
|
|
||||||
"probPct": 2.16
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "500bps - 525bps",
|
|
||||||
"probPct": 1.01
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2027-03-17",
|
|
||||||
"anchorRange": "350bps - 375bps",
|
|
||||||
"probCutPct": 12.73,
|
|
||||||
"probHikePct": 74.32,
|
|
||||||
"rate25": 373.96,
|
|
||||||
"rateMean": 408.93,
|
|
||||||
"rateMode": 397.83,
|
|
||||||
"rate75": 447.02,
|
|
||||||
"distribution": [
|
|
||||||
{
|
|
||||||
"rangeLabel": "225bps - 250bps",
|
|
||||||
"probPct": 0.55
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "250bps - 275bps",
|
|
||||||
"probPct": 0.81
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "275bps - 300bps",
|
|
||||||
"probPct": 1.1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "300bps - 325bps",
|
|
||||||
"probPct": 2.25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "325bps - 350bps",
|
|
||||||
"probPct": 6.3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "350bps - 375bps",
|
|
||||||
"probPct": 13.56
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "375bps - 400bps",
|
|
||||||
"probPct": 19.03
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "400bps - 425bps",
|
|
||||||
"probPct": 18.87
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "425bps - 450bps",
|
|
||||||
"probPct": 15.35
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "450bps - 475bps",
|
|
||||||
"probPct": 10.6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "475bps - 500bps",
|
|
||||||
"probPct": 5.95
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "500bps - 525bps",
|
|
||||||
"probPct": 2.97
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "525bps - 550bps",
|
|
||||||
"probPct": 1.62
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "550bps - 575bps",
|
|
||||||
"probPct": 1.04
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2027-06-16",
|
|
||||||
"anchorRange": "350bps - 375bps",
|
|
||||||
"probCutPct": 19.16,
|
|
||||||
"probHikePct": 69.12,
|
|
||||||
"rate25": 363.67,
|
|
||||||
"rateMean": 407,
|
|
||||||
"rateMode": 400.61,
|
|
||||||
"rate75": 452.48,
|
|
||||||
"distribution": [
|
|
||||||
{
|
|
||||||
"rangeLabel": "150bps - 175bps",
|
|
||||||
"probPct": 0.39
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "175bps - 200bps",
|
|
||||||
"probPct": 0.42
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "200bps - 225bps",
|
|
||||||
"probPct": 0.56
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "225bps - 250bps",
|
|
||||||
"probPct": 0.88
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "250bps - 275bps",
|
|
||||||
"probPct": 1.41
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "275bps - 300bps",
|
|
||||||
"probPct": 2.31
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "300bps - 325bps",
|
|
||||||
"probPct": 4.1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "325bps - 350bps",
|
|
||||||
"probPct": 7.54
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "350bps - 375bps",
|
|
||||||
"probPct": 12.3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "375bps - 400bps",
|
|
||||||
"probPct": 16.01
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "400bps - 425bps",
|
|
||||||
"probPct": 16.15
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "425bps - 450bps",
|
|
||||||
"probPct": 13.07
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "450bps - 475bps",
|
|
||||||
"probPct": 9.11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "475bps - 500bps",
|
|
||||||
"probPct": 5.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "500bps - 525bps",
|
|
||||||
"probPct": 3.73
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "525bps - 550bps",
|
|
||||||
"probPct": 2.41
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "550bps - 575bps",
|
|
||||||
"probPct": 1.65
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "575bps - 600bps",
|
|
||||||
"probPct": 1.19
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rangeLabel": "600bps - 625bps",
|
|
||||||
"probPct": 0.86
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2027-09-15",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 349.37,
|
|
||||||
"rateMean": 401.41,
|
|
||||||
"rateMode": 391.24,
|
|
||||||
"rate75": 451.98,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2027-12-15",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 336.41,
|
|
||||||
"rateMean": 394.72,
|
|
||||||
"rateMode": 386.96,
|
|
||||||
"rate75": 448.58,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2028-03-15",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 325.08,
|
|
||||||
"rateMean": 390.04,
|
|
||||||
"rateMode": 382.35,
|
|
||||||
"rate75": 450.08,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2028-06-21",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 315.28,
|
|
||||||
"rateMean": 387.51,
|
|
||||||
"rateMode": 382.48,
|
|
||||||
"rate75": 451.82,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2028-09-20",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 311.02,
|
|
||||||
"rateMean": 386.52,
|
|
||||||
"rateMode": 383.63,
|
|
||||||
"rate75": 452.56,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2028-12-20",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 307.04,
|
|
||||||
"rateMean": 386.45,
|
|
||||||
"rateMode": 376.34,
|
|
||||||
"rate75": 454.85,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2029-03-21",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 291.57,
|
|
||||||
"rateMean": 386.97,
|
|
||||||
"rateMode": 363.95,
|
|
||||||
"rate75": 461.23,
|
|
||||||
"distribution": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"windowStartIso": "2029-06-20",
|
|
||||||
"anchorRange": null,
|
|
||||||
"probCutPct": null,
|
|
||||||
"probHikePct": null,
|
|
||||||
"rate25": 268.96,
|
|
||||||
"rateMean": 387,
|
|
||||||
"rateMode": 354.61,
|
|
||||||
"rate75": 506.12,
|
|
||||||
"distribution": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{"ts":1783543879291,"data":{"current":{"NZD":{"currency":"NZD","nextMeetingProbPct":82,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":62,"publishedDate":"2026-07-03"},"USD":{"currency":"USD","nextMeetingProbPct":17,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":30,"publishedDate":"2026-07-03"},"EUR":{"currency":"EUR","nextMeetingProbPct":28,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":24,"publishedDate":"2026-07-03"},"JPY":{"currency":"JPY","nextMeetingProbPct":1,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":20,"publishedDate":"2026-07-03"},"GBP":{"currency":"GBP","nextMeetingProbPct":7,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":18,"publishedDate":"2026-07-03"},"AUD":{"currency":"AUD","nextMeetingProbPct":15,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":10,"publishedDate":"2026-07-03"},"CAD":{"currency":"CAD","nextMeetingProbPct":9,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":8,"publishedDate":"2026-07-03"},"CHF":{"currency":"CHF","nextMeetingProbPct":4,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":5,"publishedDate":"2026-07-03"}},"prev":{"NZD":{"currency":"NZD","nextMeetingProbPct":62,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":55,"publishedDate":"2026-06-26"},"USD":{"currency":"USD","nextMeetingProbPct":30,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":31,"publishedDate":"2026-06-26"},"EUR":{"currency":"EUR","nextMeetingProbPct":31,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":27,"publishedDate":"2026-06-26"},"GBP":{"currency":"GBP","nextMeetingProbPct":14,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":20,"publishedDate":"2026-06-26"},"JPY":{"currency":"JPY","nextMeetingProbPct":3,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":19,"publishedDate":"2026-06-26"},"CAD":{"currency":"CAD","nextMeetingProbPct":4,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":18,"publishedDate":"2026-06-26"},"AUD":{"currency":"AUD","nextMeetingProbPct":13,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":8,"publishedDate":"2026-06-26"},"CHF":{"currency":"CHF","nextMeetingProbPct":6,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":5,"publishedDate":"2026-06-26"}},"prevDate":"2026-06-26"}}
|
{"ts":1783590012160,"data":{"current":{"NZD":{"currency":"NZD","nextMeetingProbPct":82,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":62,"publishedDate":"2026-07-03"},"USD":{"currency":"USD","nextMeetingProbPct":17,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":30,"publishedDate":"2026-07-03"},"EUR":{"currency":"EUR","nextMeetingProbPct":28,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":24,"publishedDate":"2026-07-03"},"JPY":{"currency":"JPY","nextMeetingProbPct":1,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":20,"publishedDate":"2026-07-03"},"GBP":{"currency":"GBP","nextMeetingProbPct":7,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":18,"publishedDate":"2026-07-03"},"AUD":{"currency":"AUD","nextMeetingProbPct":15,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":10,"publishedDate":"2026-07-03"},"CAD":{"currency":"CAD","nextMeetingProbPct":9,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":8,"publishedDate":"2026-07-03"},"CHF":{"currency":"CHF","nextMeetingProbPct":4,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":5,"publishedDate":"2026-07-03"}},"prev":{"NZD":{"currency":"NZD","nextMeetingProbPct":62,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":55,"publishedDate":"2026-06-26"},"USD":{"currency":"USD","nextMeetingProbPct":30,"nextMeetingIsHike":true,"nextMeetingIsNoChange":false,"bpsYearEnd":31,"publishedDate":"2026-06-26"},"EUR":{"currency":"EUR","nextMeetingProbPct":31,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":27,"publishedDate":"2026-06-26"},"GBP":{"currency":"GBP","nextMeetingProbPct":14,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":20,"publishedDate":"2026-06-26"},"JPY":{"currency":"JPY","nextMeetingProbPct":3,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":19,"publishedDate":"2026-06-26"},"CAD":{"currency":"CAD","nextMeetingProbPct":4,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":18,"publishedDate":"2026-06-26"},"AUD":{"currency":"AUD","nextMeetingProbPct":13,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":8,"publishedDate":"2026-06-26"},"CHF":{"currency":"CHF","nextMeetingProbPct":6,"nextMeetingIsHike":false,"nextMeetingIsNoChange":true,"bpsYearEnd":5,"publishedDate":"2026-06-26"}},"prevDate":"2026-06-26"}}
|
||||||
+120
-57
@@ -7,110 +7,110 @@
|
|||||||
{
|
{
|
||||||
"meeting": "Jul 29",
|
"meeting": "Jul 29",
|
||||||
"meeting_iso": "2026-07-29",
|
"meeting_iso": "2026-07-29",
|
||||||
"implied_rate_post_meeting": 3.833,
|
"implied_rate_post_meeting": 3.8165,
|
||||||
"prob_move_pct": 33,
|
"prob_move_pct": 27,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 8.300000000000018,
|
"change_bps": 6.65,
|
||||||
"num_moves": 0.33200000000000074
|
"num_moves": 0.266
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Sep 16",
|
"meeting": "Sep 16",
|
||||||
"meeting_iso": "2026-09-16",
|
"meeting_iso": "2026-09-16",
|
||||||
"implied_rate_post_meeting": 3.9648,
|
"implied_rate_post_meeting": 3.9441,
|
||||||
"prob_move_pct": 68,
|
"prob_move_pct": 64,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 21.47999999999999,
|
"change_bps": 19.410000000000018,
|
||||||
"num_moves": 0.8591999999999996
|
"num_moves": 0.7764000000000008
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Oct 28",
|
"meeting": "Oct 28",
|
||||||
"meeting_iso": "2026-10-28",
|
"meeting_iso": "2026-10-28",
|
||||||
"implied_rate_post_meeting": 4.028,
|
"implied_rate_post_meeting": 4.0013,
|
||||||
"prob_move_pct": 76,
|
"prob_move_pct": 72,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 27.799999999999958,
|
"change_bps": 25.129999999999963,
|
||||||
"num_moves": 1.1119999999999983
|
"num_moves": 1.0051999999999985
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Dec 9",
|
"meeting": "Dec 9",
|
||||||
"meeting_iso": "2026-12-09",
|
"meeting_iso": "2026-12-09",
|
||||||
"implied_rate_post_meeting": 4.1216,
|
"implied_rate_post_meeting": 4.0998,
|
||||||
"prob_move_pct": 85,
|
"prob_move_pct": 83,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 37.16,
|
"change_bps": 34.98000000000001,
|
||||||
"num_moves": 1.4864
|
"num_moves": 1.3992000000000004
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Jan 27",
|
"meeting": "Jan 27",
|
||||||
"meeting_iso": "2027-01-27",
|
"meeting_iso": "2027-01-27",
|
||||||
"implied_rate_post_meeting": 4.1638,
|
"implied_rate_post_meeting": 4.1415,
|
||||||
"prob_move_pct": 88,
|
"prob_move_pct": 86,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 41.38000000000002,
|
"change_bps": 39.14999999999998,
|
||||||
"num_moves": 1.6552000000000007
|
"num_moves": 1.5659999999999992
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Mar 17",
|
"meeting": "Mar 17",
|
||||||
"meeting_iso": "2027-03-17",
|
"meeting_iso": "2027-03-17",
|
||||||
"implied_rate_post_meeting": 4.2123,
|
"implied_rate_post_meeting": 4.1949,
|
||||||
"prob_move_pct": 90,
|
"prob_move_pct": 89,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 46.22999999999999,
|
"change_bps": 44.48999999999997,
|
||||||
"num_moves": 1.8491999999999995
|
"num_moves": 1.7795999999999987
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Apr 28",
|
"meeting": "Apr 28",
|
||||||
"meeting_iso": "2027-04-28",
|
"meeting_iso": "2027-04-28",
|
||||||
"implied_rate_post_meeting": 4.2278,
|
"implied_rate_post_meeting": 4.207,
|
||||||
"prob_move_pct": 91,
|
"prob_move_pct": 89,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 47.78000000000002,
|
"change_bps": 45.69999999999999,
|
||||||
"num_moves": 1.911200000000001
|
"num_moves": 1.8279999999999996
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Jun 9",
|
"meeting": "Jun 9",
|
||||||
"meeting_iso": "2027-06-09",
|
"meeting_iso": "2027-06-09",
|
||||||
"implied_rate_post_meeting": 4.2172,
|
"implied_rate_post_meeting": 4.1903,
|
||||||
"prob_move_pct": 90,
|
"prob_move_pct": 88,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 46.720000000000006,
|
"change_bps": 44.02999999999997,
|
||||||
"num_moves": 1.8688000000000002
|
"num_moves": 1.761199999999999
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Jul 28",
|
"meeting": "Jul 28",
|
||||||
"meeting_iso": "2027-07-28",
|
"meeting_iso": "2027-07-28",
|
||||||
"implied_rate_post_meeting": 4.1827,
|
"implied_rate_post_meeting": 4.1616,
|
||||||
"prob_move_pct": 85,
|
"prob_move_pct": 84,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 43.26999999999997,
|
"change_bps": 41.16,
|
||||||
"num_moves": 1.7307999999999988
|
"num_moves": 1.6463999999999999
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Sep 15",
|
"meeting": "Sep 15",
|
||||||
"meeting_iso": "2027-09-15",
|
"meeting_iso": "2027-09-15",
|
||||||
"implied_rate_post_meeting": 4.128,
|
"implied_rate_post_meeting": 4.142,
|
||||||
"prob_move_pct": 79,
|
"prob_move_pct": 82,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 37.80000000000001,
|
"change_bps": 39.20000000000003,
|
||||||
"num_moves": 1.5120000000000005
|
"num_moves": 1.5680000000000012
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Oct 27",
|
"meeting": "Oct 27",
|
||||||
"meeting_iso": "2027-10-27",
|
"meeting_iso": "2027-10-27",
|
||||||
"implied_rate_post_meeting": 4.0686,
|
"implied_rate_post_meeting": 4.1072,
|
||||||
"prob_move_pct": 72,
|
"prob_move_pct": 77,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 31.86,
|
"change_bps": 35.71999999999997,
|
||||||
"num_moves": 1.2744
|
"num_moves": 1.4287999999999987
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"meeting": "Dec 8",
|
"meeting": "Dec 8",
|
||||||
"meeting_iso": "2027-12-08",
|
"meeting_iso": "2027-12-08",
|
||||||
"implied_rate_post_meeting": 4.0492,
|
"implied_rate_post_meeting": 4.0853,
|
||||||
"prob_move_pct": 70,
|
"prob_move_pct": 75,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 29.91999999999999,
|
"change_bps": 33.530000000000015,
|
||||||
"num_moves": 1.1967999999999996
|
"num_moves": 1.3412000000000006
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -120,13 +120,40 @@
|
|||||||
"midpoint": 2.4,
|
"midpoint": 2.4,
|
||||||
"rows": [
|
"rows": [
|
||||||
{
|
{
|
||||||
"meeting": "Dec",
|
"meeting": "Jul 23",
|
||||||
"meeting_iso": "2026-12-31",
|
"meeting_iso": "2026-07-23",
|
||||||
"implied_rate_post_meeting": 2.6399999999999997,
|
"implied_rate_post_meeting": 2.47,
|
||||||
"prob_move_pct": 28,
|
"prob_move_pct": 28,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 24,
|
"change_bps": 7,
|
||||||
"num_moves": 0.96
|
"num_moves": 0.28
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Sep 10",
|
||||||
|
"meeting_iso": "2026-09-10",
|
||||||
|
"implied_rate_post_meeting": 2.56,
|
||||||
|
"prob_move_pct": 64,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 16,
|
||||||
|
"num_moves": 0.64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Oct 29",
|
||||||
|
"meeting_iso": "2026-10-29",
|
||||||
|
"implied_rate_post_meeting": 2.61,
|
||||||
|
"prob_move_pct": 84,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 21,
|
||||||
|
"num_moves": 0.84
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Dec 17",
|
||||||
|
"meeting_iso": "2026-12-17",
|
||||||
|
"implied_rate_post_meeting": 2.61,
|
||||||
|
"prob_move_pct": 84,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 21,
|
||||||
|
"num_moves": 0.84
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -136,10 +163,46 @@
|
|||||||
"midpoint": 3.75,
|
"midpoint": 3.75,
|
||||||
"rows": [
|
"rows": [
|
||||||
{
|
{
|
||||||
"meeting": "Dec",
|
"meeting": "Jul 30",
|
||||||
"meeting_iso": "2026-12-31",
|
"meeting_iso": "2026-07-30",
|
||||||
|
"implied_rate_post_meeting": 3.77,
|
||||||
|
"prob_move_pct": 8,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 2,
|
||||||
|
"num_moves": 0.08
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Sep 17",
|
||||||
|
"meeting_iso": "2026-09-17",
|
||||||
"implied_rate_post_meeting": 3.93,
|
"implied_rate_post_meeting": 3.93,
|
||||||
"prob_move_pct": 7,
|
"prob_move_pct": 72,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 18,
|
||||||
|
"num_moves": 0.72
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Nov 5",
|
||||||
|
"meeting_iso": "2026-11-05",
|
||||||
|
"implied_rate_post_meeting": 3.93,
|
||||||
|
"prob_move_pct": 72,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 18,
|
||||||
|
"num_moves": 0.72
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Dec 17",
|
||||||
|
"meeting_iso": "2026-12-17",
|
||||||
|
"implied_rate_post_meeting": 3.93,
|
||||||
|
"prob_move_pct": 72,
|
||||||
|
"prob_is_cut": false,
|
||||||
|
"change_bps": 18,
|
||||||
|
"num_moves": 0.72
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meeting": "Feb 4",
|
||||||
|
"meeting_iso": "2027-02-04",
|
||||||
|
"implied_rate_post_meeting": 3.93,
|
||||||
|
"prob_move_pct": 72,
|
||||||
"prob_is_cut": false,
|
"prob_is_cut": false,
|
||||||
"change_bps": 18,
|
"change_bps": 18,
|
||||||
"num_moves": 0.72
|
"num_moves": 0.72
|
||||||
@@ -228,7 +291,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fetchedAt": "2026-07-09T08:20:31.516Z",
|
"fetchedAt": "2026-07-09T09:45:09.636Z",
|
||||||
"snapshots": [
|
"snapshots": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
// lib/atlantaFedMpt.ts
|
|
||||||
// Atlanta Fed Market Probability Tracker — méthodologie alternative aux 30-day
|
|
||||||
// Fed Fund Futures (Investing.com Fed Rate Monitor) : distribution du niveau
|
|
||||||
// de taux Fed déduite des options sur futures SOFR 3 mois (CME). Donnée
|
|
||||||
// statique maintenue par .github/workflows/fetch-atlanta-mpt.yml (quotidien).
|
|
||||||
// Source : https://www.atlantafed.org/cenfis/market-probability-tracker
|
|
||||||
|
|
||||||
import atlantaMptRaw from "@/data/atlanta-fed-mpt.json";
|
|
||||||
|
|
||||||
export interface AtlantaMptDistributionBucket {
|
|
||||||
rangeLabel: string; // "375bps - 400bps"
|
|
||||||
probPct: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AtlantaMptWindow {
|
|
||||||
windowStartIso: string; // début de la fenêtre 3 mois référencée par le contrat SOFR
|
|
||||||
anchorRange: string | null; // fourchette cible FOMC à la date d'observation
|
|
||||||
probCutPct: number | null;
|
|
||||||
probHikePct: number | null;
|
|
||||||
rate25: number | null; // bps
|
|
||||||
rateMean: number | null; // bps
|
|
||||||
rateMode: number | null; // bps
|
|
||||||
rate75: number | null; // bps
|
|
||||||
distribution: AtlantaMptDistributionBucket[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AtlantaFedMpt {
|
|
||||||
updated_at: string;
|
|
||||||
asOf: string; // date d'observation des données (publication Atlanta Fed)
|
|
||||||
source: string;
|
|
||||||
note: string;
|
|
||||||
windows: AtlantaMptWindow[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAtlantaFedMpt(): AtlantaFedMpt | null {
|
|
||||||
try {
|
|
||||||
const data = atlantaMptRaw as AtlantaFedMpt;
|
|
||||||
if (!data?.windows?.length) return null;
|
|
||||||
return data;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user