中控增加条件单委托

This commit is contained in:
dekun
2026-05-24 08:09:08 +08:00
parent 4b5fae2946
commit 3b97a59562
9 changed files with 731 additions and 14 deletions
+62
View File
@@ -35,6 +35,8 @@ from exchange_orders import (
cancel_order as hub_cancel_order,
cancel_orders_for_symbol,
list_open_orders,
replace_position_tpsl,
symbols_match,
)
HOST = os.getenv("HOST", "127.0.0.1")
@@ -299,6 +301,14 @@ class CancelSymbolOrdersBody(BaseModel):
scope: str = "all" # all | conditional | limit
class PlaceTpslBody(BaseModel):
symbol: str
side: str # long | short
stop_loss: float
take_profit: float
contracts: float | None = None
def _close_position_market(
ex: Any, sym: str, side: str, contracts: float
) -> tuple[dict[str, Any] | None, str | None]:
@@ -629,6 +639,58 @@ def cancel_symbol_orders(
)
@app.post("/orders/place-tpsl")
def place_tpsl_orders(
body: PlaceTpslBody,
x_control_token: str | None = Header(default=None, alias="X-Control-Token"),
):
"""先撤该合约全部条件单,再挂止盈+止损(与四实例策略逻辑一致)。"""
_check_token(x_control_token)
sym = (body.symbol or "").strip()
side = (body.side or "").strip().lower()
if not sym or side not in ("long", "short"):
raise HTTPException(status_code=400, detail="symbol 与 side(long/short) 必填")
try:
sl = float(body.stop_loss)
tp = float(body.take_profit)
except (TypeError, ValueError) as e:
raise HTTPException(status_code=400, detail="stop_loss / take_profit 须为数字") from e
try:
ex = get_exchange()
_ensure_markets()
amt = body.contracts
if amt is None or float(amt) <= 0:
raw = ex.fetch_positions() or []
found = None
for p in raw:
psym = p.get("symbol") or ""
if not symbols_match(sym, psym):
continue
c = abs(float(p.get("contracts") or 0))
if c <= 0:
continue
ps = (p.get("side") or "").lower()
if ps and ps != side:
continue
found = c
break
if found is None:
return JSONResponse(
{"ok": False, "error": f"未找到持仓 {sym} {side}", "exchange": EXCHANGE_KIND},
status_code=200,
)
amt = found
info = replace_position_tpsl(ex, EXCHANGE_KIND, sym, side, float(amt), sl, tp)
return {"ok": True, "exchange": EXCHANGE_KIND, "placed": info}
except HTTPException:
raise
except Exception as e:
return JSONResponse(
{"ok": False, "error": str(e), "exchange": EXCHANGE_KIND},
status_code=200,
)
@app.post("/emergency/close-all")
def emergency_close_all(x_control_token: str | None = Header(default=None, alias="X-Control-Token")):
_check_token(x_control_token)