fix: add LatestSignals component to paper-v53 page
This commit is contained in:
parent
18af5bb711
commit
224ca20666
@ -37,6 +37,100 @@ const STRATEGY_LABELS: Record<StrategyTab, { label: string; desc: string; coins:
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ─── 最新信号状态 ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const ALT_COINS = ["ETHUSDT", "XRPUSDT", "SOLUSDT"];
|
||||||
|
const BTC_COINS = ["BTCUSDT"];
|
||||||
|
|
||||||
|
function LatestSignals({ strategy }: { strategy: StrategyTab }) {
|
||||||
|
const coins = strategy === "v53_btc" ? BTC_COINS : ALT_COINS;
|
||||||
|
const [signals, setSignals] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const f = async () => {
|
||||||
|
for (const sym of coins) {
|
||||||
|
const coin = sym.replace("USDT", "");
|
||||||
|
const strat = strategy === "v53_btc" ? "v53_btc" : "v53_alt";
|
||||||
|
try {
|
||||||
|
const r = await authFetch(`/api/signals/signal-history?symbol=${coin}&limit=1&strategy=${strat}`);
|
||||||
|
if (r.ok) {
|
||||||
|
const j = await r.json();
|
||||||
|
if (j.data && j.data.length > 0) setSignals(prev => ({ ...prev, [sym]: j.data[0] }));
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
f();
|
||||||
|
const iv = setInterval(f, 15000);
|
||||||
|
return () => clearInterval(iv);
|
||||||
|
}, [strategy, coins]);
|
||||||
|
|
||||||
|
const meta = STRATEGY_LABELS[strategy];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-slate-200 bg-white overflow-hidden">
|
||||||
|
<div className="px-3 py-2 border-b border-slate-100 flex items-center justify-between">
|
||||||
|
<h3 className="font-semibold text-slate-800 text-xs">最新信号</h3>
|
||||||
|
<span className={`px-2 py-0.5 rounded text-[10px] font-semibold ${meta.badgeClass}`}>{strategy}</span>
|
||||||
|
</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;
|
||||||
|
const fc = s?.factors;
|
||||||
|
return (
|
||||||
|
<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 ? (
|
||||||
|
<>
|
||||||
|
<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-xs font-bold text-slate-800">{s.score}分</span>
|
||||||
|
<span className="text-[9px] px-1.5 py-0.5 rounded bg-slate-100 text-slate-600 font-medium">
|
||||||
|
{s.score >= 85 ? "加仓" : s.score >= 75 ? "标准" : "观望"}
|
||||||
|
</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>
|
||||||
|
{fc && strategy === "v53_alt" && (
|
||||||
|
<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">方向{fc.direction?.score ?? 0}/55</span>
|
||||||
|
<span className="text-[9px] px-1 py-0.5 rounded bg-violet-50 text-violet-700">拥挤{fc.crowding?.score ?? 0}/25</span>
|
||||||
|
<span className="text-[9px] px-1 py-0.5 rounded bg-emerald-50 text-emerald-700">环境{fc.environment?.score ?? 0}/15</span>
|
||||||
|
<span className="text-[9px] px-1 py-0.5 rounded bg-slate-100 text-slate-600">辅助{fc.auxiliary?.score ?? 0}/5</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{fc && strategy === "v53_btc" && (
|
||||||
|
<div className="flex gap-1 mt-1 flex-wrap">
|
||||||
|
<span className={`text-[9px] px-1 py-0.5 rounded ${fc.gate_passed ? "bg-emerald-100 text-emerald-700" : "bg-red-100 text-red-600"}`}>
|
||||||
|
{fc.gate_passed ? "✅ Gate通过" : "❌ Gate否决"}
|
||||||
|
</span>
|
||||||
|
{fc.block_reason && (
|
||||||
|
<span className="text-[9px] px-1 py-0.5 rounded bg-orange-50 text-orange-700">{fc.block_reason}</span>
|
||||||
|
)}
|
||||||
|
<span className="text-[9px] px-1 py-0.5 rounded bg-amber-50 text-amber-700">
|
||||||
|
OBI {((fc.obi_raw ?? 0) * 100).toFixed(2)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── 控制面板 ────────────────────────────────────────────────────
|
// ─── 控制面板 ────────────────────────────────────────────────────
|
||||||
|
|
||||||
function ControlPanel() {
|
function ControlPanel() {
|
||||||
@ -432,6 +526,7 @@ export default function PaperTradingV53Page() {
|
|||||||
|
|
||||||
<ControlPanel />
|
<ControlPanel />
|
||||||
<SummaryCards strategy={strategyTab} />
|
<SummaryCards strategy={strategyTab} />
|
||||||
|
<LatestSignals strategy={strategyTab} />
|
||||||
<ActivePositions strategy={strategyTab} />
|
<ActivePositions strategy={strategyTab} />
|
||||||
<EquityCurve strategy={strategyTab} />
|
<EquityCurve strategy={strategyTab} />
|
||||||
<TradeHistory strategy={strategyTab} />
|
<TradeHistory strategy={strategyTab} />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user