From 4fe15c41fa1dfb51ce2b2f7d62e979d01603121c Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 8 Aug 2026 15:25:41 +0800 Subject: [PATCH] Sync fleet monitor columns with semi-auto units and K+/-N exits. Row risk/open and exit no longer show full-auto 5%/1:2/base-20 when semi is on. Co-authored-by: Cursor --- control/frontend/src/pages/Monitor.tsx | 116 +++++++++++++++++++++---- 1 file changed, 98 insertions(+), 18 deletions(-) diff --git a/control/frontend/src/pages/Monitor.tsx b/control/frontend/src/pages/Monitor.tsx index e381524..1eb8518 100644 --- a/control/frontend/src/pages/Monitor.tsx +++ b/control/frontend/src/pages/Monitor.tsx @@ -162,8 +162,8 @@ const CLOSE_REASON_ZH: Record = { fixed_usdt: "固定净盈利达标·双腿全平", premium_multiple: "权利金倍数达标·双腿全平", target_perp_only: "净盈利达标·只平永续(期权归档)", - semi_target_points: "半自动·标的到点且组合净利>0", - semi_perp_exit: "半自动·净利基数达标", + semi_target_points: "半自动·指数到行权价±波动点且净利>0", + semi_perp_exit: "半自动·永续净利锁定达标", expiry: "到期结算", emergency: "紧急全平", manual: "手动平仓", @@ -183,7 +183,7 @@ type RiskLines = { lossPct: string | null; exit: string; openRatio: string | null; - /** 表格「风险/开仓」列:永期 5%/1:2/12;期期 ≤2%·12h/C:P/≥24 */ + /** 表格「风险/开仓」列:永期 5%/1:2/12;半自动 虚≤15/1:4/≥30;期期 ≤2%·12h/C:P/≥24 */ riskOrOpen: string; riskOrOpenTitle: string; minHours: string; @@ -266,6 +266,58 @@ function riskLines(strat: Record): RiskLines { }; } + // 半自动:用本单配比/波动点/净利基数,勿展示全自动 risk_* 口径 + if (strat.semi_auto_enabled === true) { + const mny = String(strat.semi_moneyness || "otm").trim().toLowerCase(); + const off = Number(strat.semi_otm_max_offset); + const mnyPart = + mny === "otm" + ? Number.isFinite(off) + ? `虚≤${unitLabel(off)}` + : "虚值" + : mny === "itm" + ? "实值" + : mny === "atm" + ? "平值" + : "半自动"; + const openRatio = `${unitLabel(strat.semi_perp_unit ?? 1)}:${unitLabel( + strat.semi_option_unit ?? 4, + )}`; + const hoursN = Number( + strat.semi_min_option_hours ?? strat.min_option_hours, + ); + const minHours = Number.isFinite(hoursN) + ? `≥${unitLabel(hoursN)}` + : "≥—"; + const move = Number(strat.semi_option_move_points); + const exitU = Number(strat.semi_perp_exit_unit); + const exit = `K±${Number.isFinite(move) ? unitLabel(move) : "—"}/锁${ + Number.isFinite(exitU) ? unitLabel(exitU) : "—" + }`; + const lev = Number(strat.leverage); + const optLev = Number( + strat.semi_min_option_leverage ?? strat.min_option_leverage, + ); + const leverage = `${ + Number.isFinite(lev) ? `${Math.round(lev)}x` : "—" + }/${Number.isFinite(optLev) ? `${Math.round(optLev)}x` : "—"}`; + return { + riskBased, + isOo: false, + sizing: riskBased ? "以损定仓(A)" : "手动开仓(B)", + sizingShort: riskBased ? "A" : "B", + lossPct: null, + exit, + openRatio, + riskOrOpen: `${mnyPart}/${openRatio}/${minHours}`, + riskOrOpenTitle: + "半自动行权·偏离 / 永续:期权配比 / 最短剩余(h)", + minHours, + leverage, + leverageTitle: "永续杠杆 / 半自动期权最低杠杆", + }; + } + const exitMode = String(strat.exit_mode || "fixed_usdt"); let exit: string; if (riskBased && exitMode === "premium_multiple") { @@ -381,7 +433,7 @@ function modeLabelTitle(mode: string, strat: Record): string { hedgeModeShort(strat) === "期期" ? "期期=双期权对冲" : hedgeModeShort(strat) === "半自动" - ? "半自动=人工看法·机器盯盘开平·平仓后停" + ? "半自动=人工看法·机器盯盘开平·平仓后停;出场=行权价±波动点/永续净利锁定" : "永期=永续+期权"; return `${label}(${riskBased ? "A=以损定仓" : "B=手动开仓"};${hedge})`; } @@ -1194,20 +1246,48 @@ export default function MonitorPage() { {detail.strat.semi_auto_enabled === true - ? `半自动·${ - detail.strat.semi_moneyness === "itm" - ? "实值" - : detail.strat.semi_moneyness === "atm" - ? "平值" - : "虚值" - } ${fmt(detail.strat.semi_perp_unit, 0)}:${fmt( - detail.strat.semi_option_unit, - 0, - )} ·点${fmt(detail.strat.semi_option_move_points, 0)}/净≥${fmt( - detail.strat.semi_net_exit_target ?? - detail.strat.semi_perp_exit_unit, - 2, - )}U` + ? (() => { + const move = Number( + detail.strat.semi_option_move_points, + ); + const view = + detail.strat.semi_view_side === "short" + ? "short" + : "long"; + const k = Number( + detail.position?.strike ?? + detail.pair?.strike, + ); + const optTgt = + Number.isFinite(k) && Number.isFinite(move) + ? `K${Math.round(k)}→${fmtExPx( + "perp", + view === "short" ? k - move : k + move, + )}` + : `K±${ + Number.isFinite(move) + ? unitLabel(move) + : "—" + }`; + const lock = fmt( + detail.strat.semi_net_exit_target ?? + detail.strat.semi_perp_exit_unit, + 2, + ); + const mny = + detail.strat.semi_moneyness === "itm" + ? "实值" + : detail.strat.semi_moneyness === "atm" + ? "平值" + : "虚值"; + return `半自动·${mny} ${fmt( + detail.strat.semi_perp_unit, + 0, + )}:${fmt( + detail.strat.semi_option_unit, + 0, + )} · 期权目标${optTgt} · 永续锁≥${lock}U`; + })() : `${fmt(detail.strat.exit_target_usdt, 2)} USDT`}