fix(hub): align trend pullback card with instance layout
Match strategy page plan card: 3x3 metrics, DCA table, breakeven row, snapshot footer; PnL percent on plan margin. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1320,139 +1320,222 @@ body.market-chart-fs-open {
|
||||
border-color: rgba(0, 255, 157, 0.38);
|
||||
}
|
||||
|
||||
.hub-trend-plan-list {
|
||||
/* 趋势回调:与四所实例 strategy_trend_panel 同款卡片 */
|
||||
.hub-trend-running-title {
|
||||
margin: 0 0 10px;
|
||||
font-size: 0.95rem;
|
||||
color: #b8c4ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hub-trend-plan-list.running-plans-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card {
|
||||
.hub-trend-plan-card.plan-position-card {
|
||||
background: #141a2a;
|
||||
border: 1px solid #2a3150;
|
||||
border-radius: 12px;
|
||||
padding: 12px 14px;
|
||||
background: rgba(0, 0, 0, 0.28);
|
||||
border: 1px solid var(--border-soft);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-head {
|
||||
.hub-trend-plan-card .plan-card-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hub-trend-plan-status {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.hub-trend-plan-meta {
|
||||
.hub-trend-plan-card .plan-card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 14px;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #f0f2ff;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-card-meta {
|
||||
font-size: 0.76rem;
|
||||
color: #8892b0;
|
||||
line-height: 1.55;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-meta .pos-meta-accent,
|
||||
.hub-trend-plan-meta strong {
|
||||
.hub-trend-plan-card .plan-card-meta .accent {
|
||||
color: #6ab8ff;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-card-meta strong {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.hub-trend-plan-foot {
|
||||
margin-top: 10px;
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
.hub-trend-plan-card .plan-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 10px 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.pos-value.pos-tp-program {
|
||||
color: #8fc8ff;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card--horizontal {
|
||||
.hub-trend-plan-card .plan-cell {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14px 18px;
|
||||
align-items: flex-start;
|
||||
background: linear-gradient(145deg, rgba(12, 18, 32, 0.92), rgba(8, 12, 22, 0.88));
|
||||
border-color: rgba(0, 212, 255, 0.22);
|
||||
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-body {
|
||||
flex: 1 1 320px;
|
||||
min-width: 0;
|
||||
.hub-trend-plan-card .plan-cell .lbl {
|
||||
font-size: 0.72rem;
|
||||
color: #8b95b8;
|
||||
}
|
||||
|
||||
.hub-trend-plan-side {
|
||||
flex: 1 1 220px;
|
||||
min-width: 200px;
|
||||
max-width: 100%;
|
||||
.hub-trend-plan-card .plan-cell .val {
|
||||
color: #f0f2ff;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.hub-trend-dca-block {
|
||||
padding: 8px 10px;
|
||||
background: rgba(0, 0, 0, 0.22);
|
||||
border: 1px solid var(--border-soft);
|
||||
.hub-trend-plan-card .plan-cell .val.pnl-profit {
|
||||
color: #4cd97f;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-cell .val.pnl-loss {
|
||||
color: #ff6666;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-cell .val.pnl-neutral {
|
||||
color: #cfd3ef;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .btn-close-plan {
|
||||
padding: 7px 14px;
|
||||
background: #5c1e2a;
|
||||
color: #ffb4b4;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.hub-trend-dca-title {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
margin-bottom: 6px;
|
||||
.hub-trend-plan-card .btn-close-plan:hover {
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.hub-trend-dca-table {
|
||||
.hub-trend-plan-card .plan-dca-block {
|
||||
margin-top: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px dashed #2a3558;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-dca-title {
|
||||
font-size: 0.74rem;
|
||||
color: #8b95b8;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .plan-dca-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 11px;
|
||||
font-size: 0.76rem;
|
||||
}
|
||||
|
||||
.hub-trend-dca-table th,
|
||||
.hub-trend-dca-table td {
|
||||
padding: 4px 6px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
.hub-trend-plan-card .plan-dca-table th,
|
||||
.hub-trend-plan-card .plan-dca-table td {
|
||||
padding: 6px 8px;
|
||||
border-bottom: 1px solid #243050;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hub-trend-dca-table th {
|
||||
color: var(--muted);
|
||||
.hub-trend-plan-card .plan-dca-table th {
|
||||
color: #6a7598;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hub-trend-dca-table .dca-done {
|
||||
color: var(--green);
|
||||
.hub-trend-plan-card .plan-dca-table .st-done {
|
||||
color: #4cd97f;
|
||||
}
|
||||
|
||||
.hub-trend-dca-table .dca-pending {
|
||||
color: var(--muted);
|
||||
.hub-trend-plan-card .plan-dca-table .st-pending {
|
||||
color: #9aa3c4;
|
||||
}
|
||||
|
||||
.exchange-fullscreen .hub-trend-plan-list {
|
||||
display: block;
|
||||
.hub-trend-plan-card .hub-plan-breakeven-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-be-label {
|
||||
font-size: 0.78rem;
|
||||
color: #cfd3ef;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-be-input {
|
||||
width: 72px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #304164;
|
||||
background: #0f1424;
|
||||
color: #cfd3ef;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-be-btn {
|
||||
padding: 6px 12px;
|
||||
background: #1f4a3a;
|
||||
color: #8fc8ff;
|
||||
border-radius: 8px;
|
||||
font-size: 0.78rem;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-be-btn--static {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-be-done {
|
||||
color: #6ab88a;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .hub-plan-account-foot {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .badge.direction-long {
|
||||
color: #4cd97f;
|
||||
border-color: rgba(76, 217, 127, 0.45);
|
||||
}
|
||||
|
||||
.hub-trend-plan-card .badge.direction-short {
|
||||
color: #ff6666;
|
||||
border-color: rgba(255, 102, 102, 0.45);
|
||||
}
|
||||
|
||||
.exchange-fullscreen .hub-trend-plan-card.plan-position-card {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.exchange-fullscreen .hub-trend-plan-card--horizontal {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.exchange-fullscreen .hub-trend-plan-metrics-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
gap: 10px 16px;
|
||||
}
|
||||
|
||||
.exchange-fullscreen .hub-trend-plan-grid {
|
||||
flex: 1 1 280px;
|
||||
@media (max-width: 720px) {
|
||||
.hub-trend-plan-card .plan-card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* 顺势加仓 */
|
||||
|
||||
@@ -345,6 +345,76 @@
|
||||
return { text: pnlText, cls: pnlCls(upnl) };
|
||||
}
|
||||
|
||||
/** 与实例策略页一致:浮盈亏 % = 浮盈亏 / 计划保证金 */
|
||||
function formatTrendPlanFloatingPnl(upnl, planMargin) {
|
||||
if (upnl == null || !Number.isFinite(Number(upnl))) {
|
||||
return { text: "—", cls: "" };
|
||||
}
|
||||
let pnlText = fmt(upnl, 2) + "U";
|
||||
const margin = Number(planMargin);
|
||||
if (Number.isFinite(margin) && margin > 0) {
|
||||
const pct = (Number(upnl) / margin) * 100;
|
||||
pnlText += ` (${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%)`;
|
||||
}
|
||||
const n = Number(upnl);
|
||||
let cls = "pnl-neutral";
|
||||
if (n > 0) cls = "pnl-profit";
|
||||
else if (n < 0) cls = "pnl-loss";
|
||||
return { text: pnlText, cls };
|
||||
}
|
||||
|
||||
function renderDirectionBadge(side) {
|
||||
const s = normSide(side);
|
||||
const label = sideDirLabel(side);
|
||||
const cls = s === "long" ? "direction-long" : s === "short" ? "direction-short" : "";
|
||||
if (!cls) return esc(String(label));
|
||||
return `<span class="badge ${cls}">${esc(label)}</span>`;
|
||||
}
|
||||
|
||||
function resolveTrendDcaLevels(t) {
|
||||
if (Array.isArray(t.dca_levels) && t.dca_levels.length) return t.dca_levels;
|
||||
const plan = t || {};
|
||||
let grid = [];
|
||||
let legAmounts = [];
|
||||
try {
|
||||
grid = JSON.parse(plan.grid_prices_json || "[]");
|
||||
if (!Array.isArray(grid)) grid = [];
|
||||
} catch (_e) {
|
||||
grid = [];
|
||||
}
|
||||
try {
|
||||
legAmounts = JSON.parse(plan.leg_amounts_json || "[]");
|
||||
if (!Array.isArray(legAmounts)) legAmounts = [];
|
||||
} catch (_e2) {
|
||||
legAmounts = [];
|
||||
}
|
||||
const legsDone = Number(plan.legs_done) || 0;
|
||||
const dcaLegs = Number(plan.dca_legs) || 0;
|
||||
const firstDone = Number(plan.first_order_done) !== 0;
|
||||
const out = [
|
||||
{
|
||||
label: "首仓",
|
||||
price: null,
|
||||
contracts: plan.first_order_amount,
|
||||
status: firstDone ? "done" : "pending",
|
||||
status_label: firstDone ? "已开仓" : "待开仓",
|
||||
},
|
||||
];
|
||||
const n = Math.max(grid.length, legAmounts.length, dcaLegs);
|
||||
for (let idx = 0; idx < n; idx += 1) {
|
||||
const legI = idx + 1;
|
||||
const done = legI <= legsDone;
|
||||
out.push({
|
||||
label: `补仓${legI}`,
|
||||
price: idx < grid.length ? grid[idx] : null,
|
||||
contracts: idx < legAmounts.length ? legAmounts[idx] : null,
|
||||
status: done ? "done" : "pending",
|
||||
status_label: done ? "已补仓" : "待补仓",
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function pnlCls(v) {
|
||||
const n = Number(v);
|
||||
if (!Number.isFinite(n) || n === 0) return "";
|
||||
@@ -1333,6 +1403,8 @@
|
||||
btn.onclick = (ev) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const msg = (btn.dataset.confirm || "").trim();
|
||||
if (msg && !confirm(msg)) return;
|
||||
openInstance(btn.dataset.exId, btn.dataset.next || "/", {
|
||||
newTab: ev.ctrlKey || ev.metaKey,
|
||||
});
|
||||
@@ -1514,7 +1586,7 @@
|
||||
}
|
||||
|
||||
function renderTrendDcaTable(t, tickMap) {
|
||||
const levels = Array.isArray(t.dca_levels) ? t.dca_levels : [];
|
||||
const levels = resolveTrendDcaLevels(t);
|
||||
if (!levels.length) return "";
|
||||
const sym = t.exchange_symbol || t.symbol || "";
|
||||
const rows = levels
|
||||
@@ -1525,7 +1597,7 @@
|
||||
: "—";
|
||||
const amt =
|
||||
lv.contracts != null && lv.contracts !== "" ? esc(String(lv.contracts)) : "—";
|
||||
const stCls = lv.status === "done" ? "dca-done" : "dca-pending";
|
||||
const stCls = lv.status === "done" ? "st-done" : "st-pending";
|
||||
const label = lv.status_label || (lv.status === "done" ? "已补仓" : "待补仓");
|
||||
return `<tr>
|
||||
<td>${esc(lv.label || lv.leg_key || "—")}</td>
|
||||
@@ -1535,16 +1607,16 @@
|
||||
</tr>`;
|
||||
})
|
||||
.join("");
|
||||
return `<div class="hub-trend-dca-block">
|
||||
<div class="hub-trend-dca-title">补仓计划明细</div>
|
||||
<table class="hub-trend-dca-table">
|
||||
<thead><tr><th>档位</th><th>触发价</th><th>张数</th><th>状态</th></tr></thead>
|
||||
<tbody>${rows}</tbody>
|
||||
return `<div class="plan-dca-block">
|
||||
<div class="plan-dca-title">补仓计划明细</div>
|
||||
<table class="plan-dca-table">
|
||||
<tr><th>档位</th><th>触发价</th><th>张数</th><th>状态</th></tr>
|
||||
${rows}
|
||||
</table>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderTrendPlanCard(t, tickMap, pos) {
|
||||
function renderTrendPlanCard(t, tickMap, pos, exchangeRow) {
|
||||
const sym = t.exchange_symbol || t.symbol || "";
|
||||
const side = (t.direction || "long").toLowerCase();
|
||||
const sl = t.stop_loss_display || fmtSymbolPrice(t.stop_loss, sym, tickMap);
|
||||
@@ -1564,66 +1636,79 @@
|
||||
? esc(legsDone)
|
||||
: "—";
|
||||
const upnlTrend = resolveTrendFloatingPnl(pos, t);
|
||||
const notional =
|
||||
pos && pos.notional_usdt != null
|
||||
? pos.notional_usdt
|
||||
: t.plan_margin_capital != null
|
||||
? Number(t.plan_margin_capital) * Number(t.leverage || 1)
|
||||
: null;
|
||||
const pnlFmt = formatFloatingPnlText(upnlTrend, notional);
|
||||
const pnlInner =
|
||||
const pnlFmt = formatTrendPlanFloatingPnl(upnlTrend, t.plan_margin_capital);
|
||||
const pnlVal =
|
||||
pnlFmt.text === "—"
|
||||
? "—"
|
||||
: `<span class="pos-value ${pnlFmt.cls}">${esc(pnlFmt.text)}</span>`;
|
||||
const sizing = resolveTrendSizingFooter({}, t, true);
|
||||
const levTxt =
|
||||
sizing.leverage != null && sizing.leverage !== "" ? `${esc(sizing.leverage)}x` : "—";
|
||||
const baseTxt =
|
||||
sizing.planBase != null && sizing.planBase !== "" ? `${fmt(sizing.planBase, 2)}U` : "—";
|
||||
const ratioTxt =
|
||||
sizing.positionRatio != null && sizing.positionRatio !== ""
|
||||
? `${fmt(sizing.positionRatio, 2)}%`
|
||||
: "—";
|
||||
: `<span class="val ${pnlFmt.cls}">${esc(pnlFmt.text)}</span>`;
|
||||
const riskTxt =
|
||||
t.risk_percent != null && t.risk_percent !== "" ? `${esc(t.risk_percent)}%` : "—";
|
||||
const footHtml = `<div class="hub-trend-plan-foot pos-footer">
|
||||
<span>杠杆: ${levTxt}</span>
|
||||
<span>计划基数: ${baseTxt}</span>
|
||||
<span>仓位占比: ${ratioTxt}</span>
|
||||
</div>`;
|
||||
const snapTxt =
|
||||
t.snapshot_available_usdt != null && t.snapshot_available_usdt !== ""
|
||||
? `${fmt(t.snapshot_available_usdt, 2)}U`
|
||||
: "—";
|
||||
const marginTxt =
|
||||
t.plan_margin_capital != null && t.plan_margin_capital !== ""
|
||||
? `≈${fmt(t.plan_margin_capital, 2)}U`
|
||||
: "—";
|
||||
const levTxt = t.leverage != null && t.leverage !== "" ? `${esc(t.leverage)}x` : "—";
|
||||
const bePct =
|
||||
t.breakeven_offset_pct != null && t.breakeven_offset_pct !== ""
|
||||
? esc(t.breakeven_offset_pct)
|
||||
: "0.3";
|
||||
const exId = exchangeRow && exchangeRow.id != null ? esc(exchangeRow.id) : "";
|
||||
const canOpen = !!(exchangeRow && (exchangeRow.flask_url_browser || exchangeRow.flask_url));
|
||||
const endBtn = canOpen
|
||||
? `<a href="#" class="btn-close-plan btn-open-instance" data-ex-id="${exId}" data-next="/stop_trend_pullback/${esc(t.id)}" data-confirm="结束计划:市价平仓并撤掉该合约全部挂单,确定?">结束计划</a>`
|
||||
: "";
|
||||
const beBtn = canOpen
|
||||
? `<a href="#" class="hub-plan-be-btn btn-open-instance" data-ex-id="${exId}" data-next="/strategy">保本移交下单监控</a>`
|
||||
: `<span class="hub-plan-be-btn hub-plan-be-btn--static">保本移交下单监控</span>`;
|
||||
const beApplied =
|
||||
t.breakeven_applied
|
||||
? `<span class="hub-plan-be-done">已保本 ${esc(String(t.breakeven_applied_at || "").slice(0, 16))}</span>`
|
||||
: "";
|
||||
const dcaHtml = renderTrendDcaTable(t, tickMap);
|
||||
return `<div class="hub-trend-plan-card hub-pos-card hub-trend-plan-card--horizontal">
|
||||
<div class="hub-trend-plan-body">
|
||||
<div class="hub-trend-plan-head">
|
||||
<span class="hub-trend-plan-title">#${esc(t.id)} ${esc(sym)} ${renderDirectionHtml(t.direction)}</span>
|
||||
<span class="hub-trend-plan-status">${esc(t.status || "active")}</span>
|
||||
return `<div class="plan-position-card hub-trend-plan-card">
|
||||
<div class="plan-card-head">
|
||||
<div class="plan-card-title">
|
||||
<span>#${esc(t.id)} ${esc(sym)}</span>
|
||||
${renderDirectionBadge(t.direction)}
|
||||
</div>
|
||||
<div class="hub-trend-plan-meta">
|
||||
<span>来源: 趋势回调计划</span>
|
||||
<span>风险: ${riskTxt}</span>
|
||||
<span>${esc(trendAddZoneLabel(t.direction))} ${esc(addZone)}</span>
|
||||
<span>已补仓 <strong>${legsTxt}</strong></span>
|
||||
${endBtn}
|
||||
</div>
|
||||
<div class="hub-trend-plan-metrics-row">
|
||||
<div class="pos-grid hub-trend-plan-grid">
|
||||
<div class="pos-cell"><span class="pos-label">均价</span><span class="pos-value">${esc(avg)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">止损</span><span class="pos-value">${esc(sl)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">止盈</span><span class="pos-value pos-tp-program">程序监控 · ${esc(tp)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">盈亏比</span><span class="pos-value">${esc(rrTxt)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">标记价</span><span class="pos-value">${esc(mark)}</span></div>
|
||||
<div class="pos-cell"><span class="pos-label">浮盈亏</span>${pnlInner}</div>
|
||||
<div class="plan-card-meta">
|
||||
来源: 趋势回调计划 | 风险: ${riskTxt}
|
||||
| <span class="accent">${esc(trendAddZoneLabel(t.direction))} ${esc(addZone)}</span>
|
||||
| 已补仓 <strong>${legsTxt}</strong>
|
||||
</div>
|
||||
${footHtml}
|
||||
<div class="plan-card-grid">
|
||||
<div class="plan-cell"><span class="lbl">均价</span><span class="val">${esc(avg)}</span></div>
|
||||
<div class="plan-cell"><span class="lbl">止损</span><span class="val">${esc(sl)}</span></div>
|
||||
<div class="plan-cell"><span class="lbl">止盈</span><span class="val">${esc(tp)}</span></div>
|
||||
<div class="plan-cell"><span class="lbl">盈亏比</span><span class="val">${esc(rrTxt)}</span></div>
|
||||
<div class="plan-cell"><span class="lbl">标记价</span><span class="val">${esc(mark)}</span></div>
|
||||
<div class="plan-cell"><span class="lbl">浮盈亏</span>${pnlVal}</div>
|
||||
</div>
|
||||
${dcaHtml}
|
||||
<div class="plan-card-meta hub-plan-breakeven-row">
|
||||
<label class="hub-plan-be-label">
|
||||
保本移交 偏移%
|
||||
<input type="number" disabled value="${bePct}" class="hub-plan-be-input" />
|
||||
</label>
|
||||
${beBtn}
|
||||
${beApplied}
|
||||
</div>
|
||||
<div class="plan-card-meta hub-plan-account-foot">
|
||||
快照可用: ${esc(snapTxt)} | 计划保证金${esc(marginTxt)} | 杠杆: ${levTxt}
|
||||
</div>
|
||||
${dcaHtml ? `<div class="hub-trend-plan-side">${dcaHtml}</div>` : ""}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderTrendSection(trends, tickMap, positions) {
|
||||
function renderTrendSection(trends, tickMap, positions, exchangeRow) {
|
||||
if (!trends || !trends.length) return "";
|
||||
const posList = Array.isArray(positions) ? positions : [];
|
||||
return `<div class="hub-trend-plan-list">${trends
|
||||
const cards = trends
|
||||
.map((t) => {
|
||||
const sym = t.exchange_symbol || t.symbol || "";
|
||||
const side = (t.direction || "long").toLowerCase();
|
||||
@@ -1636,9 +1721,13 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
return renderTrendPlanCard(t, tickMap, matched);
|
||||
return renderTrendPlanCard(t, tickMap, matched, exchangeRow);
|
||||
})
|
||||
.join("")}</div>`;
|
||||
.join("");
|
||||
return `<div class="hub-trend-running">
|
||||
<div class="hub-trend-running-title">运行中的计划</div>
|
||||
<div class="running-plans-stack hub-trend-plan-list">${cards}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder, trendPlan, tickMap) {
|
||||
@@ -2052,7 +2141,7 @@
|
||||
if ((row.capabilities || []).includes("trend")) {
|
||||
html += renderHubSectionCard(
|
||||
"趋势回调",
|
||||
renderTrendSection(trends, tickMap, pos),
|
||||
renderTrendSection(trends, tickMap, pos, row),
|
||||
"暂无运行中的趋势回调计划"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'" />
|
||||
<noscript><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" /></noscript>
|
||||
<link rel="stylesheet" href="/assets/app.css?v=20260604-hub-trend-dca" />
|
||||
<link rel="stylesheet" href="/assets/app.css?v=20260604-hub-trend-instance" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-bg" aria-hidden="true"></div>
|
||||
@@ -235,6 +235,6 @@
|
||||
<div id="toast"></div>
|
||||
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
||||
<script src="/assets/chart.js?v=20260604-hub-trend-plan"></script>
|
||||
<script src="/assets/app.js?v=20260604-hub-trend-dca"></script>
|
||||
<script src="/assets/app.js?v=20260604-hub-trend-instance"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user