"use client"; import { useState, useEffect } from "react"; import Link from "next/link"; import { authFetch, useAuth } from "@/lib/auth"; import { XAxis, YAxis, Tooltip, ResponsiveContainer, ReferenceLine, Area, AreaChart } from "recharts"; function bjt(ms: number) { const d = new Date(ms + 8 * 3600 * 1000); return `${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")} ${String(d.getUTCHours()).padStart(2, "0")}:${String(d.getUTCMinutes()).padStart(2, "0")}`; } function fmtPrice(p: number) { return p < 100 ? p.toFixed(4) : p.toLocaleString("en-US", { minimumFractionDigits: 1, maximumFractionDigits: 1 }); } const LIVE_STRATEGY = "v52_8signals"; // ─── 风控状态 ──────────────────────────────────────────────────── function RiskStatusPanel() { const [risk, setRisk] = useState(null); useEffect(() => { const f = async () => { try { const r = await authFetch("/api/live/risk-status"); if (r.ok) setRisk(await r.json()); } catch {} }; f(); const iv = setInterval(f, 5000); return () => clearInterval(iv); }, []); if (!risk) return null; const statusColor = risk.status === "normal" ? "border-emerald-400 bg-emerald-50" : risk.status === "warning" ? "border-amber-400 bg-amber-50" : risk.status === "circuit_break" ? "border-red-400 bg-red-50" : "border-slate-200 bg-slate-50"; const statusIcon = risk.status === "normal" ? "🟢" : risk.status === "warning" ? "🟡" : risk.status === "circuit_break" ? "🔴" : "⚪"; return (
{statusIcon}
风控: {risk.status === "normal" ? "正常" : risk.status === "warning" ? "警告" : risk.status === "circuit_break" ? "熔断中" : "未知"} {risk.circuit_break_reason &&

{risk.circuit_break_reason}

}
已实现

= 0 ? "text-emerald-600" : "text-red-500"}`}>{(risk.today_realized_r||0) >= 0 ? "+" : ""}{risk.today_realized_r||0}R

未实现

= 0 ? "text-emerald-600" : "text-red-500"}`}>{(risk.today_unrealized_r||0) >= 0 ? "+" : ""}{risk.today_unrealized_r||0}R

合计

= 0 ? "text-emerald-600" : "text-red-500"}`}>{(risk.today_total_r||0) >= 0 ? "+" : ""}{risk.today_total_r||0}R

连亏

{risk.consecutive_losses||0}次

{(risk.block_new_entries || risk.reduce_only) && (
{risk.block_new_entries && 🚫 禁止新开仓} {risk.reduce_only && 🔒 只减仓}
)}
); } // ─── 紧急操作 ──────────────────────────────────────────────────── function EmergencyPanel() { const [confirming, setConfirming] = useState(null); const [msg, setMsg] = useState(""); const doAction = async (action: string) => { try { const r = await authFetch(`/api/live/${action}`, { method: "POST" }); const j = await r.json(); setMsg(j.message || j.error || "已执行"); setConfirming(null); setTimeout(() => setMsg(""), 5000); } catch { setMsg("操作失败"); } }; return (

⚡ 紧急操作

{confirming === "emergency-close" ? (
确认全平?
) : ( )} {confirming === "block-new" ? (
确认?
) : ( )}
{msg &&

{msg}

}
); } // ─── 总览 ──────────────────────────────────────────────────────── function SummaryCards() { const [data, setData] = useState(null); useEffect(() => { const f = async () => { try { const r = await authFetch(`/api/live/summary?strategy=${LIVE_STRATEGY}`); if (r.ok) setData(await r.json()); } catch {} }; f(); const iv = setInterval(f, 10000); return () => clearInterval(iv); }, []); if (!data) return
加载中...
; return (

总盈亏(R)

= 0 ? "text-emerald-600" : "text-red-500"}`}>{data.total_pnl_r >= 0 ? "+" : ""}{data.total_pnl_r}R

