Add Binance SIM market adapter and exchange switch in settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-25 12:02:36 +08:00
parent 5dcec0fde0
commit 78fd046fb6
25 changed files with 879 additions and 45 deletions
+14 -8
View File
@@ -6,8 +6,17 @@ import re
from datetime import datetime, timezone
from typing import Any
from ..expiry import expiry_ms_from_ymd
_DATE_RE = re.compile(r"^\d{6}$")
__all__ = [
"expiry_ms_from_ymd",
"parse_option_inst_id",
"rows_to_option_contracts",
"safe_float",
]
def safe_float(v: Any) -> float | None:
if v is None or v == "":
@@ -31,13 +40,6 @@ def parse_option_inst_id(inst_id: str) -> tuple[str | None, float | None, str |
return ymd, strike, opt
def expiry_ms_from_ymd(ymd: str) -> int:
"""OKX 期权到期:当日 08:00 UTC = 上海 16:00。"""
yy, mm, dd = int(ymd[0:2]), int(ymd[2:4]), int(ymd[4:6])
dt = datetime(2000 + yy, mm, dd, 8, 0, 0, tzinfo=timezone.utc)
return int(dt.timestamp() * 1000)
def rows_to_option_contracts(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""
归一化为策略层可用的中性结构:
@@ -52,22 +54,26 @@ def rows_to_option_contracts(rows: list[dict[str, Any]]) -> list[dict[str, Any]]
continue
inst_id = str(row.get("instId") or "")
y, stk, opt = parse_option_inst_id(inst_id)
exp_ms = None
if y is None or stk is None or opt is None:
exp = safe_float(row.get("expTime"))
if exp:
ms = int(exp) if exp > 10_000_000_000 else int(exp * 1000)
y = datetime.fromtimestamp(ms / 1000, tz=timezone.utc).strftime("%y%m%d")
exp_ms = ms
stk = safe_float(row.get("stk"))
opt_raw = str(row.get("optType") or "").upper()
opt = opt_raw if opt_raw in ("C", "P") else None
if not inst_id or not y or stk is None or opt not in ("C", "P"):
continue
if exp_ms is None:
exp_ms = expiry_ms_from_ymd(y)
ct = safe_float(row.get("ctMult"))
out.append(
{
"inst_id": inst_id,
"expiry_ymd": y,
"expiry_ms": expiry_ms_from_ymd(y),
"expiry_ms": int(exp_ms),
"strike": float(stk),
"side": opt,
"ct_mult": float(ct) if ct and ct > 0 else None,