mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-08-18 15:08:05 +00:00
feat: calendrier économique TE+Investing, OIS SNB, yields 10Y, taux directeurs corrects
Calendrier économique - Nouvelles sources : TE HTML scraping (483 events/2 sem.) + Investing.com en co-primaires - Dédupe déterministe par clé currency+category+date (±1j pour policy_rate) - Filtre catégorie "other", filtre discours CB (fix doublon TE vs Investing) - CHF/Switzerland via page séparée TE (hors G20) - Fenêtre 14 jours avec ?startDate=&endDate= passés à TE - ForexFactory+FRED en secours uniquement si les deux scrapers tombent à vide Probabilités OIS - rateprobability.com (7 CBs : FED/ECB/BOJ/BOE/BOC/RBA/RBNZ) - investinglive.com (Dellamotta) : scan URL-date 14 jours → couvre SNB/CHF manquant - SNB : 3% probabilité hausse au 19 juin 2026 (source : IL article 2026-05-29) - rate_expectations.json MAJ : RBNZ 79% hike (corrigé depuis 70% no-change stale) - Dédup ±1 jour pour policy_rate (fix doublon SNB TE-18/06 vs IL-19/06) Taux directeurs - USD : scrapeTeRate() = 3.75% (fin midpoint FRED 3.625%) - AUD prev : 4.10% (corrigé depuis 4.60%) - NZD/CHF/JPY/CAD : cohérents avec TE officiel Yields 10Y souverains - Nouvelle lib lib/tebonds.ts : scrape TE bonds, données du jour, cache 1h - Remplace FRED IRLTLT01XXM156N mensuel (JPY/CHF/AUD/NZD avaient 1 mois de retard) - 8 devises + spread vs USD calculé automatiquement - /api/yields et /api/drivers utilisent la même lib Drivers globaux - BTC : ticker/price Binance (plus précis que 24hr lastPrice) - HY Spread cache : 86400s → 3600s (données FRED du jour) - DriversBar : suppression affichage direct US 10Y, tooltip Crb 2-10 affiche US10Y+US2Y Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3a39904ce5
commit
eb416be780
@@ -0,0 +1,84 @@
|
||||
// ── ForexFactory calendar — shared fetch utility ──────────────────────────────
|
||||
// Utilisé par /api/macro (PMI + forecasts) et /api/calendar (calendrier complet).
|
||||
//
|
||||
// Disponibilité :
|
||||
// • ff_calendar_thisweek.json : toujours disponible
|
||||
// • ff_calendar_nextweek.json : disponible du lundi au samedi matin environ
|
||||
// → Le samedi soir / dimanche matin le fichier est en 404 (FF ne l'a pas encore publié)
|
||||
|
||||
export interface FFEvent {
|
||||
title: string;
|
||||
country: string; // "USD", "EUR", "GBP", etc.
|
||||
date: string; // ISO string: "2026-05-29T08:30:00-04:00"
|
||||
impact: string; // "High", "Medium", "Low", "Holiday"
|
||||
actual: string;
|
||||
forecast: string;
|
||||
previous: string;
|
||||
}
|
||||
|
||||
// Cache séparé par semaine pour un retry rapide si nextweek est indisponible
|
||||
let _cacheThisWeek: { events: FFEvent[]; ts: number } | null = null;
|
||||
let _cacheNextWeek: { events: FFEvent[]; ts: number; ok: boolean } | null = null;
|
||||
|
||||
const TTL_OK = 3_600_000; // 1h si le JSON est dispo
|
||||
const TTL_RETRY = 300_000; // 5 min si le JSON était absent (réessaie fréquemment)
|
||||
|
||||
async function fetchFFWeek(week: "thisweek" | "nextweek"): Promise<FFEvent[]> {
|
||||
try {
|
||||
const url = `https://nfs.faireconomy.media/ff_calendar_${week}.json`;
|
||||
// cache: "no-store" pour éviter que Next.js mette en cache une 404
|
||||
const res = await fetch(url, {
|
||||
cache: "no-store",
|
||||
headers: { "User-Agent": "Mozilla/5.0 (compatible; ForexDashboard/1.0)" },
|
||||
});
|
||||
if (!res.ok) return [];
|
||||
const text = await res.text();
|
||||
const trimmed = text.trim();
|
||||
// Rejeter silencieusement les réponses HTML (404/503 pages)
|
||||
if (!trimmed.startsWith("[")) return [];
|
||||
return JSON.parse(trimmed) as FFEvent[];
|
||||
} catch { return []; }
|
||||
}
|
||||
|
||||
/** Retourne les events ForexFactory de cette semaine + semaine prochaine (si dispo). */
|
||||
export async function fetchFFEvents(): Promise<FFEvent[]> {
|
||||
const now = Date.now();
|
||||
|
||||
// Fetch thisweek et nextweek en parallèle pour réduire la latence
|
||||
const [thisWeek, nextWeek] = await Promise.all([
|
||||
(async () => {
|
||||
if (_cacheThisWeek && now - _cacheThisWeek.ts <= TTL_OK) return _cacheThisWeek.events;
|
||||
const events = await fetchFFWeek("thisweek");
|
||||
_cacheThisWeek = { events, ts: now };
|
||||
return events;
|
||||
})(),
|
||||
(async () => {
|
||||
const ttl = _cacheNextWeek?.ok ? TTL_OK : TTL_RETRY;
|
||||
if (_cacheNextWeek && now - _cacheNextWeek.ts <= ttl) return _cacheNextWeek.events;
|
||||
const events = await fetchFFWeek("nextweek");
|
||||
_cacheNextWeek = { events, ts: now, ok: events.length > 0 };
|
||||
return events;
|
||||
})(),
|
||||
]);
|
||||
|
||||
return [...thisWeek, ...nextWeek];
|
||||
}
|
||||
|
||||
/** Events de cette semaine seulement (pour PMI/forecasts macro). */
|
||||
export async function fetchFFThisWeek(): Promise<FFEvent[]> {
|
||||
const all = await fetchFFEvents();
|
||||
const monday = new Date();
|
||||
monday.setDate(monday.getDate() - monday.getDay() + 1);
|
||||
monday.setHours(0, 0, 0, 0);
|
||||
const nextMonday = new Date(monday);
|
||||
nextMonday.setDate(monday.getDate() + 7);
|
||||
return all.filter((e) => {
|
||||
const d = new Date(e.date);
|
||||
return d >= monday && d < nextMonday;
|
||||
});
|
||||
}
|
||||
|
||||
/** Indique si les données de la semaine prochaine sont disponibles. */
|
||||
export function nextWeekAvailable(): boolean {
|
||||
return (_cacheNextWeek?.ok) ?? false;
|
||||
}
|
||||
Reference in New Issue
Block a user