Enrich WeCom open/close notifies with Chinese qty, margin, and PnL.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-02 08:58:49 +08:00
parent aab0b9bdf6
commit 0e3b9e53ac
8 changed files with 373 additions and 32 deletions
+48 -1
View File
@@ -371,6 +371,12 @@ class BinanceLiveExecutor(Matcher):
except Exception:
logger.exception("lock exit target failed group=%s", group_id)
leverage = self.ledger.get_setting_float("leverage", get_settings().leverage)
perp_margin = (
abs(float(pf_px) * float(perp_qty)) / float(leverage)
if leverage and float(leverage) > 0
else None
)
return OpenResult(
ok=True,
group_id=group_id,
@@ -379,9 +385,21 @@ class BinanceLiveExecutor(Matcher):
"group_id": group_id,
"exec_mode": "LIVE",
"exchange": "binance",
"bias": bias,
"option_side": option_side,
"perp_side": perp_side,
"option_inst_id": option_inst_id,
"strike": strike,
"expiry_ymd": expiry_ymd,
"option_ord": opt_fill.ord_id,
"perp_ord": perp_fill_live.ord_id,
"perp_qty_eth": float(perp_qty),
"option_qty_eth": float(opt_qty),
"perp_entry_px": float(pf_px),
"option_entry_px": float(of_px),
"initial_premium": initial_premium,
"perp_margin": perp_margin,
"leverage": float(leverage) if leverage else None,
"fees": of_fee + pf_fee,
},
)
@@ -1101,13 +1119,31 @@ class BinanceLiveExecutor(Matcher):
local_net=float(net) if net is not None else None,
)
fills_summary = None
try:
from ..sim.pnl import summarize_fills_pnl
fill_rows = self.db.fetchall(
"SELECT * FROM fills WHERE group_id=? ORDER BY id ASC", (group_id,)
)
fills_summary = summarize_fills_pnl(list(fill_rows))
except Exception:
fills_summary = None
return CloseResult(
ok=True,
detail="closed_live_binance",
data={
"group_id": group_id,
"reason": reason,
"perp_pnl": (
fills_summary.get("perp_pnl") if fills_summary else None
),
"option_pnl": (
fills_summary.get("option_pnl") if fills_summary else None
),
"net": net,
"net_pnl": net,
"fees": fills_summary.get("fees_total") if fills_summary else None,
"exec_mode": "LIVE",
"pnl_source": "live_exchange",
},
@@ -1306,5 +1342,16 @@ class BinanceLiveExecutor(Matcher):
return CloseResult(
ok=True,
detail="perp_closed_option_residual_live_binance",
data={"group_id": group_id, "reason": reason, "mode": "target_perp_only", "exec_mode": "LIVE"},
data={
"group_id": group_id,
"reason": reason,
"mode": "target_perp_only",
"perp_pnl": perp_pnl,
"option_pnl": None,
"interim_net": interim_net,
"net": interim_net,
"net_pnl": interim_net,
"option_abandoned": True,
"exec_mode": "LIVE",
},
)
+52 -1
View File
@@ -389,6 +389,12 @@ class OkxLiveExecutor(Matcher):
except Exception:
logger.exception("lock exit target failed group=%s", group_id)
leverage = self.ledger.get_setting_float("leverage", get_settings().leverage)
perp_margin = (
abs(float(pf_px) * float(perp_qty)) / float(leverage)
if leverage and float(leverage) > 0
else None
)
return OpenResult(
ok=True,
group_id=group_id,
@@ -396,9 +402,21 @@ class OkxLiveExecutor(Matcher):
data={
"group_id": group_id,
"exec_mode": "LIVE",
"bias": bias,
"option_side": option_side,
"perp_side": perp_side,
"option_inst_id": option_inst_id,
"strike": strike,
"expiry_ymd": expiry_ymd,
"option_ord": opt_fill.ord_id,
"perp_ord": perp_fill_live.ord_id,
"perp_qty_eth": float(perp_qty),
"option_qty_eth": float(opt_qty),
"perp_entry_px": float(pf_px),
"option_entry_px": float(of_px),
"initial_premium": initial_premium,
"perp_margin": perp_margin,
"leverage": float(leverage) if leverage else None,
"fees": of_fee + pf_fee,
},
)
@@ -1140,13 +1158,35 @@ class OkxLiveExecutor(Matcher):
local_net=float(net) if net is not None else None,
)
fills_summary = None
try:
from ..sim.pnl import summarize_fills_pnl
fill_rows = self.db.fetchall(
"SELECT * FROM fills WHERE group_id=? ORDER BY id ASC", (group_id,)
)
fills_summary = summarize_fills_pnl(list(fill_rows))
except Exception:
fills_summary = None
return CloseResult(
ok=True,
detail="closed_live",
data={
"group_id": group_id,
"reason": reason,
"perp_pnl": (
fills_summary.get("perp_pnl")
if fills_summary
else None
),
"option_pnl": (
fills_summary.get("option_pnl")
if fills_summary
else None
),
"net": net,
"net_pnl": net,
"fees": fills_summary.get("fees_total") if fills_summary else None,
"exec_mode": "LIVE",
"pnl_source": "live_exchange",
},
@@ -1330,7 +1370,18 @@ class OkxLiveExecutor(Matcher):
return CloseResult(
ok=True,
detail="perp_closed_option_residual_live",
data={"group_id": group_id, "reason": reason, "mode": "target_perp_only", "exec_mode": "LIVE"},
data={
"group_id": group_id,
"reason": reason,
"mode": "target_perp_only",
"perp_pnl": perp_pnl,
"option_pnl": None,
"interim_net": interim_net,
"net": interim_net,
"net_pnl": interim_net,
"option_abandoned": True,
"exec_mode": "LIVE",
},
)