修复期权到期结算漏推企业微信:页面同步与模拟盘结算一并通知。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-06 16:08:49 +08:00
parent d743185f05
commit 95e713e9e6
4 changed files with 101 additions and 1 deletions
+38
View File
@@ -371,9 +371,47 @@ def sync_open_options_trades(
)
except Exception:
pass
if notify_cfg is not None:
_notify_recent_unsent_expiry_closes(conn, notify_cfg)
return updated
def _notify_recent_unsent_expiry_closes(
conn: sqlite3.Connection,
notify_cfg: dict[str, Any],
*,
within_hours: float = 48.0,
) -> None:
"""页面同步曾漏推时,补发近期到期结算."""
try:
from lib.options.options_notify_lib import notify_options_close_trade_ids
from lib.options.options_time_lib import options_wall_clock_to_ms
now_ms = int(time.time() * 1000)
by_inst: dict[str, list[int]] = {}
rows = conn.execute(
"""
SELECT id, inst_id, closed_at
FROM options_trades
WHERE status = 'closed'
AND COALESCE(wechat_close_sent, 0) = 0
AND COALESCE(signal_note, '') = '到期结算'
ORDER BY id DESC
LIMIT 20
"""
).fetchall()
for r in rows:
closed_ms = options_wall_clock_to_ms(r["closed_at"])
if closed_ms is None or now_ms - int(closed_ms) > float(within_hours) * 3600 * 1000:
continue
inst = str(r["inst_id"] or "")
by_inst.setdefault(inst, []).append(int(r["id"]))
for ids in by_inst.values():
notify_options_close_trade_ids(notify_cfg, conn, ids, reason="到期结算")
except Exception:
pass
def reconcile_live_open_trades(
conn: sqlite3.Connection,
*,
+32
View File
@@ -58,6 +58,38 @@ def ensure_options_notify_columns(conn: sqlite3.Connection) -> None:
pass
_BOUND_NOTIFY_CFG: dict[str, Any] | None = None
def bind_options_notify_cfg(cfg: dict[str, Any] | None) -> None:
global _BOUND_NOTIFY_CFG
_BOUND_NOTIFY_CFG = cfg
def active_options_notify_cfg(cfg: dict[str, Any] | None = None) -> dict[str, Any]:
if cfg is not None and callable(cfg.get("send_wechat")):
return cfg
if _BOUND_NOTIFY_CFG is not None and callable(_BOUND_NOTIFY_CFG.get("send_wechat")):
return _BOUND_NOTIFY_CFG
import os
from lib.common.wechat_notify_lib import send_wechat_webhook
webhook = (os.getenv("WECHAT_WEBHOOK") or "").strip()
try:
timeout = int(float(os.getenv("WECHAT_TIMEOUT_SECONDS") or "10"))
except (TypeError, ValueError):
timeout = 10
label = (
os.getenv("OKX_OPTIONS_ACCOUNT_LABEL") or os.getenv("OKX_ACCOUNT_LABEL") or "OKX期权"
).strip()
def send(content: str) -> None:
send_wechat_webhook(webhook, content, timeout=timeout)
return {"send_wechat": send, "account_label": label}
def notify_options_send(cfg: dict[str, Any], content: str) -> bool:
send: Optional[Callable[[str], Any]] = cfg.get("send_wechat")
if not callable(send):
+12 -1
View File
@@ -63,6 +63,12 @@ def install_options_trading(app: Flask, repo_root: str, app_module: Any) -> None
patch_options_cfg(cfg)
except Exception:
pass
try:
from lib.options.options_notify_lib import bind_options_notify_cfg
bind_options_notify_cfg(cfg)
except Exception:
pass
app.extensions["options_cfg"] = cfg
register_options_routes(app, cfg)
_register_options_hub_bridge(app, cfg)
@@ -438,7 +444,12 @@ def _sync_options_trades(
try:
init_options_tables(conn)
reconcile_live_open_trades(conn, live_inst_ids=live_ids)
sync_open_options_trades(conn, live_inst_ids=live_ids, fetch_history_fn=_hist)
sync_open_options_trades(
conn,
live_inst_ids=live_ids,
fetch_history_fn=_hist,
notify_cfg=cfg,
)
try:
hist_all = fetch_all_option_positions_history(ex, limit=200)
backfill_closed_options_realized_pnl_from_history(conn, hist_all)