feat: banques centrales (vote+dot plot+previsions), calendrier elargi, fix InvestingLive, M3 auto

Central bank governance (nouvel onglet Banques centrales) :
- lib/centralBankGovernance.ts + app/api/central-bank-sources : scraping live du
  vote de la derniere reunion, dot plot Fed (SEP), et desormais les previsions
  macro (PIB + inflation) publiees par chaque BC elle-meme (Fed SEP, Eurosystem
  staff projections, BoJ Outlook Report PDF, SNB conditional forecast, BoC MPR,
  RBA SMP). GBP/NZD laisses honnetement vides quand aucune source chiffree
  fiable n'est accessible (RBNZ bloque par Cloudflare).
- components/CentralBankSourcesTab.tsx : nouvel onglet avec cards par banque.

Taux directeurs + Money Supply M3 :
- data/rate_decisions.json corrige (JPY, EUR, NZD etc. etaient perimes d'1-2
  decisions) et desormais auto-maintenu : .github/workflows/update-rate-decisions.yml
  (horaire) detecte les changements de taux via Trading Economics et fait
  glisser current -> prev sans perte de donnee.
- data/money-supply-m3.json (nouveau) + .github/workflows/fetch-money-supply.yml
  (hebdo) : M3 par devise (proxy M2 pour l'USD, la Fed ne publiant plus M3
  depuis 2006), affiche dans CurrencyCard.

Calendrier economique elargi :
- lib/calendar-countries.ts, lib/calendar-taxonomy.ts, lib/fxstreetCalendar.ts :
  couverture pays elargie + classification des evenements + source FXStreet.

Fix InvestingLive :
- lib/investinglive.ts : l'ancienne API WordPress (wp-json) renvoyait 404 depuis
  leur migration Nuxt.js -> reecrit vers api.investinglive.com/api/homepage/articles,
  + fix crash silencieux (Tldr pas toujours un tableau).

Divers :
- .vercel/ ajoute au .gitignore (ne doit jamais etre commite, cf. son propre README).
- scripts/ (lancement PWA, push env Vercel), captures d'ecran, cache InvestingLive.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
caty21
2026-07-08 16:47:59 +02:00
co-authored by Claude Sonnet 5
parent 82a732fbdf
commit 0657b50c07
38 changed files with 3257 additions and 443 deletions
+6 -22
View File
@@ -9,12 +9,10 @@ import { saveCache, loadCache, formatCacheDate } from "@/lib/localCache";
import CurrencyCard from "@/components/CurrencyCard";
import DriversBar from "@/components/DriversBar";
import CalendarTab from "@/components/CalendarTab";
import SentimentPairsTab from "@/components/SentimentPairsTab";
import YieldsTab from "@/components/YieldsTab";
import NewsTab from "@/components/NewsTab";
import CotTab from "@/components/CotTab";
import ReportTab from "@/components/ReportTab";
import IdeesTab from "@/components/IdeesTab";
import CentralBankSourcesTab from "@/components/CentralBankSourcesTab";
import { TvAdvancedChart } from "@/components/TvChart";
import type { CalendarEvent } from "@/app/api/calendar/route";
import type { NewsItem } from "@/app/api/news/route";
@@ -30,12 +28,11 @@ export default function Dashboard() {
const [cot, setCot] = useState<Record<string, CotEntry> | null>(null);
const [calEvents, setCalEvents] = useState<CalendarEvent[]>([]);
const [nextWeekAvail, setNextWeekAvail] = useState(false);
const [activeTab, setActiveTab] = useState<"dashboard" | "calendar" | "pairs" | "yields" | "news" | "cot" | "report" | "markets" | "idees">("dashboard");
const [activeTab, setActiveTab] = useState<"dashboard" | "calendar" | "news" | "cot" | "markets" | "idees" | "cbsources">("dashboard");
const [newsItems, setNewsItems] = useState<NewsItem[]>([]);
const [newsLoading, setNewsLoading] = useState(false);
const [cotHistory, setCotHistory] = useState<CotHistory | null>(null);
const [cotLoading, setCotLoading] = useState(false);
const [rawSymbols, setRawSymbols] = useState<Array<{ name: string; longPercentage: number; shortPercentage: number; longVolume: number; shortVolume: number; longPositions: number; shortPositions: number; totalPositions: number; avgLongPrice?: number; avgShortPrice?: number }> | null>(null);
const [rateProbabilities, setRateProbabilities] = useState<RateProbData | null>(null);
const [lastRefresh, setLastRefresh] = useState<Date>(new Date());
const [loading, setLoading] = useState(true);
@@ -200,7 +197,6 @@ export default function Dashboard() {
// ── Sentiment Myfxbook ────────────────────────────────────────────────
if (sentimentRes.status === "fulfilled" && !sentimentRes.value?.error && sentimentRes.value?.symbols) {
const syms = sentimentRes.value.symbols as Array<{ name: string; longPercentage: number; shortPercentage: number; longVolume: number; shortVolume: number; longPositions: number; shortPositions: number; totalPositions: number; avgLongPrice?: number; avgShortPrice?: number }>;
setRawSymbols(syms);
const mapped = parseSentimentSymbols(syms);
setSentiment(mapped);
saveCache("sentiment", mapped);
@@ -347,7 +343,7 @@ export default function Dashboard() {
{/* Tab navigation */}
<div className="flex gap-0 border-b border-slate-800 mb-4">
{(["dashboard", "markets", "idees", "calendar", "pairs", "yields", "news", "cot", "report"] as const).map((tab) => (
{(["dashboard", "markets", "idees", "calendar", "cbsources", "news", "cot"] as const).map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
@@ -361,11 +357,9 @@ export default function Dashboard() {
: tab === "markets" ? "🌍 Marchés"
: tab === "idees" ? "💡 Idées"
: tab === "calendar" ? "📅 Calendrier"
: tab === "pairs" ? "↕ Paires"
: tab === "yields" ? "📈 Yields 10Y"
: tab === "cbsources" ? "🏛️ Banques centrales"
: tab === "news" ? "📰 Actualités"
: tab === "cot" ? "📊 COT"
: "📋 Rapport"}
: "📊 COT"}
</button>
))}
</div>
@@ -619,13 +613,7 @@ export default function Dashboard() {
<CalendarTab events={calEvents} loading={loading} nextWeekAvail={nextWeekAvail} />
)}
{activeTab === "pairs" && (
<SentimentPairsTab symbols={rawSymbols} />
)}
{activeTab === "yields" && (
<YieldsTab yieldsData={yields} fxDayPct={yields?.fxDayPct ?? null} />
)}
{activeTab === "cbsources" && <CentralBankSourcesTab />}
{activeTab === "news" && (
<NewsTab items={newsItems} loading={newsLoading} onRefresh={refreshNews} />
@@ -637,10 +625,6 @@ export default function Dashboard() {
{activeTab === "idees" && <IdeesTab />}
{activeTab === "report" && (
<ReportTab calEvents={calEvents} drivers={drivers} cotHistory={cotHistory} />
)}
{/* Legend */}
<div className="mt-4 pt-3 border-t border-slate-800 flex items-center gap-5 flex-wrap text-[10px] text-slate-600">
<div className="flex items-center gap-1.5"><span className="w-2 h-2 rounded-full bg-emerald-500 shrink-0" /> Haussier / Sous-évalué</div>