mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-07-27 20:37:45 +00:00
fix: actualités — tri chronologique cassé + 3 flux RSS morts remplacés
Tri (lib/newsfeed.ts + components/NewsTab.tsx) : Un bonus "+3h pour les catégories prioritaires" (Guerre/Chef d'État/Crise…) était appliqué avant le tri par date. En temps normal ça remonte discrètement une poignée d'articles importants ; mais en période de crise soutenue (conflit Moyen-Orient actuel), la quasi-totalité des articles matche une de ces catégories — le bonus s'applique presque partout et casse l'ordre chronologique au lieu de l'affiner, produisant des blocs par source de plus en plus vieux au lieu d'un flux unique correctement entrelacé. Vérifié en direct : 54 articles avant fix avec des dizaines d'inversions chronologiques, 0 après. Le badge visuel "⚡ Prioritaire" reste pour signaler l'importance sans trahir la fraîcheur réelle. Flux RSS (lib/newsfeed.ts RSS_FEEDS) — 3 des 6 sources ne contribuaient plus rien, vérifié en direct : - ForexLive : /feed/news est une coquille vide (0 <item>) depuis leur migration Nuxt.js vers investinglive.com — déjà couvert par le scraper dédié fetchInvestingLiveNews(), aucune perte réelle en le retirant. - MarketWatch : l'ancien miroir dowjones.io ne sert que des articles vieux de 1+ an (filtrés par le cutoff 8 jours) → remplacé par l'URL RSS actuelle (marketwatch.com/rss/topstories, testée fraîche). - Reuters : feeds.reuters.com n'existe plus (échec DNS, fermé par Reuters il y a plusieurs années) → remplacé par CNBC Markets (testé frais). Bloomberg (403 anti-bot) et FinancialJuice (site restructuré) restent à zéro, déjà connu et accepté (échecs silencieux gérés par try/catch). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+10
-8
@@ -55,7 +55,7 @@ const HIGH_PRIO = new Set([
|
||||
|
||||
const SOURCE_COLORS: Record<string, string> = {
|
||||
"InvestingLive": "bg-amber-500/20 text-amber-400",
|
||||
"Reuters": "bg-orange-500/20 text-orange-400",
|
||||
"CNBC": "bg-orange-500/20 text-orange-400",
|
||||
"Bloomberg Economics": "bg-sky-500/20 text-sky-400",
|
||||
"Bloomberg CB": "bg-sky-500/20 text-sky-400",
|
||||
"Bloomberg FX": "bg-sky-500/20 text-sky-400",
|
||||
@@ -72,14 +72,16 @@ function formatRelativeTime(isoDate: string): string {
|
||||
}
|
||||
|
||||
// ── Tri ───────────────────────────────────────────────────────────────────────
|
||||
// Score plus élevé = apparaît en premier.
|
||||
// Récence primaire → haute priorité (+3h) → catégorisé (+1h) → bruit sans catégorie (0)
|
||||
|
||||
// Strictement chronologique (score = timestamp). Un bonus "+3h prioritaire /
|
||||
// +1h catégorisé" existait ici, mais en période de crise soutenue la quasi-
|
||||
// totalité des articles matche une catégorie prioritaire (Guerre/Géopolitique/
|
||||
// Chef d'État) : le bonus s'applique alors presque partout et casse l'ordre
|
||||
// chronologique au lieu de l'affiner (des articles plus vieux mais
|
||||
// "prioritaires" passent devant des articles réellement plus récents). Le
|
||||
// badge visuel "⚡ Prioritaire" (NewsCard) signale déjà l'importance sans
|
||||
// trahir la fraîcheur réelle du flux.
|
||||
function scoreItem(item: NewsItem): number {
|
||||
const t = new Date(item.publishedAt).getTime();
|
||||
const isPrio = item.categories.some(c => HIGH_PRIO.has(c));
|
||||
const hasCat = item.categories.length > 0 || item.impacts.length > 0;
|
||||
return t + (isPrio ? 3 * 3_600_000 : hasCat ? 1 * 3_600_000 : 0);
|
||||
return new Date(item.publishedAt).getTime();
|
||||
}
|
||||
|
||||
// ── Composant principal ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"ts":1783520638250,"data":{"current":{},"prev":{},"prevDate":null}}
|
||||
{"ts":1783528251592,"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"}}
|
||||
+23
-15
@@ -675,13 +675,20 @@ async function fetchInvestingLiveNews(): Promise<NewsItem[]> {
|
||||
// ForexLive : commentaires macro en temps réel
|
||||
// MarketWatch : marchés généraux
|
||||
|
||||
// Vérifié en direct (2026-07-08) :
|
||||
// - ForexLive retiré : /feed/news est une coquille vide (0 <item>) depuis leur
|
||||
// migration Nuxt.js vers investinglive.com — déjà couvert par le scraper
|
||||
// dédié fetchInvestingLiveNews() (API réelle), donc pas de perte réelle.
|
||||
// - MarketWatch : l'ancien miroir dowjones.io sert des articles vieux de 1+ an
|
||||
// (tous filtrés par le cutoff 8 jours) → remplacé par l'URL RSS actuelle.
|
||||
// - Reuters : feeds.reuters.com n'existe plus (échec DNS, fermé côté Reuters
|
||||
// il y a plusieurs années) → remplacé par CNBC Markets (flux frais, testé).
|
||||
const RSS_FEEDS: { url: string; source: string }[] = [
|
||||
{ url: "https://www.fxstreet.com/rss/news", source: "FXStreet" },
|
||||
{ url: "https://www.forexlive.com/feed/news", source: "ForexLive" },
|
||||
{ url: "https://feeds.content.dowjones.io/public/rss/mw_realtimeheadlines", source: "MarketWatch" },
|
||||
{ url: "https://finance.yahoo.com/rss/topfinstories", source: "Yahoo Finance" },
|
||||
{ url: "https://feeds.reuters.com/reuters/businessNews", source: "Reuters" },
|
||||
{ url: "https://www.investing.com/rss/news.rss", source: "Investing.com" },
|
||||
{ url: "https://www.fxstreet.com/rss/news", source: "FXStreet" },
|
||||
{ url: "https://www.marketwatch.com/rss/topstories", source: "MarketWatch" },
|
||||
{ url: "https://finance.yahoo.com/rss/topfinstories", source: "Yahoo Finance" },
|
||||
{ url: "https://www.cnbc.com/id/100003114/device/rss/rss.html", source: "CNBC" },
|
||||
{ url: "https://www.investing.com/rss/news.rss", source: "Investing.com" },
|
||||
];
|
||||
|
||||
async function fetchRssFeeds(): Promise<NewsItem[]> {
|
||||
@@ -895,15 +902,16 @@ export async function fetchAllNews(): Promise<NewsItem[]> {
|
||||
return true;
|
||||
});
|
||||
|
||||
const PRIORITY_SET = new Set(["Discours BC", "Décision Taux", "Crise", "Guerre", "Chef d'État", "Probabilités Taux"]);
|
||||
const isPrio = (item: NewsItem) => item.categories.some(c => PRIORITY_SET.has(c));
|
||||
const PRIO_BONUS_MS = 3 * 60 * 60 * 1000; // +3h boost pour les prioritaires
|
||||
|
||||
deduped.sort((a, b) => {
|
||||
const ta = new Date(a.publishedAt).getTime() + (isPrio(a) ? PRIO_BONUS_MS : 0);
|
||||
const tb = new Date(b.publishedAt).getTime() + (isPrio(b) ? PRIO_BONUS_MS : 0);
|
||||
return tb - ta;
|
||||
});
|
||||
// Tri strictement chronologique (décroissant). Un bonus "+3h pour les
|
||||
// catégories prioritaires" existait ici auparavant, mais en période de
|
||||
// crise soutenue (ex. conflit Moyen-Orient) la quasi-totalité des articles
|
||||
// matche "Guerre"/"Géopolitique"/"Chef d'État" — le bonus s'appliquait donc
|
||||
// presque partout et cassait l'ordre chronologique au lieu de l'affiner
|
||||
// (des articles plus anciens mais "prioritaires" passaient devant des
|
||||
// articles réellement plus récents). Le badge visuel "⚡ Prioritaire"
|
||||
// (NewsTab.tsx) reste le bon endroit pour signaler l'importance sans
|
||||
// trahir la fraîcheur réelle du flux.
|
||||
deduped.sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime());
|
||||
|
||||
return deduped;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user