Add live expiry countdown for options positions on instance page and trading hub.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-08 11:14:30 +08:00
parent f68197b775
commit 189b27e076
12 changed files with 185 additions and 6 deletions
+32 -1
View File
@@ -227,6 +227,35 @@ def option_fields_from_inst_id(inst_id: str) -> tuple[str | None, float | None]:
return opt_type, strike
def expiry_ms_from_inst_id(inst_id: str) -> int | None:
"""从 instId 日期段解析到期时刻(OKX 期权默认 08:00 UTC)。"""
parts = (inst_id or "").strip().split("-")
if len(parts) < 3:
return None
date_part = parts[-3]
if not re.fullmatch(r"\d{6}", date_part):
return None
try:
from datetime import datetime, timezone
yy, mm, dd = int(date_part[0:2]), int(date_part[2:4]), int(date_part[4:6])
dt = datetime(2000 + yy, mm, dd, 8, 0, 0, tzinfo=timezone.utc)
return int(dt.timestamp() * 1000)
except (ValueError, OSError):
return None
def normalize_option_exp_ms(exp_time: Any, inst_id: str = "") -> int | None:
"""统一期权到期毫秒时间戳(优先 API expTime,否则从 instId 推算)。"""
raw = _safe_float(exp_time)
if raw is not None and raw > 0:
ms = int(raw)
if ms < 10_000_000_000:
ms *= 1000
return ms
return expiry_ms_from_inst_id(inst_id)
def fetch_option_instrument_meta(ex: ccxt.okx, inst_id: str) -> dict[str, Any] | None:
family = inst_family_from_inst_id(inst_id)
if not family:
@@ -839,6 +868,7 @@ def format_position_row(pos: dict[str, Any], ct_mult: float = 0.01) -> dict[str,
pos=sheets,
ct_mult=ct_mult,
)
exp_time_ms = normalize_option_exp_ms(pos.get("expTime"), inst_id)
return {
"inst_id": inst_id or pos.get("instId"),
"pos": sheets,
@@ -849,7 +879,8 @@ def format_position_row(pos: dict[str, Any], ct_mult: float = 0.01) -> dict[str,
"premium_paid": premium_paid,
"upl": upl,
"upl_ratio_pct": round(upl_ratio * 100, 2) if upl_ratio is not None else None,
"exp_time": pos.get("expTime"),
"exp_time": exp_time_ms,
"exp_time_ms": exp_time_ms,
"opt_type": opt_type,
"strike": strike,
"avail_pos": _safe_float(pos.get("availPos")),