fix(okx): use OCO algo orders for hub TP/SL to avoid instant close

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-03 21:00:08 +08:00
parent 2d8f65bf1d
commit fac28c402b
4 changed files with 120 additions and 46 deletions
+4 -1
View File
@@ -131,7 +131,10 @@ def _make_exchange() -> Any:
"secret": secret,
"password": password,
"enableRateLimit": True,
"options": {"defaultType": "swap"},
"options": {
"defaultType": "swap",
"hedged": OKX_POS_MODE == "hedge",
},
}
)
_attach_proxies(ex, "OKX")
+33 -23
View File
@@ -398,6 +398,8 @@ def cancel_order(
params = None
if kind == "gate" and ch == "algo":
params = _gate_trigger_params(ex)
elif kind == "okx" and ch == "algo":
params = {"stop": True}
oid = _okx_algo_order_id(order_id) if kind == "okx" else str(order_id)
ex.cancel_order(oid, unified, params)
@@ -489,11 +491,21 @@ def _binance_place_tp_sl(
raise RuntimeError(f"Binance 未接受止盈/止损:{last_err}")
def _okx_order_params(direction: str, *, reduce_only: bool, pos_mode: str, td_mode: str) -> dict:
def _okx_order_params(
direction: str,
*,
reduce_only: bool,
pos_mode: str,
td_mode: str,
for_algo_tpsl: bool = False,
) -> dict:
params: dict[str, Any] = {"tdMode": td_mode or "cross"}
if (pos_mode or "hedge").lower() in ("hedge", "long_short_mode", "dual"):
params["posSide"] = "long" if direction == "long" else "short"
if reduce_only:
ps = "long" if direction == "long" else "short"
params["posSide"] = ps
params["positionSide"] = ps
# OKX 条件/OCO 算法单勿带 reduceOnly,否则可能被当市价减仓立即成交
if reduce_only and not for_algo_tpsl:
params["reduceOnly"] = True
return params
@@ -509,34 +521,32 @@ def _okx_place_tp_sl(
pos_mode: str = "hedge",
td_mode: str = "cross",
) -> None:
"""OKX 永续:一笔 OCO 算法单挂止盈+止损(勿 reduceOnly + 分两笔 market)。"""
ex.load_markets()
close_side = "sell" if direction == "long" else "buy"
amt = float(ex.amount_to_precision(symbol, float(amount)))
if amt <= 0:
raise RuntimeError("止盈止损:可平数量经精度舍入后为 0")
base = _okx_order_params(direction, reduce_only=True, pos_mode=pos_mode, td_mode=td_mode)
sl_px = float(stop_loss)
tp_px = float(take_profit)
base = _okx_order_params(
direction,
reduce_only=False,
pos_mode=pos_mode,
td_mode=td_mode,
for_algo_tpsl=True,
)
sl_px = ex.price_to_precision(symbol, float(stop_loss))
tp_px = ex.price_to_precision(symbol, float(take_profit))
order_params = {
**base,
"stopLossPrice": float(sl_px),
"takeProfitPrice": float(tp_px),
"tpOrdPx": "-1",
"slOrdPx": "-1",
}
last_err: Exception | None = None
for attempt in range(6):
try:
ex.create_order(
symbol,
"market",
close_side,
amt,
None,
{**base, "stopLossPrice": sl_px},
)
time.sleep(0.05)
ex.create_order(
symbol,
"market",
close_side,
amt,
None,
{**base, "takeProfitPrice": tp_px},
)
ex.create_order(symbol, "oco", close_side, amt, None, order_params)
return
except Exception as e:
last_err = e