Show live risk-sizing estimate on plan page instead of stale manual qty.

When 以损定仓 is on, state() overlays next-open k/qty/exit from market preview.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-29 23:52:43 +08:00
parent a47a9b6377
commit 5eb169a636
2 changed files with 69 additions and 7 deletions
+42 -7
View File
@@ -145,14 +145,23 @@ export default function PlanPage() {
const pos = plan?.position;
const open = !!pos?.has_position;
const exitMode = plan?.exit_mode ?? "fixed_usdt";
const exitTarget = plan?.exit_target_usdt ?? plan?.net_profit_target ?? 15;
const riskBased =
plan?.risk_based === true || plan?.sizing_mode === "risk_based";
const riskLiveOk = !riskBased || plan?.risk_sizing_preview?.ok === true;
const displayPerpQty = riskLiveOk ? (plan?.perp_qty_eth ?? 1) : null;
const displayOptQty = riskLiveOk ? (plan?.option_qty_eth ?? 2) : null;
const exitTarget = riskLiveOk
? (plan?.exit_target_usdt ?? plan?.net_profit_target ?? 15)
: null;
const netPnl = pos?.net_pnl ?? 0;
const movePct = pos?.move_pct ?? 0;
const exitRuleLabel =
exitMode === "premium_multiple"
? `权利金×${fmt(plan?.premium_exit_multiple ?? 1, 2)}`
: plan?.risk_based || plan?.sizing_mode === "risk_based"
? `以损定仓 · 固定 ${fmt(exitTarget)} U(基数${fmt(plan?.risk_exit_unit ?? 15)}`
? exitTarget != null
? `以损定仓 · 固定 ${fmt(exitTarget)} U(基数${fmt(plan?.risk_exit_unit ?? 15)}`
: `以损定仓 · 待估算(基数${fmt(plan?.risk_exit_unit ?? 15)}`
: `固定 ${fmt(plan?.net_profit_target ?? 15)} U`;
const phaseLabel = PHASE_ZH[plan?.phase || ""] || plan?.phase || "—";
const atmRule = plan?.fixed_direction_enabled
@@ -206,7 +215,9 @@ export default function PlanPage() {
<span className={`plan-mobile-pnl-num mono ${pnlClass(open ? netPnl : null)}`}>
{open ? fmt(netPnl) : "—"}
</span>
<span className="plan-mobile-sub mono"> {fmt(exitTarget)} U</span>
<span className="plan-mobile-sub mono">
{exitTarget != null ? `${fmt(exitTarget)} U` : "—"}
</span>
</div>
<div className="plan-mobile-pnl-block">
<span className="plan-mobile-label"></span>
@@ -237,7 +248,11 @@ export default function PlanPage() {
</p>
<p>
<span className="plan-rules-k"></span>
{fmt(plan?.perp_qty_eth ?? 1, 2)} ETH / {fmt(plan?.leverage, 0)}x
{" "}
{displayPerpQty != null
? `${fmt(displayPerpQty, 2)} ETH`
: "—"}{" "}
/ {fmt(plan?.leverage, 0)}x
· {fmt(plan?.option_qty_eth ?? 2, 2)} ETH ·
{fmt(plan?.min_option_hours, 0)}h ·
{fmt(plan?.min_option_leverage, 0)}x · {atmRule}
@@ -354,11 +369,27 @@ export default function PlanPage() {
{plan?.risk_last_k
? ` · k=${fmt(plan.risk_last_k, 1)}`
: ""}
{plan?.risk_sizing_preview?.budget != null
? ` · 预算${fmt(plan.risk_sizing_preview.budget, 2)}U`
: ""}
{plan?.risk_sizing_preview?.max_loss != null
? ` · 估亏${fmt(plan.risk_sizing_preview.max_loss, 2)}U`
: ""}
{plan?.risk_sizing_preview?.ok === false
? ` · ${String(plan.risk_sizing_preview.detail || "预览失败")}`
: ""}
{" · "}
</>
) : null}
{fmt(plan?.perp_qty_eth ?? 1, 2)}ETH/
{fmt(plan?.option_qty_eth ?? 2, 2)}ETH ·
{displayPerpQty != null
? `${fmt(displayPerpQty, 2)}ETH`
: "—"}
/
{displayOptQty != null
? `${fmt(displayOptQty, 2)}ETH`
: "—"}{" "}
·
{fmt(plan?.min_option_hours, 0)}h ·
{fmt(plan?.min_option_leverage, 0)}x
{plan?.fixed_direction_enabled
@@ -451,7 +482,11 @@ export default function PlanPage() {
{open ? fmt(netPnl) : "—"}
</span>
{" / "}
{open || exitMode === "fixed_usdt" ? fmt(exitTarget) : "—"}
{open || exitMode === "fixed_usdt"
? exitTarget != null
? fmt(exitTarget)
: "—"
: "—"}
</span>
</div>
<div className="kv">