feat: 修改委托后展示最新风险,四所持仓卡增加张数
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -873,6 +873,13 @@ function submitTpslEntrust(){
|
||||
alert(data.msg || '已提交');
|
||||
closeTpslEntrustModal();
|
||||
if(data.exchange_tpsl) paintExchangeTpslRow(orderId, data.exchange_tpsl);
|
||||
paintPlanTpslDisplay(orderId, data);
|
||||
paintLatestRiskDisplay(orderId, data);
|
||||
const rrEl = document.getElementById(`order-rr-${orderId}`);
|
||||
if(rrEl){
|
||||
const rr = data.display_rr_ratio != null && data.display_rr_ratio !== "" ? data.display_rr_ratio : data.planned_rr;
|
||||
rrEl.innerText = formatRrRatio(rr);
|
||||
}
|
||||
refreshPriceSnapshotConditional();
|
||||
}).catch(()=>alert('委托请求失败'));
|
||||
}
|
||||
@@ -944,6 +951,25 @@ function paintPlanTpslDisplay(orderId, snap){
|
||||
else if(tpDisp) card.setAttribute("data-plan-tp", tpDisp);
|
||||
}
|
||||
}
|
||||
function paintLatestRiskDisplay(orderId, snap){
|
||||
const wrap = document.getElementById(`order-latest-risk-wrap-${orderId}`);
|
||||
if(!wrap) return;
|
||||
const v = snap && snap.latest_risk_amount;
|
||||
const n = v != null && v !== "" ? Number(v) : NaN;
|
||||
if(Number.isFinite(n)){
|
||||
wrap.style.display = "inline-flex";
|
||||
wrap.textContent = `最新风险: ${n.toFixed(2)}U`;
|
||||
} else {
|
||||
wrap.style.display = "none";
|
||||
}
|
||||
}
|
||||
function paintContractsDisplay(orderId, snap){
|
||||
const el = document.getElementById(`order-contracts-${orderId}`);
|
||||
if(!el || !snap) return;
|
||||
const v = snap.contracts != null && snap.contracts !== "" ? snap.contracts : snap.order_amount;
|
||||
const n = v != null && v !== "" ? Number(v) : NaN;
|
||||
el.innerText = Number.isFinite(n) ? String(parseFloat(n.toFixed(4))) : "—";
|
||||
}
|
||||
|
||||
function paintPriceTrend(el, key, value){
|
||||
if(!el) return;
|
||||
@@ -1027,8 +1053,11 @@ function refreshPriceSnapshot(){
|
||||
}
|
||||
const rrEl = document.getElementById(`order-rr-${o.id}`);
|
||||
if(rrEl){
|
||||
rrEl.innerText = formatRrRatio(o.rr_ratio);
|
||||
const rr = o.display_rr_ratio != null && o.display_rr_ratio !== "" ? o.display_rr_ratio : o.rr_ratio;
|
||||
rrEl.innerText = formatRrRatio(rr);
|
||||
}
|
||||
paintLatestRiskDisplay(o.id, o);
|
||||
paintContractsDisplay(o.id, o);
|
||||
paintBreakevenBadge(o.id, o.sl_breakeven_secured);
|
||||
if(o.exchange_tpsl) paintExchangeTpslRow(o.id, o.exchange_tpsl);
|
||||
paintPlanTpslDisplay(o.id, o);
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||
<span class="pos-meta-item">风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %}</span>
|
||||
<span class="pos-meta-item" id="order-latest-risk-wrap-{{ o.id }}" style="display:none">最新风险: —</span>
|
||||
<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>
|
||||
@@ -131,6 +132,10 @@
|
||||
<span class="pos-label">盈亏比</span>
|
||||
<span class="pos-value" id="order-rr-{{ o.id }}">{% if o.rr_ratio is not none %}{{ '%g'|format(o.rr_ratio) }}:1{% else %}-:1{% endif %}</span>
|
||||
</div>
|
||||
<div class="pos-cell">
|
||||
<span class="pos-label">张数</span>
|
||||
<span class="pos-value" id="order-contracts-{{ o.id }}">{% if o.order_amount is not none %}{{ '%g'|format(o.order_amount) }}{% else %}—{% endif %}</span>
|
||||
</div>
|
||||
<div class="pos-cell">
|
||||
<span class="pos-label">标记价</span>
|
||||
<span class="pos-value" id="order-price-{{ o.id }}">-</span>
|
||||
|
||||
@@ -175,6 +175,66 @@ def resolve_live_tpsl_prices(
|
||||
return disp_sl, disp_tp, ex_sl, ex_tp
|
||||
|
||||
|
||||
def calc_risk_fraction(direction: str, entry_price: Any, stop_loss: Any) -> Optional[float]:
|
||||
"""|入场-止损|/入场;盈利侧止损返回 0。"""
|
||||
entry = _positive_float(entry_price)
|
||||
sl = _positive_float(stop_loss)
|
||||
if entry is None or sl is None:
|
||||
return None
|
||||
d = (direction or "long").strip().lower()
|
||||
if d == "short":
|
||||
risk = sl - entry
|
||||
else:
|
||||
risk = entry - sl
|
||||
if risk <= 0:
|
||||
return 0.0
|
||||
return risk / entry
|
||||
|
||||
|
||||
def calc_latest_risk_amount(
|
||||
direction: str,
|
||||
entry_price: Any,
|
||||
stop_loss: Any,
|
||||
*,
|
||||
margin_capital: Any = None,
|
||||
leverage: Any = None,
|
||||
exchange_notional: Any = None,
|
||||
contracts: Any = None,
|
||||
contract_size: Any = None,
|
||||
mark_price: Any = None,
|
||||
funds_decimals: int = 2,
|
||||
) -> Optional[float]:
|
||||
"""按当前止损与持仓名义价值估算最新风险(U)。"""
|
||||
rf = calc_risk_fraction(direction, entry_price, stop_loss)
|
||||
if rf is None:
|
||||
return None
|
||||
if rf <= 0:
|
||||
return 0.0
|
||||
notional = _positive_float(exchange_notional)
|
||||
if notional is None:
|
||||
try:
|
||||
mc = float(margin_capital or 0)
|
||||
lev = float(leverage or 0)
|
||||
if mc > 0 and lev > 0:
|
||||
notional = mc * lev
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if notional is None:
|
||||
try:
|
||||
c = abs(float(contracts or 0))
|
||||
cs = float(contract_size or 1)
|
||||
if cs <= 0:
|
||||
cs = 1.0
|
||||
px = _positive_float(mark_price) or _positive_float(entry_price)
|
||||
if c > 0 and px is not None:
|
||||
notional = c * cs * px
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if notional is None or notional <= 0:
|
||||
return None
|
||||
return round(notional * rf, funds_decimals)
|
||||
|
||||
|
||||
def order_monitor_tpsl_needs_sync(
|
||||
plan_sl: Any,
|
||||
plan_tp: Any,
|
||||
@@ -210,8 +270,17 @@ def apply_order_price_display_fields(
|
||||
exchange_tpsl: Any = None,
|
||||
format_price_fn: Optional[Callable[[Any, Any], str]] = None,
|
||||
symbol: Any = None,
|
||||
margin_capital: Any = None,
|
||||
leverage: Any = None,
|
||||
exchange_notional: Any = None,
|
||||
contracts: Any = None,
|
||||
contract_size: Any = None,
|
||||
mark_price: Any = None,
|
||||
funds_decimals: int = 2,
|
||||
) -> dict[str, Any]:
|
||||
disp_sl, disp_tp, _, _ = resolve_live_tpsl_prices(stop_loss, take_profit, exchange_tpsl)
|
||||
payload["stop_loss_raw"] = _positive_float(stop_loss)
|
||||
payload["take_profit_raw"] = _positive_float(take_profit)
|
||||
payload["rr_ratio"] = snapshot_rr(
|
||||
calc_rr_ratio_fn,
|
||||
direction,
|
||||
@@ -231,6 +300,25 @@ def apply_order_price_display_fields(
|
||||
)
|
||||
else:
|
||||
payload["display_rr_ratio"] = None
|
||||
if contracts is not None:
|
||||
try:
|
||||
c = abs(float(contracts))
|
||||
if c > 0:
|
||||
payload["contracts"] = c
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
payload["latest_risk_amount"] = calc_latest_risk_amount(
|
||||
direction,
|
||||
entry_price,
|
||||
disp_sl if disp_sl is not None else stop_loss,
|
||||
margin_capital=margin_capital,
|
||||
leverage=leverage,
|
||||
exchange_notional=exchange_notional,
|
||||
contracts=payload.get("contracts") if payload.get("contracts") is not None else contracts,
|
||||
contract_size=contract_size,
|
||||
mark_price=mark_price,
|
||||
funds_decimals=funds_decimals,
|
||||
)
|
||||
if format_price_fn is not None and symbol is not None:
|
||||
payload["stop_loss_display"] = (
|
||||
format_price_fn(symbol, disp_sl) if disp_sl is not None else "—"
|
||||
@@ -239,3 +327,67 @@ def apply_order_price_display_fields(
|
||||
format_price_fn(symbol, disp_tp) if disp_tp is not None else "—"
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
def enrich_active_monitor_tpsl_json(
|
||||
row: Any,
|
||||
stop_loss: Any,
|
||||
take_profit: Any,
|
||||
exchange_tpsl: Any,
|
||||
*,
|
||||
position_row: Any = None,
|
||||
exchange_notional: Any = None,
|
||||
contracts: Any = None,
|
||||
contract_size: float = 1.0,
|
||||
mark_price: Any = None,
|
||||
calc_rr_ratio_fn: Callable[..., Optional[float]],
|
||||
format_price_fn: Optional[Callable[[Any, Any], str]] = None,
|
||||
symbol: Any = None,
|
||||
funds_decimals: int = 2,
|
||||
) -> dict[str, Any]:
|
||||
"""place_tpsl 响应:展示用 TP/SL、最新风险、当前盈亏比。"""
|
||||
def _row_val(key: str, default=None):
|
||||
try:
|
||||
if hasattr(row, "keys") and key in row.keys():
|
||||
return row[key]
|
||||
except Exception:
|
||||
pass
|
||||
if isinstance(row, dict):
|
||||
return row.get(key, default)
|
||||
return default
|
||||
|
||||
direction = _row_val("direction") or "long"
|
||||
entry = _row_val("trigger_price")
|
||||
init_sl = _row_val("initial_stop_loss")
|
||||
margin = _row_val("margin_capital")
|
||||
leverage = _row_val("leverage")
|
||||
if position_row is not None:
|
||||
from lib.hub.hub_position_metrics import position_contracts
|
||||
|
||||
live_c = position_contracts(position_row)
|
||||
if abs(live_c) >= 1e-12:
|
||||
contracts = abs(live_c)
|
||||
payload: dict[str, Any] = {
|
||||
"stop_loss": stop_loss,
|
||||
"take_profit": take_profit,
|
||||
}
|
||||
apply_order_price_display_fields(
|
||||
payload,
|
||||
direction=direction,
|
||||
entry_price=entry,
|
||||
initial_stop_loss=init_sl,
|
||||
stop_loss=stop_loss,
|
||||
take_profit=take_profit,
|
||||
calc_rr_ratio_fn=calc_rr_ratio_fn,
|
||||
exchange_tpsl=exchange_tpsl,
|
||||
format_price_fn=format_price_fn,
|
||||
symbol=symbol or _row_val("symbol"),
|
||||
margin_capital=margin,
|
||||
leverage=leverage,
|
||||
exchange_notional=exchange_notional,
|
||||
contracts=contracts,
|
||||
contract_size=contract_size,
|
||||
mark_price=mark_price,
|
||||
funds_decimals=funds_decimals,
|
||||
)
|
||||
return payload
|
||||
|
||||
Reference in New Issue
Block a user