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:
+54
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user