mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-08-22 17:08:05 +00:00
auto: sync 2026-06-02 23:01
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@ export const metadata: Metadata = {
|
|||||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<body className="min-h-screen bg-gray-50">{children}</body>
|
<body className="min-h-screen bg-[#090e1a]">{children}</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-19
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState, useCallback } from "react";
|
import { useEffect, useState, useCallback } from "react";
|
||||||
import { RefreshCw, Zap, Database } from "lucide-react";
|
import { RefreshCw, Zap, Database, Activity } from "lucide-react";
|
||||||
import { CURRENCIES, CURRENCY_META } from "@/lib/constants";
|
import { CURRENCIES, CURRENCY_META } from "@/lib/constants";
|
||||||
import type { Currency, DriverData, SentimentEntry, CotEntry } from "@/lib/types";
|
import type { Currency, DriverData, SentimentEntry, CotEntry } from "@/lib/types";
|
||||||
import type { RateProbData } from "@/lib/rateprobability";
|
import type { RateProbData } from "@/lib/rateprobability";
|
||||||
@@ -225,37 +225,42 @@ export default function Dashboard() {
|
|||||||
return (
|
return (
|
||||||
<div className="max-w-[1600px] mx-auto px-4 py-4">
|
<div className="max-w-[1600px] mx-auto px-4 py-4">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<header className="flex items-center justify-between mb-4">
|
<header className="flex items-center justify-between mb-4 bg-slate-950/80 border border-slate-800 rounded-xl px-5 py-3">
|
||||||
<div>
|
<div className="flex items-center gap-3">
|
||||||
<h1 className="text-xl font-semibold text-gray-900">
|
<div className="w-7 h-7 rounded-lg bg-amber-500 flex items-center justify-center shrink-0">
|
||||||
Forex Macro Dashboard
|
<Activity size={15} className="text-black" />
|
||||||
</h1>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="text-sm font-bold text-white tracking-tight">MacroFlow</span>
|
||||||
|
<span className="ml-2 text-[10px] text-slate-600 uppercase tracking-widest">Forex · Macro · Mispricing</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{divergenceCount > 0 && (
|
{divergenceCount > 0 && (
|
||||||
<div className="flex items-center gap-1.5 bg-amber-50 border border-amber-200 rounded-full px-3 py-1.5">
|
<div className="flex items-center gap-1.5 bg-amber-500/10 border border-amber-500/20 rounded-full px-3 py-1.5">
|
||||||
<Zap size={13} className="text-amber-600" />
|
<Zap size={12} className="text-amber-400" />
|
||||||
<span className="text-xs font-medium text-amber-700">
|
<span className="text-xs font-medium text-amber-400">
|
||||||
{divergenceCount} divergence{divergenceCount > 1 ? "s" : ""} active{divergenceCount > 1 ? "s" : ""}
|
{divergenceCount} divergence{divergenceCount > 1 ? "s" : ""} active{divergenceCount > 1 ? "s" : ""}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 text-xs text-gray-400">
|
<div className="flex items-center gap-2 text-[11px] text-slate-500">
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
|
||||||
{driversFromCache && driversCacheAge && (
|
{driversFromCache && driversCacheAge && (
|
||||||
<span className="flex items-center gap-0.5 text-amber-500" title="Marchés affichés depuis le cache local">
|
<span className="flex items-center gap-0.5 text-amber-500" title="Marchés depuis le cache local">
|
||||||
<Database size={11} />
|
<Database size={11} />
|
||||||
<span>cache {driversCacheAge}</span>
|
<span>cache {driversCacheAge}</span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{lastRefresh.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" })}
|
<span>{lastRefresh.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" })}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={refresh}
|
onClick={refresh}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="flex items-center gap-1.5 text-xs text-gray-600 hover:text-gray-900 disabled:opacity-50"
|
className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-slate-200 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
<RefreshCw size={13} className={loading ? "animate-spin" : ""} />
|
<RefreshCw size={13} className={loading ? "animate-spin" : ""} />
|
||||||
{loading ? "Chargement…" : "Rafraîchir"}
|
{loading ? "Chargement…" : "Rafraîchir"}
|
||||||
@@ -264,15 +269,15 @@ export default function Dashboard() {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Tab navigation */}
|
{/* Tab navigation */}
|
||||||
<div className="flex gap-0 border-b border-gray-200 mb-4">
|
<div className="flex gap-0 border-b border-slate-800 mb-4">
|
||||||
{(["dashboard", "calendar", "pairs", "yields"] as const).map((tab) => (
|
{(["dashboard", "calendar", "pairs", "yields"] as const).map((tab) => (
|
||||||
<button
|
<button
|
||||||
key={tab}
|
key={tab}
|
||||||
onClick={() => setActiveTab(tab)}
|
onClick={() => setActiveTab(tab)}
|
||||||
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
||||||
activeTab === tab
|
activeTab === tab
|
||||||
? "border-blue-600 text-blue-600"
|
? "border-amber-500 text-amber-400"
|
||||||
: "border-transparent text-gray-500 hover:text-gray-700"
|
: "border-transparent text-slate-500 hover:text-slate-300"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{tab === "dashboard" ? "Dashboard"
|
{tab === "dashboard" ? "Dashboard"
|
||||||
@@ -298,8 +303,8 @@ export default function Dashboard() {
|
|||||||
key={currency}
|
key={currency}
|
||||||
className={`flex items-center gap-1 text-xs px-2 py-1 rounded-full border font-medium ${
|
className={`flex items-center gap-1 text-xs px-2 py-1 rounded-full border font-medium ${
|
||||||
score < 0
|
score < 0
|
||||||
? "bg-red-50 border-red-200 text-red-700"
|
? "bg-red-500/10 border-red-500/20 text-red-400"
|
||||||
: "bg-green-50 border-green-200 text-green-700"
|
: "bg-emerald-500/10 border-emerald-500/20 text-emerald-400"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Zap size={10} />
|
<Zap size={10} />
|
||||||
@@ -353,7 +358,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="mt-4 text-center text-xs text-gray-400 space-y-1">
|
<footer className="mt-4 text-center text-xs text-slate-600 space-y-1">
|
||||||
<p>
|
<p>
|
||||||
Sources: FRED · ECB · BoE · BoC · CFTC · Frankfurter · Myfxbook · ForexFactory
|
Sources: FRED · ECB · BoE · BoC · CFTC · Frankfurter · Myfxbook · ForexFactory
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
+98
-161
@@ -2,86 +2,19 @@
|
|||||||
|
|
||||||
import { useState, useRef, useCallback } from "react";
|
import { useState, useRef, useCallback } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
|
import { AlertTriangle } from "lucide-react";
|
||||||
import type { DriverData } from "@/lib/types";
|
import type { DriverData } from "@/lib/types";
|
||||||
|
|
||||||
interface Props { drivers: DriverData }
|
interface Props { drivers: DriverData }
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
function fmt(v: number | null, dec: number, unit = "") {
|
function fmt(v: number | null, dec: number, unit = "") {
|
||||||
if (v === null) return "—";
|
if (v === null) return "—";
|
||||||
return `${v.toLocaleString("fr-FR", { minimumFractionDigits: dec, maximumFractionDigits: dec })}${unit}`;
|
return `${v.toLocaleString("fr-FR", { minimumFractionDigits: dec, maximumFractionDigits: dec })}${unit}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeltaTag({ delta, pct = false, dec = 2 }: { delta: number | null; pct?: boolean; dec?: number }) {
|
|
||||||
if (delta === null) return null;
|
|
||||||
const pos = delta > 0;
|
|
||||||
const neg = delta < 0;
|
|
||||||
const color = pos ? "text-emerald-600" : neg ? "text-red-500" : "text-gray-400";
|
|
||||||
const arrow = pos ? "▲" : neg ? "▼" : "▬";
|
|
||||||
return (
|
|
||||||
<span className={`text-[10px] font-medium tabular-nums ml-0.5 ${color}`}>
|
|
||||||
{arrow}{Math.abs(delta).toFixed(dec)}{pct ? "%" : ""}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Tooltip via portal (évite le clipping de overflow-x-auto) ─────────────────
|
|
||||||
|
|
||||||
interface TooltipState { x: number; y: number }
|
interface TooltipState { x: number; y: number }
|
||||||
|
|
||||||
function TooltipLabel({ label, tooltip }: { label: string; tooltip: string }) {
|
function D({ label, value, dec = 2, unit = "", delta, deltaPct, deltaDec, tooltip }: {
|
||||||
const [tip, setTip] = useState<TooltipState | null>(null);
|
|
||||||
const ref = useRef<HTMLSpanElement>(null);
|
|
||||||
|
|
||||||
const show = useCallback(() => {
|
|
||||||
if (!ref.current) return;
|
|
||||||
const r = ref.current.getBoundingClientRect();
|
|
||||||
setTip({ x: r.left + r.width / 2, y: r.top });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const hide = useCallback(() => setTip(null), []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<span
|
|
||||||
ref={ref}
|
|
||||||
onMouseEnter={show}
|
|
||||||
onMouseLeave={hide}
|
|
||||||
className="flex items-center gap-0.5 cursor-help whitespace-nowrap"
|
|
||||||
>
|
|
||||||
<span className="text-[9px] text-gray-400 leading-tight">{label}</span>
|
|
||||||
<span className="w-3 h-3 flex-shrink-0 rounded-full border border-gray-300 text-gray-400 text-[8px] flex items-center justify-center leading-none select-none">
|
|
||||||
i
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{tip && typeof document !== "undefined" && createPortal(
|
|
||||||
<div
|
|
||||||
className="fixed z-[9999] bg-gray-800 text-white text-[10px] rounded px-2.5 py-2 w-60 leading-snug shadow-xl pointer-events-none text-left"
|
|
||||||
style={{
|
|
||||||
left: tip.x,
|
|
||||||
top: tip.y - 8,
|
|
||||||
transform: "translate(-50%, -100%)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tooltip}
|
|
||||||
{/* Flèche en bas */}
|
|
||||||
<span
|
|
||||||
className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-gray-800"
|
|
||||||
style={{ marginTop: 0 }}
|
|
||||||
/>
|
|
||||||
</div>,
|
|
||||||
document.body,
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Un indicateur : label · valeur · delta — hauteur fixe garantie */
|
|
||||||
function M({
|
|
||||||
label, value, dec = 2, unit = "", delta, deltaPct, deltaDec, tooltip,
|
|
||||||
}: {
|
|
||||||
label: string;
|
label: string;
|
||||||
value: number | null;
|
value: number | null;
|
||||||
dec?: number;
|
dec?: number;
|
||||||
@@ -91,38 +24,66 @@ function M({
|
|||||||
deltaDec?: number;
|
deltaDec?: number;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
}) {
|
}) {
|
||||||
|
const [tip, setTip] = useState<TooltipState | null>(null);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const show = useCallback(() => {
|
||||||
|
if (!ref.current) return;
|
||||||
|
const r = ref.current.getBoundingClientRect();
|
||||||
|
setTip({ x: r.left + r.width / 2, y: r.top });
|
||||||
|
}, []);
|
||||||
|
const hide = useCallback(() => setTip(null), []);
|
||||||
|
|
||||||
|
const pos = delta != null && delta > 0;
|
||||||
|
const neg = delta != null && delta < 0;
|
||||||
|
const dColor = pos ? "text-emerald-400" : neg ? "text-red-400" : "text-slate-500";
|
||||||
|
const dArrow = pos ? "▲" : neg ? "▼" : "";
|
||||||
|
const dFmt = delta != null
|
||||||
|
? `${Math.abs(delta).toFixed(deltaDec ?? dec)}${deltaPct ? "%" : ""}`
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center text-center flex-shrink-0">
|
<>
|
||||||
{/* Ligne 1 — label */}
|
<div
|
||||||
<div className="h-4 flex items-center justify-center">
|
ref={ref}
|
||||||
{tooltip
|
onMouseEnter={tooltip ? show : undefined}
|
||||||
? <TooltipLabel label={label} tooltip={tooltip} />
|
onMouseLeave={tooltip ? hide : undefined}
|
||||||
: <span className="text-[9px] text-gray-400 whitespace-nowrap leading-tight">{label}</span>
|
className={`flex items-center gap-1.5 shrink-0 ${tooltip ? "cursor-help" : ""}`}
|
||||||
}
|
>
|
||||||
</div>
|
<span className="text-slate-500 text-[11px]">{label}</span>
|
||||||
{/* Ligne 2 — valeur */}
|
<span className="text-slate-100 font-semibold tabular-nums text-[11px]">
|
||||||
<div className="h-5 flex items-center justify-center">
|
|
||||||
<span className={`text-sm font-semibold tabular-nums ${value === null ? "text-gray-300" : "text-gray-800"}`}>
|
|
||||||
{fmt(value, dec, unit)}
|
{fmt(value, dec, unit)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
{dFmt && (
|
||||||
{/* Ligne 3 — delta (slot réservé = alignement garanti) */}
|
<span className={`text-[10px] font-medium tabular-nums ${dColor}`}>
|
||||||
<div className="h-4 flex items-center justify-center">
|
{dArrow}{dFmt}
|
||||||
{delta !== undefined && delta !== null && (
|
</span>
|
||||||
<DeltaTag delta={delta} pct={deltaPct} dec={deltaDec ?? dec} />
|
)}
|
||||||
|
{tooltip && (
|
||||||
|
<span className="w-3 h-3 rounded-full border border-slate-700 text-slate-600 text-[7px] flex items-center justify-center leading-none select-none shrink-0">
|
||||||
|
i
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
{tip && typeof document !== "undefined" && createPortal(
|
||||||
|
<div
|
||||||
|
className="fixed z-[9999] bg-slate-800 border border-slate-700 text-slate-300 text-[10px] rounded-lg px-3 py-2 w-60 leading-snug shadow-xl pointer-events-none whitespace-pre-line"
|
||||||
|
style={{ left: tip.x, top: tip.y - 8, transform: "translate(-50%, -100%)" }}
|
||||||
|
>
|
||||||
|
{tooltip}
|
||||||
|
<span className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-slate-800" />
|
||||||
|
</div>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Séparateur vertical */
|
|
||||||
function VSep() {
|
function VSep() {
|
||||||
return <div className="w-px bg-gray-100 self-stretch mx-2 flex-shrink-0" />;
|
return <div className="w-px h-3.5 bg-slate-700/60 shrink-0 mx-0.5" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Composant principal ───────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
export default function DriversBar({ drivers }: Props) {
|
export default function DriversBar({ drivers }: Props) {
|
||||||
const {
|
const {
|
||||||
vix, vixDelta,
|
vix, vixDelta,
|
||||||
@@ -134,90 +95,66 @@ export default function DriversBar({ drivers }: Props) {
|
|||||||
silver, silverDelta,
|
silver, silverDelta,
|
||||||
brent, brentDelta,
|
brent, brentDelta,
|
||||||
wti, wtiDelta,
|
wti, wtiDelta,
|
||||||
} = drivers as DriverData & { dxy?: number | null };
|
} = drivers;
|
||||||
|
|
||||||
const dxy = (drivers as DriverData & { dxy?: number | null }).dxy ?? null;
|
const dxy = (drivers as DriverData & { dxy?: number | null }).dxy ?? null;
|
||||||
const riskOff = (vix ?? 0) > 25 || (hySpread ?? 0) > 500;
|
const dxyDelta = (drivers as DriverData & { dxyDelta?: number | null }).dxyDelta ?? null;
|
||||||
|
const riskOff = (vix ?? 0) > 25 || (hySpread ?? 0) > 500;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 bg-white border border-gray-200 rounded-xl px-5 py-3">
|
<div className="mb-4 bg-slate-900 border border-slate-800 rounded-xl px-4 py-2.5 flex items-center gap-4 overflow-x-auto scrollbar-hide">
|
||||||
|
|
||||||
{/* En-tête */}
|
<span className="text-slate-500 font-semibold uppercase tracking-widest text-[10px] shrink-0">
|
||||||
<div className="flex items-center justify-between mb-2">
|
DRIVERS GLOBAUX
|
||||||
<span className="text-[9px] font-semibold text-gray-400 uppercase tracking-widest">
|
</span>
|
||||||
Drivers globaux
|
|
||||||
</span>
|
|
||||||
{riskOff && (
|
|
||||||
<span className="text-[9px] font-medium bg-red-50 text-red-600 border border-red-200 rounded-full px-2 py-0.5">
|
|
||||||
⚠ Risk-Off
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ── Ligne unique — tous les indicateurs ── */}
|
{riskOff && (
|
||||||
<div className="flex items-start gap-4 overflow-x-auto pb-0.5">
|
<div className="flex items-center gap-1 shrink-0 bg-red-500/10 border border-red-500/20 rounded-full px-2 py-0.5">
|
||||||
|
<AlertTriangle size={10} className="text-red-400" />
|
||||||
|
<span className="text-[9px] font-semibold text-red-400">Risk-Off</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Sentiment / Risk-On */}
|
<VSep />
|
||||||
<M
|
|
||||||
label="VIX" value={vix} dec={1} delta={vixDelta} deltaDec={1}
|
|
||||||
tooltip="Delta = clôture actuelle − clôture précédente issue de Yahoo Finance (métrique intraday/close de session)."
|
|
||||||
/>
|
|
||||||
<M
|
|
||||||
label="S&P 500" value={sp500} dec={0} delta={sp500ChangePct} deltaPct deltaDec={2}
|
|
||||||
tooltip="Changement = clôture actuelle − clôture précédente de Yahoo Finance. Le % est calculé sur la clôture précédente."
|
|
||||||
/>
|
|
||||||
<M
|
|
||||||
label="Bitcoin" value={btc} dec={0} unit=" $" delta={btcChange24h} deltaPct deltaDec={2}
|
|
||||||
tooltip="Variation 24h issue de Binance / CoinGecko via le ticker 24h (priceChangePercent)."
|
|
||||||
/>
|
|
||||||
|
|
||||||
<VSep />
|
{/* Sentiment / Risk-On */}
|
||||||
|
<D label="VIX" value={vix} dec={1} delta={vixDelta} deltaDec={1}
|
||||||
|
tooltip="Clôture actuelle − clôture précédente (Yahoo Finance)." />
|
||||||
|
<D label="S&P 500" value={sp500} dec={0} delta={sp500ChangePct} deltaPct deltaDec={2}
|
||||||
|
tooltip="% vs clôture précédente (Yahoo Finance)." />
|
||||||
|
<D label="Bitcoin" value={btc} dec={0} unit=" $" delta={btcChange24h} deltaPct deltaDec={2}
|
||||||
|
tooltip="Variation 24h (Binance / CoinGecko)." />
|
||||||
|
|
||||||
{/* Crédit */}
|
<VSep />
|
||||||
<M
|
|
||||||
label="HY Spread" value={hySpread} dec={0} unit=" bps"
|
|
||||||
tooltip="High Yield spread : écart entre les obligations d'entreprises à haut risque (< BBB) et les Treasuries US. >500 bps = signal risk-off fort."
|
|
||||||
/>
|
|
||||||
<M
|
|
||||||
label="IG Spread" value={igSpread} dec={0} unit=" bps"
|
|
||||||
tooltip="Investment Grade spread : écart entre les obligations bien notées (BBB+) et les Treasuries US. Mesure le coût du crédit des grandes entreprises."
|
|
||||||
/>
|
|
||||||
|
|
||||||
<VSep />
|
{/* Crédit */}
|
||||||
|
<D label="HY Spread" value={hySpread} dec={0} unit=" bps"
|
||||||
|
tooltip="High Yield spread vs Treasuries US. >500 bps = risk-off fort." />
|
||||||
|
<D label="IG Spread" value={igSpread} dec={0} unit=" bps"
|
||||||
|
tooltip="Investment Grade spread vs Treasuries US." />
|
||||||
|
|
||||||
{/* Taux & FX */}
|
<VSep />
|
||||||
<M
|
|
||||||
label="DXY" value={dxy} dec={2}
|
|
||||||
delta={(drivers as DriverData & { dxyDelta?: number | null }).dxyDelta ?? null}
|
|
||||||
deltaDec={2}
|
|
||||||
tooltip="ICE Dollar Index Futures (DX=F) via Yahoo Finance — temps réel, cache 5 min. Delta = clôture actuelle − clôture précédente."
|
|
||||||
/>
|
|
||||||
<M
|
|
||||||
label="Crb 2-10" value={curveSlope} dec={0} unit=" bps"
|
|
||||||
tooltip={`Spread US 10Y − US 2Y. Positif = courbe normale. Négatif = courbe inversée (signal récessif historiquement).\nUS 10Y: ${us10y != null ? us10y.toFixed(4) + "%" : "N/A"} | US 2Y: ${us2y != null ? us2y.toFixed(2) + "%" : "N/A"}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<VSep />
|
{/* Taux & FX */}
|
||||||
|
<D label="DXY" value={dxy} dec={2} delta={dxyDelta} deltaDec={2}
|
||||||
|
tooltip="ICE Dollar Index Futures (DX=F) — Yahoo Finance, cache 5 min." />
|
||||||
|
<D
|
||||||
|
label="Crb 2-10" value={curveSlope} dec={0} unit=" bps"
|
||||||
|
tooltip={`Spread US 10Y − US 2Y. Négatif = courbe inversée.\nUS 10Y: ${us10y != null ? us10y.toFixed(2) + "%" : "N/A"} | US 2Y: ${us2y != null ? us2y.toFixed(2) + "%" : "N/A"}`}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Commodités */}
|
<VSep />
|
||||||
<M
|
|
||||||
label="Or $/oz" value={gold} dec={0} delta={goldDelta} deltaDec={1}
|
{/* Commodités */}
|
||||||
tooltip="Delta intraday = close − open issue de Stooq (métaux précieux)."
|
<D label="Or $/oz" value={gold} dec={0} delta={goldDelta} deltaDec={1}
|
||||||
/>
|
tooltip="Delta intraday close−open (Stooq)." />
|
||||||
<M
|
<D label="Argent $/oz" value={silver} dec={2} delta={silverDelta}
|
||||||
label="Argent $/oz" value={silver} dec={2} delta={silverDelta} deltaDec={2}
|
tooltip="Delta intraday close−open (Stooq)." />
|
||||||
tooltip="Delta intraday = close − open issue de Stooq (métaux précieux)."
|
<D label="Brent $/b" value={brent} dec={1} delta={brentDelta} deltaDec={1}
|
||||||
/>
|
tooltip="Delta intraday close−open (Stooq)." />
|
||||||
<M
|
<D label="WTI $/b" value={wti} dec={1} delta={wtiDelta} deltaDec={1}
|
||||||
label="Brent $/b" value={brent} dec={1} delta={brentDelta} deltaDec={1}
|
tooltip="Delta intraday close−open (Stooq)." />
|
||||||
tooltip="Delta intraday = close − open issue de Stooq (pétrole Brent)."
|
|
||||||
/>
|
|
||||||
<M
|
|
||||||
label="WTI $/b" value={wti} dec={1} delta={wtiDelta} deltaDec={1}
|
|
||||||
tooltip="Delta intraday = close − open issue de Stooq (pétrole WTI)."
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user