feat: 持仓快照盈亏比与交易所止损已保本标识
盈亏比固定用开仓 initial_stop_loss 计算,人工改委托后不变化;轮询交易所止损触发价相对成交价判定已保本,四所实例与中控统一显示绿色标识。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+19
-19
@@ -94,6 +94,10 @@ from key_monitor_lib import (
|
||||
rs_break_from_direction,
|
||||
run_rs_level_alert_tick,
|
||||
)
|
||||
from order_monitor_display_lib import (
|
||||
apply_order_price_display_fields,
|
||||
enrich_order_display_fields,
|
||||
)
|
||||
from wechat_notify_lib import build_wechat_rs_level_message, send_wechat_webhook
|
||||
from hub_auth import request_allowed as hub_request_allowed
|
||||
from history_window_lib import (
|
||||
@@ -2126,13 +2130,7 @@ def enrich_order_item(raw_item, current_capital):
|
||||
ratio = round(margin / current_capital * 100, 2) if current_capital else 0
|
||||
item["notional_value"] = notional
|
||||
item["position_ratio"] = ratio
|
||||
item["rr_ratio"] = calc_planned_rr_ratio(
|
||||
item.get("direction") or "long",
|
||||
item.get("trigger_price"),
|
||||
item.get("stop_loss"),
|
||||
item.get("initial_stop_loss"),
|
||||
item.get("take_profit"),
|
||||
)
|
||||
enrich_order_display_fields(item, calc_rr_ratio)
|
||||
try:
|
||||
be = item.get("breakeven_enabled")
|
||||
item["breakeven_enabled"] = 0 if be is not None and int(be) == 0 else 1
|
||||
@@ -5934,13 +5932,7 @@ def api_price_snapshot():
|
||||
entry = float(r["trigger_price"] or 0)
|
||||
pnl = calc_pnl(r["direction"], entry, price, margin, leverage) if entry > 0 else 0
|
||||
pnl_pct = round((pnl / margin * 100), 4) if margin > 0 else 0
|
||||
rr_ratio = calc_planned_rr_ratio(
|
||||
r["direction"],
|
||||
entry,
|
||||
r["stop_loss"],
|
||||
r["initial_stop_loss"],
|
||||
r["take_profit"],
|
||||
)
|
||||
exchange_tpsl = {"sl": None, "tp": None}
|
||||
ex_sym = resolve_monitor_exchange_symbol(r)
|
||||
prow = _select_live_position_row(all_swap_positions, ex_sym, r["direction"])
|
||||
lev_row = r["leverage"] if "leverage" in r.keys() else None
|
||||
@@ -5950,7 +5942,6 @@ def api_price_snapshot():
|
||||
"symbol": r["symbol"],
|
||||
"float_pnl": round(pnl, 2),
|
||||
"float_pct": pnl_pct,
|
||||
"rr_ratio": rr_ratio,
|
||||
"plan_margin": round(margin, 2) if margin else None,
|
||||
"exchange_initial_margin": None,
|
||||
"exchange_notional": None,
|
||||
@@ -5985,16 +5976,25 @@ def api_price_snapshot():
|
||||
payload["price_display"] = px_disp
|
||||
if exchange_private_api_configured():
|
||||
try:
|
||||
payload["exchange_tpsl"] = fetch_exchange_tpsl_slots(
|
||||
exchange_tpsl = fetch_exchange_tpsl_slots(
|
||||
ex_sym,
|
||||
r["direction"],
|
||||
plan_sl=r["stop_loss"],
|
||||
plan_tp=r["take_profit"],
|
||||
)
|
||||
except Exception:
|
||||
payload["exchange_tpsl"] = {"sl": None, "tp": None}
|
||||
else:
|
||||
payload["exchange_tpsl"] = {"sl": None, "tp": None}
|
||||
exchange_tpsl = {"sl": None, "tp": None}
|
||||
payload["exchange_tpsl"] = exchange_tpsl
|
||||
apply_order_price_display_fields(
|
||||
payload,
|
||||
direction=r["direction"],
|
||||
entry_price=entry,
|
||||
initial_stop_loss=r["initial_stop_loss"],
|
||||
stop_loss=r["stop_loss"],
|
||||
take_profit=r["take_profit"],
|
||||
calc_rr_ratio_fn=calc_rr_ratio,
|
||||
exchange_tpsl=exchange_tpsl,
|
||||
)
|
||||
order_prices.append(payload)
|
||||
|
||||
return jsonify({
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
.pos-meta-item:not(:last-child)::after{content:'|';margin:0 8px;color:#3d4659}
|
||||
.pos-meta-on{color:#6eb5ff}
|
||||
.pos-meta-off{color:#7d8799}
|
||||
.pos-breakeven-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:6px;font-size:.72rem;font-weight:600;background:#1a3d2e;color:#4cd97f}
|
||||
.pos-card-symbol{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
|
||||
.pos-card-symbol strong{font-size:.95rem;color:#fff;font-weight:600}
|
||||
.pos-side-badge{padding:3px 8px;border-radius:6px;font-size:.72rem;font-weight:500;line-height:1.2}
|
||||
@@ -500,6 +501,7 @@
|
||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||
</span>
|
||||
<span class="pos-meta-item" id="order-be-wrap-{{ o.id }}" style="display:none"><span class="pos-breakeven-badge">已保本</span></span>
|
||||
</div>
|
||||
<div class="pos-grid">
|
||||
<div class="pos-cell">
|
||||
@@ -1791,6 +1793,12 @@ function formatRrRatio(rr){
|
||||
return `${body}:1`;
|
||||
}
|
||||
|
||||
function paintBreakevenBadge(orderId, secured){
|
||||
const wrap = document.getElementById(`order-be-wrap-${orderId}`);
|
||||
if(!wrap) return;
|
||||
wrap.style.display = secured ? "inline-flex" : "none";
|
||||
}
|
||||
|
||||
function paintPriceTrend(el, key, value){
|
||||
if(!el) return;
|
||||
const prev = lastPriceMap[key];
|
||||
@@ -1875,6 +1883,7 @@ function refreshPriceSnapshot(){
|
||||
if(rrEl){
|
||||
rrEl.innerText = formatRrRatio(o.rr_ratio);
|
||||
}
|
||||
paintBreakevenBadge(o.id, o.sl_breakeven_secured);
|
||||
if(o.exchange_tpsl) paintExchangeTpslRow(o.id, o.exchange_tpsl);
|
||||
});
|
||||
}).catch(()=>{});
|
||||
@@ -2116,6 +2125,7 @@ function refreshPriceSnapshotConditional(){
|
||||
}
|
||||
const rrEl = document.getElementById(`order-rr-${o.id}`);
|
||||
if(rrEl) rrEl.innerText = formatRrRatio(o.rr_ratio);
|
||||
paintBreakevenBadge(o.id, o.sl_breakeven_secured);
|
||||
paintExchangeTpslRow(o.id, o.exchange_tpsl || {});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user