修复期权到期结算漏推企业微信:页面同步与模拟盘结算一并通知。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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,
|
||||
*,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -760,6 +760,13 @@ class SimBroker:
|
||||
conn.execute("DELETE FROM sim_option_positions WHERE inst_id=?", (inst_id,))
|
||||
try:
|
||||
closed_at = _now()
|
||||
open_ids = [
|
||||
int(r["id"])
|
||||
for r in conn.execute(
|
||||
"SELECT id FROM options_trades WHERE inst_id=? AND status='open'",
|
||||
(inst_id,),
|
||||
).fetchall()
|
||||
]
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE options_trades
|
||||
@@ -783,6 +790,18 @@ class SimBroker:
|
||||
inst_id,
|
||||
),
|
||||
)
|
||||
if open_ids:
|
||||
from lib.options.options_notify_lib import (
|
||||
active_options_notify_cfg,
|
||||
notify_options_close_trade_ids,
|
||||
)
|
||||
|
||||
notify_options_close_trade_ids(
|
||||
active_options_notify_cfg(),
|
||||
conn,
|
||||
open_ids,
|
||||
reason="到期结算",
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user