feat: paper page show latest signal per coin
This commit is contained in:
parent
95fec35d97
commit
374615dea7
@ -108,6 +108,61 @@ function SummaryCards() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── 最新信号状态 ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const COINS = ["BTCUSDT", "ETHUSDT", "XRPUSDT", "SOLUSDT"];
|
||||||
|
|
||||||
|
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/latest?symbol=${sym}`);
|
||||||
|
if (r.ok) {
|
||||||
|
const j = await r.json();
|
||||||
|
setSignals(prev => ({ ...prev, [sym]: j }));
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
f(); const iv = setInterval(f, 15000); return () => clearInterval(iv);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-slate-200 bg-white overflow-hidden">
|
||||||
|
<div className="px-3 py-2 border-b border-slate-100">
|
||||||
|
<h3 className="font-semibold text-slate-800 text-xs">最新信号</h3>
|
||||||
|
</div>
|
||||||
|
<div className="divide-y divide-slate-50">
|
||||||
|
{COINS.map(sym => {
|
||||||
|
const s = signals[sym];
|
||||||
|
const coin = sym.replace("USDT", "");
|
||||||
|
const ago = s?.ts ? Math.round((Date.now() - s.ts) / 60000) : null;
|
||||||
|
return (
|
||||||
|
<div key={sym} className="px-3 py-1.5 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 ? (
|
||||||
|
<>
|
||||||
|
<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="text-[10px] text-slate-400">⚪ 无信号</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{ago !== null && <span className="text-[10px] text-slate-400">{ago < 60 ? `${ago}m前` : `${Math.round(ago/60)}h前`}</span>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── 当前持仓 ────────────────────────────────────────────────────
|
// ─── 当前持仓 ────────────────────────────────────────────────────
|
||||||
|
|
||||||
function ActivePositions() {
|
function ActivePositions() {
|
||||||
@ -378,6 +433,7 @@ export default function PaperTradingPage() {
|
|||||||
|
|
||||||
<ControlPanel />
|
<ControlPanel />
|
||||||
<SummaryCards />
|
<SummaryCards />
|
||||||
|
<LatestSignals />
|
||||||
<ActivePositions />
|
<ActivePositions />
|
||||||
<EquityCurve />
|
<EquityCurve />
|
||||||
<TradeHistory />
|
<TradeHistory />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user