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:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user