修复okx止盈止损
This commit is contained in:
@@ -21,6 +21,22 @@ def _coerce_float(*values) -> float | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _symbol_base_coin(symbol: str) -> str:
|
||||||
|
"""ZEC/USDT:USDT、ZEC-USDT-SWAP 等统一为标的币 ZEC。"""
|
||||||
|
s = (symbol or "").strip().upper()
|
||||||
|
if not s:
|
||||||
|
return ""
|
||||||
|
if "-SWAP" in s:
|
||||||
|
s = s.replace("-SWAP", "")
|
||||||
|
if "-" in s:
|
||||||
|
return s.split("-", 1)[0]
|
||||||
|
if "/" in s:
|
||||||
|
return s.split("/", 1)[0]
|
||||||
|
if ":" in s:
|
||||||
|
return s.split(":", 1)[0]
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
def symbols_match(position_symbol: str, order_symbol: str) -> bool:
|
def symbols_match(position_symbol: str, order_symbol: str) -> bool:
|
||||||
a = (position_symbol or "").strip().upper()
|
a = (position_symbol or "").strip().upper()
|
||||||
b = (order_symbol or "").strip().upper()
|
b = (order_symbol or "").strip().upper()
|
||||||
@@ -28,6 +44,9 @@ def symbols_match(position_symbol: str, order_symbol: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
if a == b:
|
if a == b:
|
||||||
return True
|
return True
|
||||||
|
ba, bb = _symbol_base_coin(a), _symbol_base_coin(b)
|
||||||
|
if ba and bb and ba == bb:
|
||||||
|
return True
|
||||||
for suf in (":USDT", "/USDT:USDT", "/USDT"):
|
for suf in (":USDT", "/USDT:USDT", "/USDT"):
|
||||||
a2 = a.replace(suf, "")
|
a2 = a.replace(suf, "")
|
||||||
b2 = b.replace(suf, "")
|
b2 = b.replace(suf, "")
|
||||||
@@ -54,7 +73,7 @@ def _is_conditional_type(typ: str) -> bool:
|
|||||||
t = (typ or "").upper()
|
t = (typ or "").upper()
|
||||||
if not t:
|
if not t:
|
||||||
return False
|
return False
|
||||||
keys = ("STOP", "TAKE_PROFIT", "TRAIL", "TRIGGER", "CONDITIONAL")
|
keys = ("STOP", "TAKE_PROFIT", "TRAIL", "TRIGGER", "CONDITIONAL", "OCO")
|
||||||
return any(k in t for k in keys)
|
return any(k in t for k in keys)
|
||||||
|
|
||||||
|
|
||||||
@@ -90,7 +109,7 @@ def _normalize_raw_order(order: dict, *, channel: str) -> dict[str, Any] | None:
|
|||||||
oid = order.get("id") or info.get("algoId") or info.get("orderId") or info.get("ordId")
|
oid = order.get("id") or info.get("algoId") or info.get("orderId") or info.get("ordId")
|
||||||
if oid is None:
|
if oid is None:
|
||||||
return None
|
return None
|
||||||
sym = str(order.get("symbol") or info.get("symbol") or "")
|
sym = str(order.get("symbol") or info.get("symbol") or info.get("instId") or "")
|
||||||
typ = _order_type_str(order)
|
typ = _order_type_str(order)
|
||||||
side = str(order.get("side") or info.get("side") or "").lower()
|
side = str(order.get("side") or info.get("side") or "").lower()
|
||||||
reduce_only = order.get("reduceOnly")
|
reduce_only = order.get("reduceOnly")
|
||||||
@@ -137,6 +156,42 @@ def _normalize_raw_order(order: dict, *, channel: str) -> dict[str, Any] | None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _okx_normalize_orders(raw: dict, channel: str) -> list[dict[str, Any]]:
|
||||||
|
"""OKX 算法单常一笔同时含 SL+TP,拆成两条供中控「交易所止盈止损」展示。"""
|
||||||
|
n = _normalize_raw_order(dict(raw), channel=channel)
|
||||||
|
if not n:
|
||||||
|
return []
|
||||||
|
info = raw.get("info") or {}
|
||||||
|
if not isinstance(info, dict):
|
||||||
|
info = {}
|
||||||
|
sl_trig = _coerce_float(info.get("slTriggerPx"), raw.get("stopLossPrice"))
|
||||||
|
tp_trig = _coerce_float(info.get("tpTriggerPx"), raw.get("takeProfitPrice"))
|
||||||
|
if sl_trig is None or tp_trig is None:
|
||||||
|
return [n]
|
||||||
|
base_id = n["id"]
|
||||||
|
rows: list[dict[str, Any]] = []
|
||||||
|
for role, px, lbl in (
|
||||||
|
("sl", sl_trig, f"止损 {sl_trig:g}"),
|
||||||
|
("tp", tp_trig, f"止盈 {tp_trig:g}"),
|
||||||
|
):
|
||||||
|
row = dict(n)
|
||||||
|
row["id"] = f"{base_id}:{role}"
|
||||||
|
row["algo_id"] = base_id
|
||||||
|
row["label"] = lbl
|
||||||
|
row["trigger_price"] = px
|
||||||
|
row["category"] = "conditional"
|
||||||
|
row["channel"] = channel
|
||||||
|
rows.append(row)
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def _okx_algo_order_id(order_id: str) -> str:
|
||||||
|
oid = str(order_id or "")
|
||||||
|
if ":" in oid:
|
||||||
|
return oid.split(":", 1)[0]
|
||||||
|
return oid
|
||||||
|
|
||||||
|
|
||||||
def _binance_list(ex: Any, symbol: str | None) -> list[dict]:
|
def _binance_list(ex: Any, symbol: str | None) -> list[dict]:
|
||||||
ex.load_markets()
|
ex.load_markets()
|
||||||
out: list[dict] = []
|
out: list[dict] = []
|
||||||
@@ -227,14 +282,12 @@ def _okx_list(ex: Any, symbol: str | None) -> list[dict]:
|
|||||||
try:
|
try:
|
||||||
for o in fetch_okx_all_open_orders(ex, sym):
|
for o in fetch_okx_all_open_orders(ex, sym):
|
||||||
ch = "algo" if _is_conditional_type(_order_type_str(o)) else "regular"
|
ch = "algo" if _is_conditional_type(_order_type_str(o)) else "regular"
|
||||||
n = _normalize_raw_order(dict(o), channel=ch)
|
for n in _okx_normalize_orders(dict(o), channel=ch):
|
||||||
if not n:
|
key = (n["id"], n.get("channel") or ch)
|
||||||
continue
|
if key in seen:
|
||||||
key = (n["id"], n.get("channel") or ch)
|
continue
|
||||||
if key in seen:
|
seen.add(key)
|
||||||
continue
|
out.append(n)
|
||||||
seen.add(key)
|
|
||||||
out.append(n)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return out
|
return out
|
||||||
@@ -345,7 +398,8 @@ def cancel_order(
|
|||||||
params = None
|
params = None
|
||||||
if kind == "gate" and ch == "algo":
|
if kind == "gate" and ch == "algo":
|
||||||
params = _gate_trigger_params(ex)
|
params = _gate_trigger_params(ex)
|
||||||
ex.cancel_order(str(order_id), unified, params)
|
oid = _okx_algo_order_id(order_id) if kind == "okx" else str(order_id)
|
||||||
|
ex.cancel_order(oid, unified, params)
|
||||||
|
|
||||||
|
|
||||||
def cancel_orders_for_symbol(
|
def cancel_orders_for_symbol(
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ HUB_BRIDGE_TOKEN = (os.getenv("HUB_BRIDGE_TOKEN") or os.getenv("CONTROL_TOKEN")
|
|||||||
_trust_raw = (os.getenv("HUB_TRUST_LAN", "true") or "").strip().lower()
|
_trust_raw = (os.getenv("HUB_TRUST_LAN", "true") or "").strip().lower()
|
||||||
HUB_TRUST_LAN = _trust_raw not in ("0", "false", "no", "off")
|
HUB_TRUST_LAN = _trust_raw not in ("0", "false", "no", "off")
|
||||||
DIR = Path(__file__).resolve().parent
|
DIR = Path(__file__).resolve().parent
|
||||||
HUB_BUILD = "20260525-perf"
|
HUB_BUILD = "20260525-okx-tpsl"
|
||||||
HUB_AGENT_TIMEOUT = float(os.getenv("HUB_AGENT_TIMEOUT", "8"))
|
HUB_AGENT_TIMEOUT = float(os.getenv("HUB_AGENT_TIMEOUT", "8"))
|
||||||
HUB_FLASK_TIMEOUT = float(os.getenv("HUB_FLASK_TIMEOUT", "10"))
|
HUB_FLASK_TIMEOUT = float(os.getenv("HUB_FLASK_TIMEOUT", "10"))
|
||||||
_board_key_prices_raw = (os.getenv("HUB_BOARD_KEY_PRICES", "true") or "").strip().lower()
|
_board_key_prices_raw = (os.getenv("HUB_BOARD_KEY_PRICES", "true") or "").strip().lower()
|
||||||
|
|||||||
@@ -410,10 +410,27 @@
|
|||||||
</details>`;
|
</details>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pickExTpslOrders(cond) {
|
||||||
|
let sl = cond.find((o) => /^止损\b/.test(o.label || ""));
|
||||||
|
let tp = cond.find((o) => /^止盈\b/.test(o.label || "") && !(o.label || "").includes("止盈止损"));
|
||||||
|
if (!sl || !tp) {
|
||||||
|
const combo = cond.find((o) => (o.label || "").includes("止盈止损"));
|
||||||
|
if (combo) {
|
||||||
|
const m = (combo.label || "").match(/SL=([\d.eE+-]+).*TP=([\d.eE+-]+)/i);
|
||||||
|
if (m) {
|
||||||
|
if (!sl) sl = { ...combo, label: "止损", trigger_price: Number(m[1]) };
|
||||||
|
if (!tp) tp = { ...combo, label: "止盈", trigger_price: Number(m[2]) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sl) sl = cond.find((o) => (o.label || "").includes("止损"));
|
||||||
|
if (!tp) tp = cond.find((o) => (o.label || "").includes("止盈") && o !== sl);
|
||||||
|
return { sl, tp };
|
||||||
|
}
|
||||||
|
|
||||||
function renderExTpslRows(exchangeId, symbol, cond) {
|
function renderExTpslRows(exchangeId, symbol, cond) {
|
||||||
const symAttr = esc(symbol || "").replace(/"/g, """);
|
const symAttr = esc(symbol || "").replace(/"/g, """);
|
||||||
const sl = cond.find((o) => (o.label || "").includes("止损"));
|
const { sl, tp } = pickExTpslOrders(cond);
|
||||||
const tp = cond.find((o) => (o.label || "").includes("止盈"));
|
|
||||||
function row(label, o) {
|
function row(label, o) {
|
||||||
if (!o) {
|
if (!o) {
|
||||||
return `<div class="pos-ex-order-row"><span class="pos-ex-order-main">${label}:—</span></div>`;
|
return `<div class="pos-ex-order-row"><span class="pos-ex-order-main">${label}:—</span></div>`;
|
||||||
|
|||||||
Reference in New Issue
Block a user