import { useState, useEffect, useCallback } from 'react';
export interface Trader {
address: string;
label: string | null;
totalTrades: number;
totalVolume: number;
avgTradeSize: number;
largestTrade: number;
totalPnl: number | null;
winRate: number | null;
topCategory: string | null;
firstSeen: string | null;
lastSeen: string | null;
avgBuy: number | null;
sellRate: number | null;
avatar: string | null;
// Phase B: honest positional stats (only resolved/closed positions).
winRatePos: number | null;
realizedPnlPos: number | null;
closedPositions: number | null;
openPositions: number | null;
// Phase «Флаги»: copy-fit quality gate (Phase D).
qualityFlag: number | null;
backtestPf: number | null;
activeDays: number | null;
// Chunk B: realized PnL on resolved BUYs in the last 7 days (momentum). NULL if none.
pnl7d: number | null;
// Chunk B: JSON array of last-16 resolved-BUY per-trade PnLs (oldest→newest) for a sparkline.
spark: string | null;
}
const FOLLOW_KEY = 'sz_following';
export function useTopTraders(sort = 'volume', limit = 30) {
const [traders, setTraders] = useState<Trader[]>([]);
const [loading, setLoading] = useState(true);
const fetchTraders = useCallback(async () => {
setLoading(true);
try {
const res = await fetch(`/api/signals/top-traders?sort=${sort}&limit=${limit}`);
const d = await res.json();
if (d.success) setTraders(d.data ?? []);
} catch { /* ignore */ }
setLoading(false);
}, [sort, limit]);
useEffect(() => {
const t = setTimeout(fetchTraders, 0);
return () => { clearTimeout(t); };
}, [fetchTraders]);
return { traders, loading, refresh: fetchTraders };
}
// Follow/unfollow persistence (localStorage)
export function useFollowing() {
const [following, setFollowing] = useState<Set<string>>(() => {
try {
const stored = localStorage.getItem(FOLLOW_KEY);
return stored ? new Set(JSON.parse(stored)) : new Set();
} catch { return new Set(); }
});
const toggle = useCallback((address: string) => {
setFollowing(prev => {
const next = new Set(prev);
if (next.has(address)) next.delete(address);
else next.add(address);
try { localStorage.setItem(FOLLOW_KEY, JSON.stringify([...next])); } catch { /* ignore */ }
return next;
});
}, []);
return { following, toggle };
}
📜 Git History
03a2d80chore(save): session 2026-06-22 — Phase2 redesign + 3mo history + realized-PnL fix; staged _impl edits11 days ago
Show last diff
Loading...