增加关键位显示

This commit is contained in:
dekun
2026-05-22 10:51:57 +08:00
parent 493b4ff3fb
commit d144cb592a
4 changed files with 41 additions and 11 deletions
+10
View File
@@ -206,11 +206,21 @@ async def api_monitor_board():
snap = await _fetch_flask_json(client, ex, "/api/price_snapshot") snap = await _fetch_flask_json(client, ex, "/api/price_snapshot")
if isinstance(snap, dict): if isinstance(snap, dict):
key_prices = snap.get("key_prices") key_prices = snap.get("key_prices")
flask_ok = isinstance(hub_mon, dict) and hub_mon.get("ok") is not False
flask_err = None
if isinstance(hub_mon, dict) and hub_mon.get("ok") is False:
flask_err = (
hub_mon.get("msg")
or hub_mon.get("error")
or (str(hub_mon.get("text") or "")[:200] or None)
)
out.append( out.append(
{ {
**agent_row, **agent_row,
"review_url": ex.get("review_url") or "", "review_url": ex.get("review_url") or "",
"hub_monitor": hub_mon, "hub_monitor": hub_mon,
"flask_ok": flask_ok,
"flask_error": flask_err,
"meta": (meta or {}).get("meta") if isinstance(meta, dict) else meta, "meta": (meta or {}).get("meta") if isinstance(meta, dict) else meta,
"key_prices": key_prices, "key_prices": key_prices,
} }
+25 -10
View File
@@ -97,9 +97,10 @@
const ag = row.agent || {}; const ag = row.agent || {};
const pos = Array.isArray(ag.positions) ? ag.positions : []; const pos = Array.isArray(ag.positions) ? ag.positions : [];
const hm = row.hub_monitor || {}; const hm = row.hub_monitor || {};
const keys = hm.keys || []; const flaskOk = row.flask_ok !== false && hm.ok !== false;
const orders = hm.orders || []; const keys = flaskOk ? hm.keys || [] : [];
const trends = hm.trends || []; const orders = flaskOk ? hm.orders || [] : [];
const trends = flaskOk ? hm.trends || [] : [];
const kmap = {}; const kmap = {};
(row.key_prices || []).forEach((k) => { (row.key_prices || []).forEach((k) => {
kmap[k.id] = k; kmap[k.id] = k;
@@ -129,12 +130,26 @@
inner += `<div class="rule-tip">${esc(o.symbol)} ${o.direction} 成交${o.trigger_price}</div>`; inner += `<div class="rule-tip">${esc(o.symbol)} ${o.direction} 成交${o.trigger_price}</div>`;
}); });
} }
if ((row.capabilities || []).includes("key") && keys.length) { if ((row.capabilities || []).includes("key")) {
inner += `<div style="margin-top:8px;font-size:12px;color:#b8c4ff">关键位 ${keys.length} 条</div>`; if (!flaskOk) {
keys.slice(0, 6).forEach((k) => { inner += `<div style="margin-top:8px;font-size:12px;color:#f85149">关键位/机器人:策略 Flask 未连通</div>`;
const kp = kmap[k.id] || {}; inner += `<div class="rule-tip">${esc(row.flask_error || hm.msg || "请确认实例 app 已启动,且 HUB_BRIDGE_TOKEN 与实例一致或 APP_AUTH_DISABLED=true")}</div>`;
inner += `<div class="rule-tip">${esc(k.symbol)} ${esc(k.monitor_type)}${k.upper}/下${k.lower} 门控:${esc(kp.gate_summary || "-")}</div>`; } else if (!keys.length) {
}); inner += `<div style="margin-top:8px;color:var(--muted);font-size:12px">关键位:当前无记录(在下单区或实例首页添加)</div>`;
} else {
inner += `<div style="margin-top:8px;font-size:12px;color:#b8c4ff">关键位 ${keys.length} 条</div>`;
keys.slice(0, 8).forEach((k) => {
const kp = kmap[k.id] || kmap[String(k.id)] || {};
const mt = k.monitor_type || k.type || "";
inner += `<div class="rule-tip">${esc(k.symbol)} ${esc(mt)}${k.upper}/下${k.lower}`;
if (kp.price_display != null || kp.price != null) {
inner += ` · 现价 ${esc(kp.price_display != null ? kp.price_display : kp.price)}`;
}
inner += ` · 门控 ${esc(kp.gate_summary || "-")}</div>`;
});
}
} else if ((row.capabilities || []).includes("trend")) {
inner += `<div style="margin-top:6px;color:var(--muted);font-size:12px">该账户为趋势户,无关键位(见趋势计划或下单区)</div>`;
} }
if (trends.length) { if (trends.length) {
inner += `<div style="margin-top:8px;font-size:12px;color:#b8c4ff">趋势计划 ${trends.length} 个运行中</div>`; inner += `<div style="margin-top:8px;font-size:12px;color:#b8c4ff">趋势计划 ${trends.length} 个运行中</div>`;
@@ -144,7 +159,7 @@
} }
} }
const review = row.review_url const review = row.review_url
? `<a href="${esc(row.review_url)}" target="_blank" rel="noopener">复盘</a>` ? `<a href="${esc(row.review_url)}" target="_blank" rel="noopener" title="打开该实例的交易记录与复盘页(不在中控内操作)">交易复盘</a>`
: ""; : "";
return `<div class="card"> return `<div class="card">
<div class="card-head"> <div class="card-head">
+4
View File
@@ -15,6 +15,10 @@
<div id="page-monitor" class="page"> <div id="page-monitor" class="page">
<h1>监控区</h1> <h1>监控区</h1>
<p class="rule-tip" style="margin-top:0">
持仓/余额来自子代理;关键位、机器人单来自各实例 Flask(须 PM2 跑着 crypto_*)。
卡片右上角「交易复盘」= 打开该所交易记录页,不在中控里做复盘。
</p>
<div class="toolbar"> <div class="toolbar">
<button type="button" id="btn-monitor-refresh">立即刷新</button> <button type="button" id="btn-monitor-refresh">立即刷新</button>
<label style="color:var(--muted);font-size:12px;display:flex;align-items:center;gap:6px"> <label style="color:var(--muted);font-size:12px;display:flex;align-items:center;gap:6px">
+2 -1
View File
@@ -154,7 +154,8 @@ python hub.py
| **机器人持仓** | 来自实例 `/api/hub/monitor``order_monitors`active | | **机器人持仓** | 来自实例 `/api/hub/monitor``order_monitors`active |
| **关键位** | 仅 `capabilities``key` 的户;展示门控摘要(`/api/price_snapshot` | | **关键位** | 仅 `capabilities``key` 的户;展示门控摘要(`/api/price_snapshot` |
| **趋势计划** | 仅 Gate 趋势户;`trend_pullback_plans` active | | **趋势计划** | 仅 Gate 趋势户;`trend_pullback_plans` active |
| **复盘** | 新标签打开该户 `review_url`(各实例交易记录页) | | **交易复盘** | 新标签打开该户 Flask 的 `/records`(交易记录、笔记、导出 CSV);**中控不做复盘**,仅跳转 |
| **关键位** | 来自实例 `/api/hub/monitor` + `/api/price_snapshot`(须 Flask 已启动);无记录或 Flask 未连通时卡片会提示原因;**Gate 趋势户**无关键位 |
| **该户全平** | `POST` 子代理 `/emergency/close-all`,仅平该 API Key 仓位 | | **该户全平** | `POST` 子代理 `/emergency/close-all`,仅平该 API Key 仓位 |
| **全局紧急全平** | 对所有已启用户依次全平(不含 `HUB_DISABLED_IDS` 强制关闭的 id | | **全局紧急全平** | 对所有已启用户依次全平(不含 `HUB_DISABLED_IDS` 强制关闭的 id |
| **自动刷新** | 默认每 5 秒请求 `/api/monitor/board` | | **自动刷新** | 默认每 5 秒请求 `/api/monitor/board` |