Restore Gate intraday close/TP-SL controls and document force-close rules.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2565,27 +2565,6 @@ def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict
|
||||
)
|
||||
|
||||
|
||||
_INTRADAY_CLOSE_BLOCK_MSG = (
|
||||
"日内账户禁止中控手动平仓/改委托,请等待计划止损/止盈或整点强制清仓"
|
||||
)
|
||||
|
||||
|
||||
def _meta_intraday_discipline(meta: dict | None) -> bool:
|
||||
if not isinstance(meta, dict):
|
||||
return False
|
||||
if meta.get("intraday_discipline") is True:
|
||||
return True
|
||||
return meta.get("order_entry_profile") == "intraday"
|
||||
|
||||
|
||||
async def _fetch_exchange_intraday_discipline(
|
||||
client: httpx.AsyncClient, ex: dict
|
||||
) -> bool:
|
||||
data = await _fetch_flask_json(client, ex, "/api/hub/meta")
|
||||
meta = (data or {}).get("meta") if isinstance(data, dict) else None
|
||||
return _meta_intraday_discipline(meta if isinstance(meta, dict) else None)
|
||||
|
||||
|
||||
async def _fetch_exchange_flask_bundle(
|
||||
client: httpx.AsyncClient, ex: dict, *, trading_day: str | None = None
|
||||
) -> tuple[dict | None, dict | None, list | None, dict | None, dict | None, dict | None]:
|
||||
@@ -2980,8 +2959,6 @@ async def api_close_position(exchange_id: str, body: ClosePositionBody):
|
||||
raise HTTPException(status_code=400, detail="side 须为 long 或 short")
|
||||
url = f"{ex['agent_url'].rstrip('/')}/emergency/close-position"
|
||||
async with httpx.AsyncClient() as client:
|
||||
if await _fetch_exchange_intraday_discipline(client, ex):
|
||||
raise HTTPException(status_code=403, detail=_INTRADAY_CLOSE_BLOCK_MSG)
|
||||
r = await client.post(
|
||||
url,
|
||||
headers=_agent_headers(),
|
||||
@@ -3018,8 +2995,6 @@ async def api_place_tpsl(exchange_id: str, body: PlaceTpslBody):
|
||||
raise HTTPException(status_code=404, detail="账户未启用")
|
||||
url = f"{ex['agent_url'].rstrip('/')}/orders/place-tpsl"
|
||||
async with httpx.AsyncClient() as client:
|
||||
if await _fetch_exchange_intraday_discipline(client, ex):
|
||||
raise HTTPException(status_code=403, detail=_INTRADAY_CLOSE_BLOCK_MSG)
|
||||
r = await client.post(
|
||||
url,
|
||||
headers=_agent_headers(),
|
||||
@@ -3077,8 +3052,6 @@ async def api_close_exchange(exchange_id: str):
|
||||
raise HTTPException(status_code=404, detail="账户未启用")
|
||||
url = f"{ex['agent_url'].rstrip('/')}/emergency/close-all"
|
||||
async with httpx.AsyncClient() as client:
|
||||
if await _fetch_exchange_intraday_discipline(client, ex):
|
||||
raise HTTPException(status_code=403, detail=_INTRADAY_CLOSE_BLOCK_MSG)
|
||||
r = await client.post(url, headers=_agent_headers(), timeout=120.0)
|
||||
try:
|
||||
body = r.json()
|
||||
@@ -3115,13 +3088,6 @@ async def api_close_all(body: CloseAllBody | None = Body(default=None)):
|
||||
async with httpx.AsyncClient() as client:
|
||||
|
||||
async def one(ex: dict):
|
||||
if await _fetch_exchange_intraday_discipline(client, ex):
|
||||
return {
|
||||
"id": ex["id"],
|
||||
"name": ex["name"],
|
||||
"skipped": True,
|
||||
"reason": _INTRADAY_CLOSE_BLOCK_MSG,
|
||||
}
|
||||
url = f"{ex['agent_url'].rstrip('/')}/emergency/close-all"
|
||||
try:
|
||||
r = await client.post(url, headers=_agent_headers(), timeout=120.0)
|
||||
|
||||
@@ -3164,7 +3164,7 @@
|
||||
const px = orderTriggerOrPrice(o);
|
||||
const trig = px != null ? fmtSymbolPrice(px, symbol, tickMap) : "—";
|
||||
const cancelBtn =
|
||||
!intraday && oid && o.channel !== "plan"
|
||||
oid && o.channel !== "plan"
|
||||
? `<button type="button" class="pos-ex-cancel-btn btn-cancel-order" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-order-id="${oid}" data-channel="${ch}">撤单</button>`
|
||||
: "";
|
||||
const planHint = o.channel === "plan" ? '<span class="pos-ex-plan-hint">(下单监控)</span>' : "";
|
||||
@@ -3491,9 +3491,7 @@
|
||||
const tcSymBadge = !isTrend && mo.time_close_enabled ? timeCloseSymbolBadgeHtml(mo) : "";
|
||||
const fcSymBadge = !isTrend && mo.force_close_enabled ? forceCloseSymbolBadgeHtml(mo) : "";
|
||||
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder, trendPlan);
|
||||
const headActions = intraday
|
||||
? ""
|
||||
: `<div class="pos-head-actions">
|
||||
const headActions = `<div class="pos-head-actions">
|
||||
<button type="button" class="pos-entrust-btn btn-place-tpsl" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}" data-contracts="${contractsAttr}" data-sl="${slAttr}" data-tp="${tpAttr}">委托</button>
|
||||
<button type="button" class="pos-close-btn btn-close-pos" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}">平仓</button>
|
||||
</div>`;
|
||||
@@ -3657,9 +3655,7 @@
|
||||
const fcBadge =
|
||||
!isTrendContext(mo, trendPlan) && mo.force_close_enabled ? forceCloseSymbolBadgeHtml(mo) : "";
|
||||
const intraday = !!options.intradayDiscipline;
|
||||
const actionCell = intraday
|
||||
? ""
|
||||
: `<div class="pos-action-group">
|
||||
const actionCell = `<div class="pos-action-group">
|
||||
<button type="button" class="btn-place-tpsl btn-sm ghost" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}" data-contracts="${contractsAttr}" data-sl="${slAttr}" data-tp="${tpAttr}">委托</button>
|
||||
<button type="button" class="btn-close-pos btn-sm danger" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}">平仓</button>
|
||||
</div>`;
|
||||
@@ -4128,7 +4124,7 @@
|
||||
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/key_monitor">监控位</a>` : ""}
|
||||
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/records">复盘</a>` : ""}
|
||||
${flaskOpen && (row.capabilities || []).includes("options") ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/options">期权</a>` : ""}
|
||||
${intraday ? "" : `<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>`}
|
||||
<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>
|
||||
</div>
|
||||
</div>`;
|
||||
if (!row.http_ok || ag.ok === false) {
|
||||
@@ -4519,7 +4515,7 @@
|
||||
: "";
|
||||
const intraday = isIntradayDisciplineRow(row);
|
||||
const fcHeadBadge = intraday && !isOkxOptionsCard ? forceCloseHeadBadgeHtml(row.force_close) : "";
|
||||
const showCloseAll = !intraday && !isOkxOptionsCard;
|
||||
const showCloseAll = !isOkxOptionsCard;
|
||||
const layoutCls = opts.okxSplit
|
||||
? " card-monitor-okx-split"
|
||||
: opts.splitSide || okxPart
|
||||
|
||||
@@ -1767,6 +1767,6 @@
|
||||
<script src="/assets/options_expiry_countdown.js?v=1"></script>
|
||||
<script src="/assets/options_position_cards.js?v=3"></script>
|
||||
<script src="/assets/backup.js?v=1"></script>
|
||||
<script src="/assets/app.js?v=20260724-display-hide"></script>
|
||||
<script src="/assets/app.js?v=20260805-intraday-close"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user