fix: 持仓手数均价分列、止损止盈显示金额、CTP开仓时间含OpenTime
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+9
-9
@@ -430,8 +430,6 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
trailing_be = int(existing.get("trailing_be") or 0)
|
||||
open_time_val = existing.get("open_time") or now_s
|
||||
if ctp_open_time:
|
||||
prev = (open_time_val or "")[:19]
|
||||
if not prev or ctp_open_time < prev:
|
||||
open_time_val = ctp_open_time
|
||||
conn.execute(
|
||||
"""UPDATE trade_order_monitors SET
|
||||
@@ -495,12 +493,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
"SELECT open_time FROM trade_order_monitors WHERE id=?", (mid,),
|
||||
).fetchone()
|
||||
db_open = (row["open_time"] or "").strip() if row else ""
|
||||
open_time_val = db_open or ctp_open
|
||||
if ctp_open and db_open:
|
||||
if ctp_open < db_open[:19]:
|
||||
open_time_val = ctp_open
|
||||
elif ctp_open:
|
||||
open_time_val = ctp_open
|
||||
open_time_val = ctp_open or db_open
|
||||
execute_retry(
|
||||
conn,
|
||||
"""UPDATE trade_order_monitors SET lots=?, entry_price=?,
|
||||
@@ -552,7 +545,12 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
sl = float(mon["stop_loss"]) if mon and mon.get("stop_loss") is not None else None
|
||||
tp = float(mon["take_profit"]) if mon and mon.get("take_profit") is not None else None
|
||||
ctp_open = (ctp.get("open_time") or "").strip() if ctp else ""
|
||||
open_time = ctp_open or ((mon.get("open_time") or "") if mon else "")
|
||||
if ctp and ctp_open:
|
||||
open_time = ctp_open
|
||||
open_time_source = "ctp"
|
||||
else:
|
||||
open_time = ((mon.get("open_time") or "") if mon else "")
|
||||
open_time_source = "local" if open_time else ""
|
||||
holding = _holding_duration(open_time, now_iso) if open_time else ""
|
||||
|
||||
mark = None
|
||||
@@ -630,6 +628,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
"stop_loss": sl,
|
||||
"take_profit": tp,
|
||||
"open_time": open_time or None,
|
||||
"open_time_source": open_time_source or None,
|
||||
"holding_duration": holding or None,
|
||||
"mark_price": mark,
|
||||
"current_price": mark,
|
||||
@@ -637,6 +636,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
"margin_source": margin_source,
|
||||
"position_pct": position_pct,
|
||||
"risk_amount": pos_metrics.get("risk_amount") if sl is not None else None,
|
||||
"reward_amount": pos_metrics.get("reward_amount") if tp is not None else None,
|
||||
"risk_pct": pos_metrics.get("risk_pct") if sl is not None else None,
|
||||
"rr_ratio": pos_metrics.get("rr_ratio") if sl is not None and tp is not None else None,
|
||||
"float_pnl": float_pnl,
|
||||
|
||||
+8
-4
@@ -683,14 +683,17 @@
|
||||
var metaLine =
|
||||
'来源 <strong>' + (row.source_label || 'CTP') + '</strong>' +
|
||||
(row.rr_ratio != null ? ' · 盈亏比 <strong>' + row.rr_ratio + ':1</strong>' : '') +
|
||||
' · 止损 <strong>' + (row.stop_loss != null ? fmtNum(row.stop_loss) : '--') + '</strong>' +
|
||||
' · 止盈 <strong>' + (row.take_profit != null ? fmtNum(row.take_profit) : '--') + '</strong>' +
|
||||
' · 止损金额 <strong class="text-loss">' +
|
||||
(row.risk_amount != null ? fmtNum(row.risk_amount) + ' 元' : '--') + '</strong>' +
|
||||
' · 盈利金额 <strong class="text-profit">' +
|
||||
(row.reward_amount != null ? fmtNum(row.reward_amount) + ' 元' : '--') + '</strong>' +
|
||||
' · ' + slTpStatusHtml(row) +
|
||||
' · 移动保本 ' + trailingStatusHtml(row) +
|
||||
(slTpBtn ? ' · ' + slTpBtn : '') +
|
||||
(row.sync_pending ? ' · <span class="text-muted">同步柜台中…</span>' : '');
|
||||
var feeLabel = row.fee_source === 'ctp' ? '手续费(柜台)' : '手续费';
|
||||
var marginLabel = row.margin_source === 'ctp' ? '占用保证金(柜台)' : '占用保证金';
|
||||
var openLabel = row.open_time_source === 'ctp' ? '开仓(柜台)' : '开仓';
|
||||
return (
|
||||
'<div class="pos-card">' +
|
||||
'<div class="pos-card-head"><div><div class="title">' + row.symbol + ' <span class="badge dir">' + dirBadge + '</span></div>' +
|
||||
@@ -698,13 +701,14 @@
|
||||
actionBtns + '</div>' +
|
||||
'<div class="pos-card-meta pos-card-meta-line">' + metaLine + '</div>' +
|
||||
'<div class="pos-metrics">' +
|
||||
'<div class="cell"><label>手数 / 均价</label><div><strong>' + row.lots + ' 手</strong> @ ' + fmtNum(row.entry_price) + '</div></div>' +
|
||||
'<div class="cell"><label>手数</label><div><strong>' + row.lots + ' 手</strong></div></div>' +
|
||||
'<div class="cell"><label>均价</label><div>' + fmtNum(row.entry_price) + '</div></div>' +
|
||||
'<div class="cell"><label>当前价格</label><div>' + (row.current_price != null ? fmtNum(row.current_price) : '--') + '</div></div>' +
|
||||
'<div class="cell"><label>' + marginLabel + '</label><div>' + (row.margin != null ? fmtNum(row.margin) + ' 元' : '--') + '</div></div>' +
|
||||
'<div class="cell"><label>仓位占比</label><div>' + (row.position_pct != null ? fmtNum(row.position_pct) + '%' : '--') + '</div></div>' +
|
||||
'<div class="cell ' + pnlClass + '"><label>浮盈亏</label><div>' + pnlText + '</div></div>' +
|
||||
'<div class="cell"><label>' + feeLabel + '</label><div>' + (row.est_fee != null ? fmtNum(row.est_fee) + ' 元' : '--') + '</div></div>' +
|
||||
'<div class="cell"><label>开仓</label><div>' + (openT || '--') + '</div></div>' +
|
||||
'<div class="cell"><label>' + openLabel + '</label><div>' + (openT || '--') + '</div></div>' +
|
||||
'<div class="cell"><label>持仓</label><div>' + (row.holding_duration || '--') + '</div></div>' +
|
||||
'</div>' + buildPendingHtml(row.pending_orders) +
|
||||
'</div>'
|
||||
|
||||
+21
-6
@@ -732,11 +732,22 @@ class CtpBridge:
|
||||
return (self._position_open_times.get(self._position_margin_key(sym, direction)) or "").strip()
|
||||
|
||||
@staticmethod
|
||||
def _parse_ctp_open_date(raw: str) -> str:
|
||||
s = (raw or "").strip()
|
||||
if len(s) >= 8 and s[:8].isdigit():
|
||||
return f"{s[:4]}-{s[4:6]}-{s[6:8]} 09:00:00"
|
||||
def _parse_ctp_open_datetime(date_raw: str, time_raw: str = "") -> str:
|
||||
"""CTP OpenDate + OpenTime → YYYY-MM-DD HH:MM[:SS]。"""
|
||||
d = (date_raw or "").strip()
|
||||
if len(d) >= 8 and d[:8].isdigit():
|
||||
date_part = f"{d[:4]}-{d[4:6]}-{d[6:8]}"
|
||||
else:
|
||||
return ""
|
||||
t = (time_raw or "").strip().replace(":", "")
|
||||
if len(t) >= 6 and t[:6].isdigit():
|
||||
return f"{date_part} {t[0:2]}:{t[2:4]}:{t[4:6]}"
|
||||
if len(t) >= 4 and t.isdigit():
|
||||
return f"{date_part} {t[0:2]}:{t[2:4]}"
|
||||
return date_part
|
||||
|
||||
def _parse_ctp_open_date(raw: str) -> str:
|
||||
return CtpBridge._parse_ctp_open_datetime(raw, "")
|
||||
|
||||
def _install_position_margin_hook(self) -> None:
|
||||
"""拦截 CTP 持仓回报,缓存柜台 UseMargin。"""
|
||||
@@ -769,8 +780,12 @@ class CtpBridge:
|
||||
bridge._position_margins[k] = (
|
||||
bridge._position_margins.get(k, 0.0) + margin
|
||||
)
|
||||
open_date = bridge._parse_ctp_open_date(
|
||||
str(data.get("OpenDate") or data.get("open_date") or "")
|
||||
open_date = bridge._parse_ctp_open_datetime(
|
||||
str(data.get("OpenDate") or data.get("open_date") or ""),
|
||||
str(
|
||||
data.get("OpenTime") or data.get("open_time")
|
||||
or data.get("TradeTime") or ""
|
||||
),
|
||||
)
|
||||
if sym and open_date:
|
||||
k = bridge._position_margin_key(sym, d)
|
||||
|
||||
Reference in New Issue
Block a user