fix(hub,gate): cross-margin TP/SL and dedupe hub conditional orders

Gate hedge position triggers use close=false; stop silent ccxt fallback on cross margin. Hub merges agent and Flask TP/SL by trigger price and labels Gate orders correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-04 19:48:04 +08:00
parent ed0805538f
commit 24270944e7
7 changed files with 220 additions and 25 deletions
+48 -9
View File
@@ -687,6 +687,53 @@ def _flask_error_from_hub_mon(hub_mon: dict | None) -> str | None:
)
def _cond_order_trigger_key(price: object) -> str | None:
if price is None or price == "":
return None
try:
return f"{float(price):.12g}"
except (TypeError, ValueError):
return None
def _merge_conditional_orders_no_dup(
existing: list, extra: list
) -> list:
"""子代理已拉到的条件单与 Flask exchange_tpsl 合成行按触发价/订单号去重,避免 Gate 显示 4 笔实为 2 笔。"""
if not extra:
return list(existing) if existing else []
if not existing:
return list(extra)
triggers: set[str] = set()
order_ids: set[str] = set()
out: list = []
for row in existing:
if not isinstance(row, dict):
continue
out.append(row)
k = _cond_order_trigger_key(row.get("trigger_price"))
if k:
triggers.add(k)
oid = row.get("id")
if oid not in (None, ""):
order_ids.add(str(oid))
for row in extra:
if not isinstance(row, dict):
continue
k = _cond_order_trigger_key(row.get("trigger_price"))
oid = row.get("id")
if k and k in triggers:
continue
if oid not in (None, "") and str(oid) in order_ids:
continue
out.append(row)
if k:
triggers.add(k)
if oid not in (None, ""):
order_ids.add(str(oid))
return out
def _tpsl_slots_to_conditional_orders(exchange_tpsl: dict, symbol: str) -> list[dict]:
"""将实例 price_snapshot 的 exchange_tpsl 转为中控条件单结构。"""
out: list[dict] = []
@@ -984,15 +1031,7 @@ def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict
p["exchange_tpsl"] = et
cond = p.get("conditional_orders") or []
merged = _tpsl_slots_to_conditional_orders(et, sym)
if not cond:
p["conditional_orders"] = merged
elif merged:
labels = {str(c.get("label") or "") for c in cond if isinstance(c, dict)}
for row in merged:
lbl = str(row.get("label") or "")
if lbl and not any(lbl in x or x in lbl for x in labels):
cond.append(row)
p["conditional_orders"] = cond
p["conditional_orders"] = _merge_conditional_orders_no_dup(cond, merged)
async def _fetch_exchange_flask_bundle(