Gate order cancel to trading hours and sync trade logs from CTP.

Disable cancel UI outside sessions, query exchange fills for records, and label local vs counterparty rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-26 00:35:51 +08:00
parent a23f2c80ca
commit 9f48f22d16
9 changed files with 606 additions and 8 deletions
+54 -2
View File
@@ -80,6 +80,7 @@ from trading_context import (
)
from ctp_symbol import ths_to_vnpy_symbol
from vnpy_bridge import (
ctp_cancel_order,
ctp_connect,
ctp_get_account,
ctp_get_tick_price,
@@ -354,6 +355,25 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
"label": "止盈监控",
"price": float(tp),
})
for r in conn.execute(
"SELECT * FROM trade_order_monitors WHERE status='pending' ORDER BY id DESC"
).fetchall():
mon = dict(r)
sym = mon.get("symbol") or ""
pending.append({
"symbol_code": sym,
"symbol": mon.get("symbol_name") or sym,
"direction": mon.get("direction") or "long",
"direction_label": "做多" if (mon.get("direction") or "long") == "long" else "做空",
"lots": int(mon.get("lots") or 0),
"price": float(mon.get("order_price") or mon.get("entry_price") or 0),
"order_kind": "open_pending",
"label": "开仓挂单中",
"source": "monitor",
"monitor_id": mon.get("id"),
"can_cancel_order": is_trading_session(),
"cancel_allowed": is_trading_session(),
})
ctp_st = ctp_status(mode)
if ctp_st.get("connected"):
for o in _ctp_active_orders(mode):
@@ -374,6 +394,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
"label": label,
"source": "ctp",
"order_id": o.get("order_id"),
"can_cancel_order": is_trading_session(),
"cancel_allowed": is_trading_session(),
})
return pending
@@ -833,7 +855,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
"est_fee": None,
"can_close": False,
"close_allowed": False,
"can_cancel_order": True,
"can_cancel_order": is_trading_session(),
"cancel_allowed": is_trading_session(),
"auto_cancel_sec": remain,
"pending_timeout_sec": timeout_sec,
"pending_timeout_min": max(1, timeout_sec // 60),
@@ -1285,6 +1308,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
return jsonify({"ok": False, "error": "记录不存在或已关闭"}), 404
mon = dict(row)
if (mon.get("status") or "").strip().lower() == "pending":
if not is_trading_session():
return jsonify({"ok": False, "error": "不在交易时间段,无法撤单"}), 403
ok, msg = cancel_pending_monitor(conn, mon, mode)
_push_position_snapshot_async(fast=False)
return jsonify({"ok": ok, "message": msg})
@@ -1315,6 +1340,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
mode = get_trading_mode(get_setting)
if not ctp_status(mode).get("connected"):
return jsonify({"ok": False, "error": "请先连接 CTP"}), 400
if not is_trading_session():
return jsonify({"ok": False, "error": "不在交易时间段,无法撤单"}), 403
row = conn.execute(
"SELECT * FROM trade_order_monitors WHERE id=? AND status='pending'",
(monitor_id,),
@@ -1327,6 +1354,25 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
finally:
conn.close()
@app.route("/api/trading/order/cancel", methods=["POST"])
@login_required
def api_trading_order_cancel():
"""撤销柜台未成交委托(按 vt_order_id)。"""
d = request.get_json(silent=True) or {}
order_id = (d.get("order_id") or "").strip()
if not order_id:
return jsonify({"ok": False, "error": "无效的委托号"}), 400
mode = get_trading_mode(get_setting)
if not ctp_status(mode).get("connected"):
return jsonify({"ok": False, "error": "请先连接 CTP"}), 400
if not is_trading_session():
return jsonify({"ok": False, "error": "不在交易时间段,无法撤单"}), 403
ok = ctp_cancel_order(mode, order_id)
_push_position_snapshot_async(fast=False)
if not ok:
return jsonify({"ok": False, "error": "撤单失败,委托可能已成交或已撤销"}), 400
return jsonify({"ok": True, "message": "撤单已提交"})
@app.route("/api/trading/close", methods=["POST"])
@login_required
def api_trading_close():
@@ -1409,9 +1455,15 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
(mid,),
)
conn.commit()
try:
from ctp_trade_sync import sync_trade_logs_from_ctp
sync_trade_logs_from_ctp(conn, mode, capital=capital, trading_mode=mode)
conn.commit()
except Exception as exc:
logger.debug("sync trades after close: %s", exc)
conn.close()
_push_position_snapshot_async()
return jsonify({"ok": True, "message": "已平仓并记入交易记录(手动平仓)"})
return jsonify({"ok": True, "message": "已平仓交易记录将按柜台成交同步"})
except ValueError as exc:
conn.close()
return jsonify({"ok": False, "error": str(exc)}), 400