修复okx止盈止损

This commit is contained in:
dekun
2026-05-25 11:14:20 +08:00
parent dccd490a46
commit 4e8498f736
3 changed files with 156 additions and 58 deletions
+77 -46
View File
@@ -45,6 +45,7 @@ from fib_key_monitor_lib import (
key_signal_type_for_trade_record,
stored_key_signal_type,
)
from okx_orders_lib import fetch_okx_all_open_orders
from key_sl_tp_lib import (
breakeven_enabled_from_row,
normalize_sl_tp_mode,
@@ -2467,7 +2468,7 @@ def cancel_okx_swap_open_orders(exchange_symbol):
except Exception:
pass
try:
for o in exchange.fetch_open_orders(exchange_symbol) or []:
for o in fetch_okx_all_open_orders(exchange, exchange_symbol):
oid = o.get("id")
if oid is None:
continue
@@ -2616,26 +2617,52 @@ def _resolve_tpsl_prices_for_manual(direction, live_price, sltp_mode, data):
return stop_loss, take_profit
def _okx_tpsl_slot_from_order(order, exchange_symbol):
def _okx_tpsl_slot_build(exchange_symbol, order_id, trigger_price, order_type=""):
if trigger_price is None or order_id is None:
return None
sym = exchange_symbol.replace(":USDT", "").replace("/USDT:USDT", "")
return {
"order_id": str(order_id),
"trigger_price": float(trigger_price),
"trigger_display": format_price_for_symbol(sym, trigger_price),
"type": str(order_type or ""),
}
def _okx_tpsl_slots_from_order(order, exchange_symbol):
"""从单笔 OKX 订单解析 SL/TP(算法单常同时带 slTriggerPx 与 tpTriggerPx)。"""
if not isinstance(order, dict):
return None, None
info = order.get("info") or {}
if not isinstance(info, dict):
info = {}
oid = order.get("id") or info.get("algoId") or info.get("ordId")
trig = _coerce_float(
info.get("slTriggerPx"),
info.get("tpTriggerPx"),
if oid is None:
return None, None
ord_type = str(order.get("type") or info.get("ordType") or "")
sl_px = _coerce_float(
order.get("stopLossPrice"),
info.get("slTriggerPx"),
info.get("slOrdPx"),
)
tp_px = _coerce_float(
order.get("takeProfitPrice"),
info.get("tpTriggerPx"),
info.get("tpOrdPx"),
)
sl_slot = _okx_tpsl_slot_build(exchange_symbol, oid, sl_px, ord_type) if sl_px is not None else None
tp_slot = _okx_tpsl_slot_build(exchange_symbol, oid, tp_px, ord_type) if tp_px is not None else None
if sl_slot or tp_slot:
return sl_slot, tp_slot
trig = _coerce_float(
info.get("triggerPx"),
order.get("triggerPrice"),
order.get("stopPrice"),
)
if trig is None:
return None
return {
"order_id": str(oid) if oid is not None else None,
"trigger_price": float(trig),
"trigger_display": format_price_for_symbol(
exchange_symbol.replace(":USDT", "").replace("/USDT:USDT", ""),
trig,
),
"type": str(order.get("type") or info.get("ordType") or ""),
}
return None, None
one = _okx_tpsl_slot_build(exchange_symbol, oid, trig, ord_type)
return one, None
def fetch_exchange_tpsl_slots(exchange_symbol, direction, plan_sl=None, plan_tp=None):
@@ -2647,35 +2674,18 @@ def fetch_exchange_tpsl_slots(exchange_symbol, direction, plan_sl=None, plan_tp=
return slots
try:
ensure_markets_loaded()
ambiguous = []
for order in exchange.fetch_open_orders(exchange_symbol) or []:
slot = _okx_tpsl_slot_from_order(order, exchange_symbol)
if not slot or not slot.get("order_id"):
continue
trig = slot.get("trigger_price")
if plan_sl is not None and plan_tp is not None:
try:
role = "sl" if abs(trig - float(plan_sl)) <= abs(trig - float(plan_tp)) else "tp"
except Exception:
role = None
elif plan_sl is not None:
role = "sl"
elif plan_tp is not None:
role = "tp"
else:
ambiguous.append(slot)
continue
if role in ("sl", "tp") and slots[role] is None:
slots[role] = slot
for slot in ambiguous:
trig = slot.get("trigger_price")
if trig is None:
continue
try:
plan_sl_f = float(plan_sl) if plan_sl is not None else None
plan_tp_f = float(plan_tp) if plan_tp is not None else None
except Exception:
plan_sl_f = plan_tp_f = None
plan_sl_f = plan_tp_f = None
try:
if plan_sl is not None:
plan_sl_f = float(plan_sl)
if plan_tp is not None:
plan_tp_f = float(plan_tp)
except Exception:
plan_sl_f = plan_tp_f = None
def assign_role(trig, slot):
if trig is None or slot is None:
return
if plan_sl_f is not None and plan_tp_f is not None:
role = "sl" if abs(trig - plan_sl_f) <= abs(trig - plan_tp_f) else "tp"
elif plan_sl_f is not None:
@@ -2683,9 +2693,30 @@ def fetch_exchange_tpsl_slots(exchange_symbol, direction, plan_sl=None, plan_tp=
elif plan_tp_f is not None:
role = "tp"
else:
continue
return
if slots[role] is None:
slots[role] = slot
for order in fetch_okx_all_open_orders(exchange, exchange_symbol):
sl_slot, tp_slot = _okx_tpsl_slots_from_order(order, exchange_symbol)
if sl_slot and slots["sl"] is None:
slots["sl"] = sl_slot
if tp_slot and slots["tp"] is None:
slots["tp"] = tp_slot
if sl_slot or tp_slot:
continue
info = order.get("info") or {}
oid = order.get("id") or info.get("algoId")
trig = _coerce_float(info.get("triggerPx"), order.get("triggerPrice"))
if oid is None or trig is None:
continue
slot = _okx_tpsl_slot_build(
exchange_symbol,
oid,
trig,
str(order.get("type") or info.get("ordType") or ""),
)
assign_role(trig, slot)
except Exception:
pass
return slots
@@ -3717,7 +3748,7 @@ def fib_limit_order_status(exchange_symbol, order_id):
except Exception:
pass
try:
for o in exchange.fetch_open_orders(exchange_symbol) or []:
for o in fetch_okx_all_open_orders(exchange, exchange_symbol):
if str(o.get("id")) == oid:
return "open"
except Exception: