/* ===== ArbitrajZ — Dashboard app ===== */ /* ---- tiny helpers ---- */ function pad(n) { return n < 10 ? "0" + n : "" + n; } function fmtClock(d) { return pad(d.getHours()) + ":" + pad(d.getMinutes()); } function StabilityMeter({ level }) { // High = 3 bars, Med = 2, Low = 1 const n = level === "High" ? 3 : level === "Med" ? 2 : 1; return ( ); } /* ---- info tooltip ---- */ function InfoTip({ text }) { const [pos, setPos] = useState(null); const ref = useRef(null); function show() { if (!ref.current) return; const r = ref.current.getBoundingClientRect(); setPos({ top: r.bottom + 7, left: r.left + r.width / 2 }); } return ( setPos(null)} onClick={(e) => { e.stopPropagation(); pos ? setPos(null) : show(); }}> i {pos && ( {text} )} ); } /* ---- top bar ---- */ function TopBar({ scanning, exchanges }) { const NAV = [ { label: "Dashboard", href: "/" }, { label: "Opportunities", href: "/opportunities.html" }, { label: "Alerts" }, { label: "Help", href: "/help.html" }, ]; const [active, setActive] = useState("Dashboard"); const lastScanRaw = window.ARBZ.SUMMARY.lastScan; const scanDisplay = lastScanRaw ? fmtClock(new Date(lastScanRaw)) : "--:--"; return (
ArbitrajZ
Live · last scan  {scanning ? "scanning…" : scanDisplay} · {exchanges} exchanges
); } /* ---- summary metric cards ---- */ function MetricCard({ label, children, accent, sub, tip }) { return (
{label}{tip && }
{children}
{sub &&
{sub}
}
); } function Summary({ s }) { return (
{s.cleanSignalsTotal} {s.bestApr.toFixed(1)}% {s.pairsScanned.toLocaleString()} High
); } /* ---- one opportunity ---- */ function OppRow({ o, open, onToggle }) { const stable = o.stable; const exLeg = `${o.base}\u2011PERP`; return (
{open && }
); } function OppDetail({ o, exLeg }) { const avg = o.series.reduce((a, b) => a + b, 0) / o.series.length; const stable = o.stable; return (
LONG
{o.base}/{o.quote} spot
{o.exchange} · collects nothing, hedges price
delta-neutral
SHORT
{exLeg} perp
{o.exchange} · earns funding every 8h
= 0 ? "+" : "") + o.curFunding.toFixed(4) + "%"} tone={o.curFunding >= 0 ? "pos" : "neg"} sub="per 8h" /> = 0 ? "+" : "") + avg.toFixed(4) + "%"} tone="pos" sub="per 8h" />
{stable ? "✓" : "!"} {stable ? `Funding held positive across all 21 intervals this week. Carry has been steady — this is the kind of clean, boring signal we surface first.` : `Headline APR looks comparable, but funding flipped negative ${o.negCount}× this week. Each flip means you paid instead of earned. Size down or skip — the 7d average can hide a bumpy ride.`}
Set funding alert window.open(pairUrl(o), "_blank")}>Open pair refreshed just now
); } function pairUrl(o) { const base = (o.base || "").toUpperCase(); const ex = (o.exchange || "").toLowerCase(); if (ex === "bybit") return "https://www.bybit.com/trade/usdt/" + base + "USDT"; if (ex === "binance") return "https://www.binance.com/en/futures/" + base + "USDT"; if (ex === "okx") return "https://www.okx.com/trade-swap/" + base.toLowerCase() + "-usdt-swap"; if (ex === "gate") return "https://www.gate.io/futures/USDT/" + base + "_USDT"; return "https://www.google.com/search?q=" + encodeURIComponent(base + " USDT perpetual " + (o.exchange || "")); } function Stat({ k, v, sub, tone }) { return (
{k}
{v}
{sub &&
{sub}
}
); } function ActionBtn({ children, primary, onAction }) { const [hit, setHit] = useState(false); return ( ); } /* ---- opportunities section ---- */ function Opportunities({ opps }) { const [sort, setSort] = useState("stability"); const [stableOnly, setStableOnly] = useState(false); const [openId, setOpenId] = useState("apex"); const [refreshIn, setRefreshIn] = useState(60); useEffect(() => { const t = setInterval(() => setRefreshIn((r) => (r <= 1 ? 60 : r - 1)), 1000); return () => clearInterval(t); }, []); const list = useMemo(() => { let xs = opps.slice(); if (stableOnly) xs = xs.filter((o) => o.stable); if (sort === "stability") xs.sort((a, b) => a.negCount - b.negCount || b.netApr - a.netApr); else xs.sort((a, b) => b.netApr - a.netApr); return xs; }, [opps, sort, stableOnly]); return (

Opportunities

{list.length} live
Sort
sorted by {sort === "stability" ? "stability" : "net APR"} · auto-refresh in {refreshIn}s
{list.map((o) => ( setOpenId((id) => (id === o.id ? null : o.id))} /> ))} {list.length === 0 && (
No stable signals match the filter right now.
)}
); } /* ---- root ---- */ function App() { const { OPPS, SUMMARY } = window.ARBZ; const [scanning, setScanning] = useState(false); // periodic "re-scan" pulse — feels alive without being noisy useEffect(() => { const t = setInterval(() => { setScanning(true); setTimeout(() => { setScanning(false); }, 1500); }, 18000); return () => clearInterval(t); }, []); return (
Informational signals only. Not financial advice. DYOR.
ArbitrajZ · funding-rate arbitrage radar
); } /* Re-randare la fiecare refresh de date din data.js (fetch async) */ const __arbzRoot = ReactDOM.createRoot(document.getElementById("root")); window.__ARBZ_RENDER = function () { __arbzRoot.render(); }; window.__ARBZ_RENDER();