feat: paper pages show per-strategy signals with layer scores
- V5.1 paper reads /api/signals/latest?strategy=v51_baseline - V5.2 paper reads /api/signals/latest?strategy=v52_8signals - Each coin shows layer score badges (方向/拥挤/环境/确认/辅助) - V5.2 additionally shows FR and 清算 badges
This commit is contained in:
parent
7ebdb98643
commit
5b704a0a0e
@ -166,17 +166,13 @@ function LatestSignals() {
|
||||
const [signals, setSignals] = useState<Record<string, any>>({});
|
||||
useEffect(() => {
|
||||
const f = async () => {
|
||||
for (const sym of COINS) {
|
||||
try {
|
||||
const r = await authFetch(`/api/signals/signal-history?symbol=${sym.replace("USDT", "")}&limit=1`);
|
||||
const r = await authFetch("/api/signals/latest?strategy=v52_8signals");
|
||||
if (r.ok) {
|
||||
const j = await r.json();
|
||||
if (j.data && j.data.length > 0) {
|
||||
setSignals((prev) => ({ ...prev, [sym]: j.data[0] }));
|
||||
}
|
||||
setSignals(j);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
};
|
||||
f();
|
||||
const iv = setInterval(f, 15000);
|
||||
@ -190,11 +186,13 @@ function LatestSignals() {
|
||||
</div>
|
||||
<div className="divide-y divide-slate-50">
|
||||
{COINS.map((sym) => {
|
||||
const s = signals[sym];
|
||||
const coin = sym.replace("USDT", "");
|
||||
const s = signals[coin];
|
||||
const ago = s?.ts ? Math.round((Date.now() - s.ts) / 60000) : null;
|
||||
const f = s?.factors;
|
||||
return (
|
||||
<div key={sym} className="px-3 py-1.5 flex items-center justify-between">
|
||||
<div key={sym} className="px-3 py-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-mono text-xs font-bold text-slate-700 w-8">{coin}</span>
|
||||
{s?.signal ? (
|
||||
@ -202,14 +200,29 @@ function LatestSignals() {
|
||||
<span className={`text-xs font-bold ${s.signal === "LONG" ? "text-emerald-600" : "text-red-500"}`}>
|
||||
{s.signal === "LONG" ? "🟢" : "🔴"} {s.signal}
|
||||
</span>
|
||||
<span className="font-mono text-[10px] text-slate-500">{s.score}分</span>
|
||||
<span className="font-mono text-xs font-bold text-slate-800">{s.score}分</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="text-[10px] text-slate-400">⚪ 无信号</span>
|
||||
<span className="font-mono text-[10px] text-slate-500">{s?.score ?? 0}分</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{ago !== null && <span className="text-[10px] text-slate-400">{ago < 60 ? `${ago}m前` : `${Math.round(ago / 60)}h前`}</span>}
|
||||
</div>
|
||||
{f && (
|
||||
<div className="flex gap-1 mt-1 flex-wrap">
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-blue-50 text-blue-700">方向{f.direction?.score ?? 0}/{f.direction?.max ?? 40}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-violet-50 text-violet-700">拥挤{f.crowding?.score ?? 0}/{f.crowding?.max ?? 18}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-cyan-50 text-cyan-700">FR{f.funding_rate?.score ?? 0}/{f.funding_rate?.max ?? 5}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-emerald-50 text-emerald-700">环境{f.environment?.score ?? 0}/{f.environment?.max ?? 12}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-amber-50 text-amber-700">确认{f.confirmation?.score ?? 0}/{f.confirmation?.max ?? 15}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-orange-50 text-orange-700">清算{f.liquidation?.score ?? 0}/{f.liquidation?.max ?? 5}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-slate-100 text-slate-600">辅助{f.auxiliary?.score ?? 0}/{f.auxiliary?.max ?? 5}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@ -118,17 +118,13 @@ function LatestSignals() {
|
||||
const [signals, setSignals] = useState<Record<string, any>>({});
|
||||
useEffect(() => {
|
||||
const f = async () => {
|
||||
for (const sym of COINS) {
|
||||
try {
|
||||
const r = await authFetch(`/api/signals/signal-history?symbol=${sym.replace("USDT","")}&limit=1`);
|
||||
const r = await authFetch("/api/signals/latest?strategy=v51_baseline");
|
||||
if (r.ok) {
|
||||
const j = await r.json();
|
||||
if (j.data && j.data.length > 0) {
|
||||
setSignals(prev => ({ ...prev, [sym]: j.data[0] }));
|
||||
}
|
||||
setSignals(j);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
};
|
||||
f(); const iv = setInterval(f, 15000); return () => clearInterval(iv);
|
||||
}, []);
|
||||
@ -140,11 +136,13 @@ function LatestSignals() {
|
||||
</div>
|
||||
<div className="divide-y divide-slate-50">
|
||||
{COINS.map(sym => {
|
||||
const s = signals[sym];
|
||||
const coin = sym.replace("USDT", "");
|
||||
const s = signals[coin];
|
||||
const ago = s?.ts ? Math.round((Date.now() - s.ts) / 60000) : null;
|
||||
const f = s?.factors;
|
||||
return (
|
||||
<div key={sym} className="px-3 py-1.5 flex items-center justify-between">
|
||||
<div key={sym} className="px-3 py-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-mono text-xs font-bold text-slate-700 w-8">{coin}</span>
|
||||
{s?.signal ? (
|
||||
@ -152,14 +150,27 @@ function LatestSignals() {
|
||||
<span className={`text-xs font-bold ${s.signal === "LONG" ? "text-emerald-600" : "text-red-500"}`}>
|
||||
{s.signal === "LONG" ? "🟢" : "🔴"} {s.signal}
|
||||
</span>
|
||||
<span className="font-mono text-[10px] text-slate-500">{s.score}分</span>
|
||||
<span className="font-mono text-xs font-bold text-slate-800">{s.score}分</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="text-[10px] text-slate-400">⚪ 无信号</span>
|
||||
<span className="font-mono text-[10px] text-slate-500">{s?.score ?? 0}分</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{ago !== null && <span className="text-[10px] text-slate-400">{ago < 60 ? `${ago}m前` : `${Math.round(ago/60)}h前`}</span>}
|
||||
</div>
|
||||
{f && (
|
||||
<div className="flex gap-1 mt-1 flex-wrap">
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-blue-50 text-blue-700">方向{f.direction?.score ?? 0}/{f.direction?.max ?? 45}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-violet-50 text-violet-700">拥挤{f.crowding?.score ?? 0}/{f.crowding?.max ?? 20}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-emerald-50 text-emerald-700">环境{f.environment?.score ?? 0}/{f.environment?.max ?? 15}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-amber-50 text-amber-700">确认{f.confirmation?.score ?? 0}/{f.confirmation?.max ?? 15}</span>
|
||||
<span className="text-[9px] px-1 py-0.5 rounded bg-slate-100 text-slate-600">辅助{f.auxiliary?.score ?? 0}/{f.auxiliary?.max ?? 5}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user