Show OKX-style perp/option position cards on plan page.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+135
-28
@@ -6,6 +6,24 @@ function fmt(n: number | null | undefined, d = 2) {
|
||||
return n.toFixed(d);
|
||||
}
|
||||
|
||||
function pnlClass(n: number | null | undefined) {
|
||||
if (n == null || Number.isNaN(n) || n === 0) return "";
|
||||
return n > 0 ? "pos-pnl-profit" : "pos-pnl-loss";
|
||||
}
|
||||
|
||||
const PHASE_ZH: Record<string, string> = {
|
||||
idle: "空闲",
|
||||
wait_signal: "等待信号",
|
||||
opening: "开仓中",
|
||||
open: "持仓中",
|
||||
closing: "平仓中",
|
||||
resting: "休息中",
|
||||
paused: "已暂停",
|
||||
stopped: "已停开",
|
||||
outside_window: "窗外",
|
||||
liquidity_wait: "流动性等待",
|
||||
};
|
||||
|
||||
export default function PlanPage() {
|
||||
const [snap, setSnap] = useState<MarketSnapshot | null>(null);
|
||||
const [plan, setPlan] = useState<PlanState | null>(null);
|
||||
@@ -56,22 +74,10 @@ export default function PlanPage() {
|
||||
);
|
||||
|
||||
const pos = plan?.position;
|
||||
const open = !!pos?.has_position;
|
||||
const exitN = plan?.exit_move_points ?? 30;
|
||||
const move = pos?.move_points ?? 0;
|
||||
|
||||
const phaseZh: Record<string, string> = {
|
||||
idle: "空闲",
|
||||
wait_signal: "等待信号",
|
||||
opening: "开仓中",
|
||||
open: "持仓中",
|
||||
closing: "平仓中",
|
||||
resting: "休息中",
|
||||
paused: "已暂停",
|
||||
stopped: "已停开",
|
||||
outside_window: "窗外",
|
||||
liquidity_wait: "流动性等待",
|
||||
};
|
||||
const phaseLabel = phaseZh[plan?.phase || ""] || plan?.phase || "—";
|
||||
const phaseLabel = PHASE_ZH[plan?.phase || ""] || plan?.phase || "—";
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -125,7 +131,7 @@ export default function PlanPage() {
|
||||
{busy ? <span className="meta">{busy}…</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginBottom: 12 }}>
|
||||
<div className="card plan-summary" style={{ marginBottom: 12 }}>
|
||||
<div className="kv">
|
||||
<span>策略</span>
|
||||
<span>
|
||||
@@ -154,29 +160,24 @@ export default function PlanPage() {
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>权益</span>
|
||||
<span className="mono">{fmt(plan?.ledger?.equity)} / 可用 {fmt(plan?.ledger?.available)}</span>
|
||||
<span className="mono">
|
||||
{fmt(plan?.ledger?.equity)} / 可用 {fmt(plan?.ledger?.available)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>当前组</span>
|
||||
<span className="mono">{pos?.group_id || "—"}</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>方向</span>
|
||||
<span className="mono">
|
||||
{pos?.has_position
|
||||
? `永续${pos.perp_side === "long" ? "多" : "空"} + 买${pos.option_side === "call" ? "Call" : "Put"}`
|
||||
: "—"}{" "}
|
||||
{biasTag}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>初始权利金</span>
|
||||
<span className="mono">{fmt(pos?.initial_premium)}</span>
|
||||
<span>信号方向</span>
|
||||
<span className="mono">{biasTag}</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
<span>永续浮盈 / 距覆盖</span>
|
||||
<span className="mono">
|
||||
{fmt(pos?.perp_upl)} / {fmt(pos?.premium_gap)}
|
||||
<span className={pnlClass(pos?.perp_upl)}>{fmt(pos?.perp_upl)}</span>
|
||||
{" / "}
|
||||
{fmt(pos?.premium_gap)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="kv">
|
||||
@@ -193,6 +194,112 @@ export default function PlanPage() {
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="pos-embed-grid">
|
||||
{open ? (
|
||||
<>
|
||||
<div className="pos-card">
|
||||
<div className="pos-card-head">
|
||||
<div className="pos-card-symbol">
|
||||
<strong>{pos?.perp_inst_id || "ETH-USDT-SWAP"}</strong>
|
||||
<span
|
||||
className={
|
||||
pos?.perp_side === "long"
|
||||
? "pos-side-badge pos-side-long"
|
||||
: "pos-side-badge pos-side-short"
|
||||
}
|
||||
>
|
||||
{pos?.perp_side === "long" ? "做多" : "做空"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pos-meta">
|
||||
<span className="pos-meta-item">永续持仓</span>
|
||||
<span className="pos-meta-item">组 {pos?.group_id}</span>
|
||||
<span className="pos-meta-item mono">数量 {fmt(pos?.perp_qty_eth, 2)} ETH</span>
|
||||
</div>
|
||||
<div className="pos-grid">
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">开仓价</span>
|
||||
<span className="pos-value mono">{fmt(pos?.perp_entry_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">可平价</span>
|
||||
<span className="pos-value mono">{fmt(pos?.perp_mark_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">浮盈亏</span>
|
||||
<span className={`pos-value mono ${pnlClass(pos?.perp_upl)}`}>
|
||||
{fmt(pos?.perp_upl)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">指数</span>
|
||||
<span className="pos-value mono">{fmt(pos?.index_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">开仓指数</span>
|
||||
<span className="pos-value mono">{fmt(pos?.entry_index_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">波动点数</span>
|
||||
<span className="pos-value mono">{fmt(move, 1)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pos-card">
|
||||
<div className="pos-card-head">
|
||||
<div className="pos-card-symbol">
|
||||
<strong>{pos?.option_inst_id || "期权"}</strong>
|
||||
<span
|
||||
className={
|
||||
pos?.option_side === "call"
|
||||
? "pos-side-badge pos-side-long"
|
||||
: "pos-side-badge pos-side-short"
|
||||
}
|
||||
>
|
||||
{pos?.option_side === "call" ? "看涨 Call" : "看跌 Put"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pos-meta">
|
||||
<span className="pos-meta-item">期权持仓</span>
|
||||
<span className="pos-meta-item">到期 {pos?.expiry_ymd || "—"}</span>
|
||||
<span className="pos-meta-item">行权 {fmt(pos?.strike, 0)}</span>
|
||||
<span className="pos-meta-item mono">
|
||||
{fmt(pos?.option_qty_eth, 2)} ETH · {fmt(pos?.option_qty_contracts, 0)} 张
|
||||
</span>
|
||||
</div>
|
||||
<div className="pos-grid">
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">开仓均价</span>
|
||||
<span className="pos-value mono">{fmt(pos?.option_entry_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">标记/买一</span>
|
||||
<span className="pos-value mono">{fmt(pos?.option_mark_px)}</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">浮盈亏</span>
|
||||
<span className={`pos-value mono ${pnlClass(pos?.option_upl)}`}>
|
||||
{fmt(pos?.option_upl)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="pos-cell">
|
||||
<span className="pos-label">初始权利金</span>
|
||||
<span className="pos-value mono">{fmt(pos?.initial_premium)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="pos-empty">永续持仓 · 暂无</div>
|
||||
<div className="pos-empty">期权持仓 · 暂无</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid-2">
|
||||
|
||||
Reference in New Issue
Block a user