中控增加条件单
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
子账户极轻代理:GET /status、POST /emergency/close-all、POST /emergency/close-position,仅监听 127.0.0.1。
|
||||
子账户极轻代理:GET /status、挂单/条件单查询与撤销、POST /emergency/close-all、POST /emergency/close-position,仅监听 127.0.0.1。
|
||||
|
||||
与仓库内四个策略/监控目录一一对应时,典型用法(各目录自己的 .env 里已有密钥;子代理用环境变量 PORT,勿与 Flask 的 APP_PORT 相同):
|
||||
EXCHANGE=binance → crypto_monitor_binance(BINANCE_*)
|
||||
@@ -30,6 +30,13 @@ from fastapi import FastAPI, Header, HTTPException, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
from exchange_orders import (
|
||||
attach_orders_to_positions,
|
||||
cancel_order as hub_cancel_order,
|
||||
cancel_orders_for_symbol,
|
||||
list_open_orders,
|
||||
)
|
||||
|
||||
HOST = os.getenv("HOST", "127.0.0.1")
|
||||
PORT = int(os.getenv("PORT", "15200"))
|
||||
CONTROL_TOKEN = (os.getenv("CONTROL_TOKEN") or "").strip()
|
||||
@@ -281,6 +288,17 @@ class EmergencyClosePositionBody(BaseModel):
|
||||
side: str
|
||||
|
||||
|
||||
class CancelOrderBody(BaseModel):
|
||||
symbol: str
|
||||
order_id: str
|
||||
channel: str = "regular"
|
||||
|
||||
|
||||
class CancelSymbolOrdersBody(BaseModel):
|
||||
symbol: str
|
||||
scope: str = "all" # all | conditional | limit
|
||||
|
||||
|
||||
def _close_position_market(
|
||||
ex: Any, sym: str, side: str, contracts: float
|
||||
) -> tuple[dict[str, Any] | None, str | None]:
|
||||
@@ -522,6 +540,16 @@ def _status_inner(x_control_token: str | None) -> Any:
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
attach_orders_to_positions(
|
||||
positions_out,
|
||||
list_open_orders(ex, EXCHANGE_KIND, None),
|
||||
)
|
||||
except Exception:
|
||||
for p in positions_out:
|
||||
p.setdefault("conditional_orders", [])
|
||||
p.setdefault("regular_orders", [])
|
||||
|
||||
try:
|
||||
pm = _position_mode_label()
|
||||
except Exception:
|
||||
@@ -536,6 +564,71 @@ def _status_inner(x_control_token: str | None) -> Any:
|
||||
}
|
||||
|
||||
|
||||
@app.get("/open-orders")
|
||||
def open_orders(
|
||||
symbol: str = "",
|
||||
x_control_token: str | None = Header(default=None, alias="X-Control-Token"),
|
||||
):
|
||||
_check_token(x_control_token)
|
||||
try:
|
||||
ex = get_exchange()
|
||||
_ensure_markets()
|
||||
sym = (symbol or "").strip() or None
|
||||
orders = list_open_orders(ex, EXCHANGE_KIND, sym)
|
||||
return {"ok": True, "exchange": EXCHANGE_KIND, "symbol": sym, "orders": orders}
|
||||
except Exception as e:
|
||||
return JSONResponse(
|
||||
{"ok": False, "error": str(e), "exchange": EXCHANGE_KIND, "orders": []},
|
||||
status_code=200,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/orders/cancel")
|
||||
def cancel_one_order(
|
||||
body: CancelOrderBody,
|
||||
x_control_token: str | None = Header(default=None, alias="X-Control-Token"),
|
||||
):
|
||||
_check_token(x_control_token)
|
||||
sym = (body.symbol or "").strip()
|
||||
oid = (body.order_id or "").strip()
|
||||
if not sym or not oid:
|
||||
raise HTTPException(status_code=400, detail="symbol 与 order_id 必填")
|
||||
try:
|
||||
ex = get_exchange()
|
||||
_ensure_markets()
|
||||
hub_cancel_order(ex, EXCHANGE_KIND, sym, oid, body.channel or "regular")
|
||||
return {"ok": True, "exchange": EXCHANGE_KIND, "cancelled": {"symbol": sym, "order_id": oid}}
|
||||
except Exception as e:
|
||||
return JSONResponse(
|
||||
{"ok": False, "error": str(e), "exchange": EXCHANGE_KIND},
|
||||
status_code=200,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/orders/cancel-symbol")
|
||||
def cancel_symbol_orders(
|
||||
body: CancelSymbolOrdersBody,
|
||||
x_control_token: str | None = Header(default=None, alias="X-Control-Token"),
|
||||
):
|
||||
_check_token(x_control_token)
|
||||
sym = (body.symbol or "").strip()
|
||||
if not sym:
|
||||
raise HTTPException(status_code=400, detail="symbol 必填")
|
||||
scope = (body.scope or "all").strip().lower()
|
||||
if scope not in ("all", "conditional", "limit"):
|
||||
raise HTTPException(status_code=400, detail="scope 须为 all / conditional / limit")
|
||||
try:
|
||||
ex = get_exchange()
|
||||
_ensure_markets()
|
||||
n = cancel_orders_for_symbol(ex, EXCHANGE_KIND, sym, scope=scope)
|
||||
return {"ok": True, "exchange": EXCHANGE_KIND, "cancelled_count": n, "scope": scope}
|
||||
except Exception as e:
|
||||
return JSONResponse(
|
||||
{"ok": False, "error": str(e), "exchange": EXCHANGE_KIND, "cancelled_count": 0},
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user