fix: 中控改委托后同步计划价并去重条件单展示
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,11 @@ _REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
if str(_REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(_REPO_ROOT))
|
||||
|
||||
from lib.hub.hub_order_sync_lib import (
|
||||
cond_order_role,
|
||||
dedupe_conditional_orders_by_role,
|
||||
exchange_tpsl_from_cond_orders,
|
||||
)
|
||||
from lib.hub.hub_kline_store import format_ohlcv_detail, resolve_chart_bars, retention_days
|
||||
from lib.hub.hub_ohlcv_lib import (
|
||||
CHART_TIMEFRAME_ORDER,
|
||||
@@ -1941,7 +1946,7 @@ def _merge_flask_position_mark_price(
|
||||
|
||||
|
||||
def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict | None) -> None:
|
||||
"""子代理挂单为空时,用实例 Flask 已算好的 exchange_tpsl 补全展示。"""
|
||||
"""子代理条件单优先;Flask exchange_tpsl 仅补缺失槽位,避免重复止损/止盈行。"""
|
||||
ag = agent_row.get("agent")
|
||||
if not isinstance(ag, dict):
|
||||
return
|
||||
@@ -1949,8 +1954,8 @@ def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict
|
||||
if not isinstance(positions, list) or not positions:
|
||||
return
|
||||
if not isinstance(snap, dict):
|
||||
return
|
||||
order_prices = snap.get("order_prices") or []
|
||||
snap = None
|
||||
order_prices = (snap or {}).get("order_prices") or []
|
||||
hub_orders = []
|
||||
if isinstance(hub_mon, dict):
|
||||
hub_orders = hub_mon.get("orders") or []
|
||||
@@ -1959,15 +1964,31 @@ def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict
|
||||
continue
|
||||
sym = p.get("symbol") or ""
|
||||
side = p.get("side") or ""
|
||||
et = _find_exchange_tpsl_for_position(sym, side, order_prices, hub_orders)
|
||||
if not et:
|
||||
et = _exchange_tpsl_from_hub_order(hub_orders, sym, side)
|
||||
cond = dedupe_conditional_orders_by_role(p.get("conditional_orders") or [])
|
||||
roles_in_cond = {
|
||||
r for row in cond if (r := cond_order_role(row)) in ("sl", "tp")
|
||||
}
|
||||
et = exchange_tpsl_from_cond_orders(cond)
|
||||
if not et or roles_in_cond != {"sl", "tp"}:
|
||||
flask_et = _find_exchange_tpsl_for_position(sym, side, order_prices, hub_orders)
|
||||
if not flask_et:
|
||||
flask_et = _exchange_tpsl_from_hub_order(hub_orders, sym, side)
|
||||
if flask_et:
|
||||
if et:
|
||||
for role in ("sl", "tp"):
|
||||
if not et.get(role) and flask_et.get(role):
|
||||
et[role] = flask_et[role]
|
||||
else:
|
||||
et = flask_et
|
||||
if not et:
|
||||
p["conditional_orders"] = cond
|
||||
continue
|
||||
p["exchange_tpsl"] = et
|
||||
cond = p.get("conditional_orders") or []
|
||||
merged = _tpsl_slots_to_conditional_orders(et, sym)
|
||||
p["conditional_orders"] = _merge_conditional_orders_no_dup(cond, merged)
|
||||
extra = [r for r in merged if cond_order_role(r) not in roles_in_cond]
|
||||
p["conditional_orders"] = dedupe_conditional_orders_by_role(
|
||||
_merge_conditional_orders_no_dup(cond, extra)
|
||||
)
|
||||
|
||||
|
||||
async def _fetch_exchange_flask_bundle(
|
||||
@@ -2392,6 +2413,22 @@ async def api_place_tpsl(exchange_id: str, body: PlaceTpslBody):
|
||||
"payload": payload,
|
||||
"ok": bool(isinstance(payload, dict) and payload.get("ok")),
|
||||
}
|
||||
if out.get("ok") and (ex.get("flask_url") or "").strip():
|
||||
async with httpx.AsyncClient() as flask_client:
|
||||
sync_parsed = await _fetch_flask_json(
|
||||
flask_client,
|
||||
ex,
|
||||
"/api/hub/order/sync-tpsl",
|
||||
method="POST",
|
||||
json_body={
|
||||
"symbol": body.symbol,
|
||||
"side": body.side,
|
||||
"stop_loss": body.stop_loss,
|
||||
"take_profit": body.take_profit,
|
||||
},
|
||||
)
|
||||
if isinstance(sync_parsed, dict):
|
||||
out["order_sync"] = sync_parsed
|
||||
_schedule_board_refresh()
|
||||
return out
|
||||
|
||||
|
||||
Reference in New Issue
Block a user