refactor: 将共用代码迁入 lib/ 模块化目录
统一 strategy、key_monitor、trade、hub 等共用库到 lib/ 子包,并补充 lib-structure 文档,便于四所与中控维护。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
OKX 挂单聚合:普通委托 + 算法单(conditional / oco / trigger)。
|
||||
交易所 App「止盈止损」页多为 orders-algo-pending,仅 fetch_open_orders 默认拿不到。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _order_dedupe_key(order: dict) -> str:
|
||||
info = order.get("info") or {}
|
||||
if not isinstance(info, dict):
|
||||
info = {}
|
||||
return str(order.get("id") or info.get("algoId") or info.get("ordId") or "")
|
||||
|
||||
|
||||
def _okx_algo_cancel_id(order_id: str) -> str:
|
||||
oid = str(order_id or "")
|
||||
if ":" in oid:
|
||||
return oid.split(":", 1)[0]
|
||||
return oid
|
||||
|
||||
|
||||
def _okx_order_needs_stop_cancel_param(order: dict) -> bool:
|
||||
"""OKX 条件/算法单撤单须 params.stop=True,否则 cancel_order 走普通单接口会静默失败。"""
|
||||
if not isinstance(order, dict):
|
||||
return False
|
||||
info = order.get("info") or {}
|
||||
if not isinstance(info, dict):
|
||||
info = {}
|
||||
if order.get("stopLossPrice") is not None or order.get("takeProfitPrice") is not None:
|
||||
return True
|
||||
if info.get("algoId") or info.get("slTriggerPx") or info.get("tpTriggerPx"):
|
||||
return True
|
||||
typ = str(order.get("type") or info.get("ordType") or "").lower()
|
||||
for token in ("conditional", "oco", "trigger", "move_order_stop", "iceberg"):
|
||||
if token in typ:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def fetch_okx_all_open_orders(ex, exchange_symbol: str) -> list[dict]:
|
||||
"""合并 OKX 普通挂单与算法挂单(去重)。"""
|
||||
if not exchange_symbol:
|
||||
return []
|
||||
ex.load_markets()
|
||||
sym = exchange_symbol
|
||||
try:
|
||||
sym = ex.market(exchange_symbol)["symbol"]
|
||||
except Exception:
|
||||
pass
|
||||
seen: set[str] = set()
|
||||
out: list[dict] = []
|
||||
|
||||
def add_batch(batch: list | None) -> None:
|
||||
for o in batch or []:
|
||||
if not isinstance(o, dict):
|
||||
continue
|
||||
k = _order_dedupe_key(o)
|
||||
if not k or k in seen:
|
||||
continue
|
||||
seen.add(k)
|
||||
out.append(o)
|
||||
|
||||
try:
|
||||
add_batch(ex.fetch_open_orders(sym))
|
||||
except Exception:
|
||||
pass
|
||||
for params in (
|
||||
{"ordType": "conditional"},
|
||||
{"ordType": "oco"},
|
||||
{"trigger": True},
|
||||
):
|
||||
try:
|
||||
add_batch(ex.fetch_open_orders(sym, params=dict(params)))
|
||||
except Exception:
|
||||
pass
|
||||
return out
|
||||
|
||||
|
||||
def cancel_okx_all_open_orders(ex, exchange_symbol: str) -> int:
|
||||
"""
|
||||
撤销某合约全部挂单(普通 + 条件/算法)。
|
||||
OKX 止盈止损在 orders-algo-pending,必须用 stop=True 才能撤掉。
|
||||
"""
|
||||
if not exchange_symbol:
|
||||
return 0
|
||||
ex.load_markets()
|
||||
sym = exchange_symbol
|
||||
try:
|
||||
sym = ex.market(exchange_symbol)["symbol"]
|
||||
except Exception:
|
||||
pass
|
||||
n = 0
|
||||
for o in fetch_okx_all_open_orders(ex, sym):
|
||||
oid = _order_dedupe_key(o)
|
||||
if not oid:
|
||||
continue
|
||||
cancel_id = _okx_algo_cancel_id(oid)
|
||||
params = {"stop": True} if _okx_order_needs_stop_cancel_param(o) else None
|
||||
try:
|
||||
ex.cancel_order(cancel_id, sym, params)
|
||||
n += 1
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
ex.cancel_order(oid, sym, params)
|
||||
n += 1
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
ex.cancel_all_orders(sym)
|
||||
except Exception:
|
||||
pass
|
||||
return n
|
||||
Reference in New Issue
Block a user