条件单未触发至周四23:00自动取消,下发/取消/开仓均推企业微信。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-06 16:45:19 +08:00
parent a957946cfd
commit 474e0742f7
2 changed files with 127 additions and 18 deletions
+121 -17
View File
@@ -4,10 +4,11 @@ from __future__ import annotations
import json
import sqlite3
import time
from datetime import datetime, timedelta, timezone
from typing import Any
# armed:待命穿越; triggering:已穿越等偏离区内开仓; open:持仓中;
# done:终态(leave_up/leave_down/cancel/closed)
# done:终态(leave_up/leave_down/cancel/timeout/closed)
ACTIVE_STATUSES = ("armed", "triggering", "open")
@@ -87,6 +88,78 @@ def _now() -> str:
return time.strftime("%Y-%m-%d %H:%M:%S")
def _notify_cond(
send_wechat: Any,
*,
title: str,
order: dict[str, Any],
account_label: str = "",
extra: list[str] | None = None,
) -> None:
if not callable(send_wechat) or not order:
return
try:
lines = [
title,
f"账户:{account_label or 'OKX期权'}",
f"单号:{order.get('hub_order_id') or '—'}",
f"标的:{order.get('underlying') or '—'} {order.get('opt_type') or '—'}",
f"触发价:{order.get('trigger_px') if order.get('trigger_px') is not None else '—'}",
]
for line in extra or []:
if line:
lines.append(line)
send_wechat("\n".join(lines))
except Exception:
pass
def next_thursday_2300(created_at: Any) -> datetime | None:
"""下发后第一个周四 23:00(业务时区).周四 23:00 之后下发的顺延到下周四."""
from lib.options.options_time_lib import options_app_tz, options_wall_clock_to_ms
ms = options_wall_clock_to_ms(created_at)
if ms is None:
return None
tz = options_app_tz()
dt = datetime.fromtimestamp(ms / 1000.0, tz=timezone.utc).astimezone(tz)
days = (3 - dt.weekday()) % 7
cand = dt.replace(hour=23, minute=0, second=0, microsecond=0) + timedelta(days=days)
if cand <= dt:
cand += timedelta(days=7)
return cand
def expire_untriggered_cond_orders(
conn: sqlite3.Connection,
*,
send_wechat: Any = None,
account_label: str = "",
now: datetime | None = None,
) -> int:
"""仅取消仍待命(未触发)的条件单;持仓/触发中不动."""
from lib.options.options_time_lib import options_app_tz
now_dt = now or datetime.now(options_app_tz())
n = 0
for order in list_cond_orders(conn, active_only=True):
if str(order.get("status") or "") != "armed":
continue
deadline = next_thursday_2300(order.get("created_at"))
if deadline is None or now_dt < deadline:
continue
_end_order(
conn,
order,
end_reason="timeout",
message="周四23:00未触发自动取消",
send_wechat=send_wechat,
account_label=account_label,
)
n += 1
return n
def _row_to_dict(row: sqlite3.Row | None) -> dict[str, Any] | None:
if row is None:
return None
@@ -156,7 +229,13 @@ def machine_has_option_position(cfg: dict[str, Any], ex: Any) -> bool:
return count_live_option_positions(raw) > 0
def create_cond_order(conn: sqlite3.Connection, payload: dict[str, Any]) -> dict[str, Any]:
def create_cond_order(
conn: sqlite3.Connection,
payload: dict[str, Any],
*,
send_wechat: Any = None,
account_label: str = "",
) -> dict[str, Any]:
"""接收中控下发;同机仅允许一张活跃条件单."""
ensure_cond_order_table(conn)
hub_order_id = (payload.get("hub_order_id") or "").strip()
@@ -224,6 +303,18 @@ def create_cond_order(conn: sqlite3.Connection, payload: dict[str, Any]) -> dict
)
conn.commit()
order = get_cond_order_by_hub_id(conn, hub_order_id)
_notify_cond(
send_wechat,
title="【OKX期权·条件单下发】",
order=order or {},
account_label=account_label,
extra=[
f"方向:{'Put 上穿' if opt_type == 'P' else 'Call 下穿'}",
f"偏离:{deviation_pct:g}%",
f"最短到期:{float(min_expiry_hours):g}h",
"状态:待命",
],
)
return {"ok": True, "msg": "条件单已 armed", "order": order}
@@ -435,20 +526,20 @@ def _end_order(
"leave_up": "上破偏离区结束",
"leave_down": "下破偏离区结束",
"cancel": "中控取消",
"timeout": "周四23:00未触发自动取消",
"closed": "出场完成",
}
lines = [
"【OKX期权·条件单结束】",
f"账户:{account_label or 'OKX期权'}",
f"单号:{order.get('hub_order_id')}",
f"标的:{order.get('underlying')} {order.get('opt_type')}",
f"触发价:{order.get('trigger_px')}",
f"原因:{reason_map.get(end_reason, end_reason)}",
f"说明:{message}",
]
if index_px is not None:
lines.append(f"当前指数:{index_px:g}")
send_wechat("\n".join(lines))
_notify_cond(
send_wechat,
title="【OKX期权·条件单结束】",
order=order,
account_label=account_label,
extra=[
f"原因:{reason_map.get(end_reason, end_reason)}",
f"说明:{message}",
]
+ ([f"当前指数:{index_px:g}"] if index_px is not None else []),
)
except Exception:
pass
@@ -583,8 +674,11 @@ def run_cond_orders_tick(
send_wechat: Any = None,
account_label: str = "",
) -> None:
"""监控循环单步:穿越/偏离区/开仓/出场收尾."""
"""监控循环单步:周四未触发取消 / 穿越 / 偏离区 / 开仓 / 出场收尾."""
ensure_cond_order_table(conn)
expire_untriggered_cond_orders(
conn, send_wechat=send_wechat, account_label=account_label
)
ex = cfg.get("exchange_options")
if ex is None:
return
@@ -747,8 +841,18 @@ def _tick_one(
),
)
conn.commit()
# 确保出场规则挂上
order2 = get_cond_order_by_hub_id(conn, order["hub_order_id"]) or order
opened = get_cond_order_by_hub_id(conn, order["hub_order_id"]) or order
_notify_cond(
send_wechat,
title="【OKX期权·条件单开仓】",
order=opened,
account_label=account_label,
extra=[
f"合约:{inst_id}",
f"说明:已开仓 {inst_id}",
],
)
order2 = opened
order2["opened_inst_id"] = inst_id
_apply_exit_to_position(
conn,