= 0 ? "text-emerald-500" : "text-red-400"}`}>{data.total_pnl_usdt >= 0 ? "+" : ""}${data.total_pnl_usdt}

胜率

{data.win_rate}%

总交易

{data.total_trades}

持仓中

{data.active_positions}

盈亏比(PF)

{data.profit_factor}

手续费

${data.total_fee_usdt}

资金费

${data.total_funding_usdt}

); } // ─── 当前持仓 ──────────────────────────────────────────────────── function ActivePositions() { const [positions, setPositions] = useState([]); const [wsPrices, setWsPrices] = useState>({}); useEffect(() => { const f = async () => { try { const r = await authFetch(`/api/live/positions?strategy=${LIVE_STRATEGY}`); if (r.ok) { const j = await r.json(); setPositions(j.data || []); } } catch {} }; f(); const iv = setInterval(f, 5000); return () => clearInterval(iv); }, []); useEffect(() => { const streams = ["btcusdt", "ethusdt", "xrpusdt", "solusdt"].map(s => `${s}@aggTrade`).join("/"); const ws = new WebSocket(`wss://fstream.binance.com/stream?streams=${streams}`); ws.onmessage = (e) => { try { const msg = JSON.parse(e.data); if (msg.data) { setWsPrices(prev => ({ ...prev, [msg.data.s]: parseFloat(msg.data.p) })); } } catch {} }; return () => ws.close(); }, []); if (positions.length === 0) return
暂无活跃持仓
; return (

当前持仓 ● 实时 币安合约

{positions.map((p: any) => { const sym = p.symbol?.replace("USDT", "") || ""; const holdMin = p.hold_time_min || Math.round((Date.now() - p.entry_ts) / 60000); const currentPrice = wsPrices[p.symbol] || p.current_price || 0; const entry = p.entry_price || 0; const rd = p.risk_distance || 1; const fullR = rd > 0 ? (p.direction === "LONG" ? (currentPrice - entry) / rd : (entry - currentPrice) / rd) : 0; const tp1R = rd > 0 ? (p.direction === "LONG" ? ((p.tp1_price || 0) - entry) / rd : (entry - (p.tp1_price || 0)) / rd) : 0; const unrealR = p.tp1_hit ? 0.5 * tp1R + 0.5 * fullR : fullR; const unrealUsdt = unrealR * 2; const holdColor = holdMin >= 60 ? "text-red-500 font-bold" : holdMin >= 45 ? "text-amber-500" : "text-slate-400"; return (
{p.direction === "LONG" ? "🟢" : "🔴"} {sym} {p.direction} 评分{p.score} · {p.tier === "heavy" ? "加仓" : "标准"}
= 0 ? "text-emerald-600" : "text-red-500"}`}>{unrealR >= 0 ? "+" : ""}{unrealR.toFixed(2)}R = 0 ? "text-emerald-500" : "text-red-400"}`}>({unrealUsdt >= 0 ? "+" : ""}${unrealUsdt.toFixed(2)}) {holdMin}m
入场: ${fmtPrice(entry)} 成交: ${fmtPrice(p.fill_price || entry)} 现价: ${currentPrice ? fmtPrice(currentPrice) : "-"} TP1: ${fmtPrice(p.tp1_price)}{p.tp1_hit ? " ✅" : ""} TP2: ${fmtPrice(p.tp2_price)} SL: ${fmtPrice(p.sl_price)}
8?"bg-red-50 text-red-700":Math.abs(p.slippage_bps||0)>2.5?"bg-amber-50 text-amber-700":"bg-emerald-50 text-emerald-700"}`}>滑点 {(p.slippage_bps||0).toFixed(1)}bps 5000?"bg-red-50 text-red-700":(p.protection_gap_ms||0)>2000?"bg-amber-50 text-amber-700":"bg-emerald-50 text-emerald-700"}`}>裸奔 {p.protection_gap_ms||0}ms 信号→下单 {p.signal_to_order_ms||0}ms 下单→成交 {p.order_to_fill_ms||0}ms #{p.binance_order_id||"-"}
); })}
); } // ─── 权益曲线 ──────────────────────────────────────────────────── function EquityCurve() { const [data, setData] = useState([]); useEffect(() => { const f = async () => { try { const r = await authFetch(`/api/live/equity-curve?strategy=${LIVE_STRATEGY}`); if (r.ok) { const j = await r.json(); setData(j.data || []); } } catch {} }; f(); const iv = setInterval(f, 30000); return () => clearInterval(iv); }, []); if (data.length < 2) return null; return (

权益曲线 (累计PnL)

bjt(v)} tick={{ fontSize: 10 }} /> `${v}R`} /> bjt(Number(v))} formatter={(v: any) => [`${v}R`, "累计PnL"]} />
); } // ─── 历史交易 ──────────────────────────────────────────────────── type FilterSymbol = "all" | "BTC" | "ETH" | "XRP" | "SOL"; type FilterResult = "all" | "win" | "loss"; function TradeHistory() { const [trades, setTrades] = useState([]); const [symbol, setSymbol] = useState("all"); const [result, setResult] = useState("all"); useEffect(() => { const f = async () => { try { const r = await authFetch(`/api/live/trades?symbol=${symbol}&result=${result}&strategy=${LIVE_STRATEGY}&limit=50`); if (r.ok) { const j = await r.json(); setTrades(j.data || []); } } catch {} }; f(); const iv = setInterval(f, 10000); return () => clearInterval(iv); }, [symbol, result]); return (

历史交易

{(["all","BTC","ETH","XRP","SOL"] as FilterSymbol[]).map(s => ())} | {(["all","win","loss"] as FilterResult[]).map(r => ())}
{trades.length === 0 ?
暂无交易记录
: ( {trades.map((t: any) => { const holdMin = t.exit_ts && t.entry_ts ? Math.round((t.exit_ts - t.entry_ts) / 60000) : 0; return ( ); })}
币种 方向 入场 成交 出场 PnL(R) 状态 滑点 费用 时间
{t.symbol?.replace("USDT","")} {t.direction === "LONG" ? "🟢" : "🔴"} {t.direction} {fmtPrice(t.entry_price)} {t.fill_price ? fmtPrice(t.fill_price) : "-"} {t.exit_price ? fmtPrice(t.exit_price) : "-"} 0 ? "text-emerald-600" : (t.pnl_r||0) < 0 ? "text-red-500" : "text-slate-500"}`}>{(t.pnl_r||0) > 0 ? "+" : ""}{(t.pnl_r||0).toFixed(2)} {t.status==="tp"?"止盈":t.status==="sl"?"止损":t.status==="sl_be"?"保本":t.status} 8?"text-red-500":Math.abs(t.slippage_bps||0)>2.5?"text-amber-500":"text-slate-600"}`}>{(t.slippage_bps||0).toFixed(1)}bps ${(t.fee_usdt||0).toFixed(2)} {holdMin}m
)}
); } // ─── 详细统计 ──────────────────────────────────────────────────── function StatsPanel() { const [data, setData] = useState(null); useEffect(() => { const f = async () => { try { const r = await authFetch(`/api/live/stats?strategy=${LIVE_STRATEGY}`); if (r.ok) setData(await r.json()); } catch {} }; f(); const iv = setInterval(f, 30000); return () => clearInterval(iv); }, []); if (!data || data.error) return null; return (

详细统计

胜率

{data.win_rate}%

盈亏比

{data.win_loss_ratio}

平均盈利

+{data.avg_win}R

平均亏损

-{data.avg_loss}R

最大回撤

{data.mdd}R

总盈亏

= 0 ? "text-emerald-600" : "text-red-500"}`}>{data.total_pnl >= 0 ? "+" : ""}{data.total_pnl}R

总笔数

{data.total}

滑点P50

{data.p50_slippage_bps}bps

滑点P95

{data.p95_slippage_bps}bps

平均滑点

{data.avg_slippage_bps}bps

{data.by_symbol && (

按币种

{Object.entries(data.by_symbol).map(([sym, v]: [string, any]) => (
{sym.replace("USDT","")} {v.total}笔 {v.win_rate}% = 0 ? "text-emerald-600" : "text-red-500"}`}>{v.total_pnl >= 0 ? "+" : ""}{v.total_pnl}R
))}
)}
); } // ─── 主页面 ────────────────────────────────────────────────────── export default function LiveTradingPage() { const { isLoggedIn, loading } = useAuth(); if (loading) return
加载中...
; if (!isLoggedIn) return (
🔒

请先登录查看实盘

登录
); return (

⚡ 实盘交易

V5.2策略 · 币安USDT永续合约 · 测试网

); }