fix: 登录冷却期间不再显示 CTP 连接中,优化前端状态同步
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -47,7 +47,11 @@ def start_ctp_premarket_connect_worker(
|
||||
):
|
||||
mode = get_mode_fn()
|
||||
st = ctp_status(mode)
|
||||
if not st.get("connected") and not st.get("connecting"):
|
||||
if (
|
||||
not st.get("connected")
|
||||
and not st.get("connecting")
|
||||
and int(st.get("login_cooldown_sec") or 0) <= 0
|
||||
):
|
||||
info = ctp_start_connect(mode, force=False)
|
||||
if info.get("started"):
|
||||
logger.info(
|
||||
|
||||
@@ -1549,6 +1549,14 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
"status": st,
|
||||
"account": acc,
|
||||
})
|
||||
if info.get("cooldown"):
|
||||
return jsonify({
|
||||
"ok": False,
|
||||
"cooldown": True,
|
||||
"error": st.get("last_error") or "CTP 登录冷却中",
|
||||
"status": st,
|
||||
"account": acc,
|
||||
}), 400
|
||||
return jsonify({
|
||||
"ok": False,
|
||||
"error": st.get("last_error") or "CTP 连接未启动",
|
||||
|
||||
+61
-12
@@ -30,7 +30,7 @@
|
||||
var selectedMaxLots = null;
|
||||
var recommendMaxByProduct = {};
|
||||
var recommendMaxByCode = {};
|
||||
var POS_CACHE_KEY = 'qihuo_trading_live_v2';
|
||||
var POS_CACHE_KEY = 'qihuo_trading_live_v3';
|
||||
|
||||
function runWhenReady(fn) {
|
||||
if (document.readyState === 'loading') {
|
||||
@@ -148,9 +148,11 @@
|
||||
if (cap && data.capital != null) cap.textContent = Number(data.capital).toFixed(2);
|
||||
var connected = data.ctp_status && data.ctp_status.connected;
|
||||
var connecting = data.ctp_status && data.ctp_status.connecting;
|
||||
var cooldownSec = (data.ctp_status && data.ctp_status.login_cooldown_sec) || 0;
|
||||
if (cooldownSec > 0) connecting = false;
|
||||
ctpConnected = !!connected;
|
||||
isTradingSession = !!data.trading_session;
|
||||
updateCtpBadge(!!connected, !!connecting);
|
||||
syncCtpBadgeFromStatus(data.ctp_status || { connected: connected, connecting: connecting });
|
||||
if (!connected && !connecting && data.ctp_status && data.ctp_status.last_error) {
|
||||
showCtpError(data.ctp_status.last_error);
|
||||
if (isCtpLoginBanError(data.ctp_status.last_error)) {
|
||||
@@ -184,6 +186,11 @@
|
||||
list.innerHTML = '<div class="empty-hint">CTP 连接中,请稍候…</div>';
|
||||
return;
|
||||
}
|
||||
if (cooldownSec > 0 || (data.ctp_status && data.ctp_status.last_error)) {
|
||||
var err = (data.ctp_status && data.ctp_status.last_error) || 'CTP 未连接';
|
||||
list.innerHTML = '<div class="empty-hint text-loss">' + err + '</div>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = '<div class="empty-hint">CTP 未连接,正在尝试自动重连…</div>';
|
||||
tryAutoCtpReconnect();
|
||||
return;
|
||||
@@ -305,6 +312,16 @@
|
||||
updateRRDisplay();
|
||||
}
|
||||
|
||||
function syncCtpBadgeFromStatus(st) {
|
||||
if (!st) return;
|
||||
var connected = !!st.connected;
|
||||
var connecting = !!st.connecting;
|
||||
if ((st.login_cooldown_sec || 0) > 0) {
|
||||
connecting = false;
|
||||
}
|
||||
updateCtpBadge(connected, connecting);
|
||||
}
|
||||
|
||||
function updateCtpBadge(connected, connecting) {
|
||||
var ctpBadge = document.getElementById('ctp-badge');
|
||||
var btnConnect = document.getElementById('btn-ctp-connect');
|
||||
@@ -336,7 +353,7 @@
|
||||
.then(function (d) {
|
||||
var st = d.status || {};
|
||||
if (st.connected) {
|
||||
updateCtpBadge(true, false);
|
||||
syncCtpBadgeFromStatus(st);
|
||||
showCtpError('');
|
||||
if (d.account && d.account.available != null) {
|
||||
var avail = document.getElementById('avail-display');
|
||||
@@ -345,13 +362,18 @@
|
||||
pollPositions();
|
||||
return true;
|
||||
}
|
||||
if ((st.login_cooldown_sec || 0) > 0) {
|
||||
syncCtpBadgeFromStatus(st);
|
||||
if (st.last_error) showCtpError(st.last_error);
|
||||
return false;
|
||||
}
|
||||
if (st.connecting && Date.now() < deadline) {
|
||||
updateCtpBadge(false, true);
|
||||
syncCtpBadgeFromStatus(st);
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(function () { resolve(tick()); }, 2000);
|
||||
});
|
||||
}
|
||||
updateCtpBadge(false, false);
|
||||
syncCtpBadgeFromStatus(st);
|
||||
if (st.last_error) {
|
||||
showCtpError(st.last_error);
|
||||
if (isCtpLoginBanError(st.last_error)) {
|
||||
@@ -380,22 +402,28 @@
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (d.status && d.status.connected) {
|
||||
updateCtpBadge(true, false);
|
||||
var st = d.status || {};
|
||||
if (st.connected) {
|
||||
syncCtpBadgeFromStatus(st);
|
||||
showCtpError('');
|
||||
pollPositions();
|
||||
return d;
|
||||
}
|
||||
if (d.connecting || (d.status && d.status.connecting)) {
|
||||
if ((st.login_cooldown_sec || 0) > 0 || d.cooldown) {
|
||||
syncCtpBadgeFromStatus(st);
|
||||
showCtpError(st.last_error || d.error || 'CTP 登录冷却中');
|
||||
return d;
|
||||
}
|
||||
if (d.connecting || st.connecting) {
|
||||
return waitForCtpConnected(70000).then(function (ok) {
|
||||
if (!ok && d.error) showCtpError(d.error);
|
||||
else if (!ok && d.status && d.status.last_error) showCtpError(d.status.last_error);
|
||||
else if (!ok && st.last_error) showCtpError(st.last_error);
|
||||
return d;
|
||||
});
|
||||
}
|
||||
if (!d.ok) {
|
||||
updateCtpBadge(false, false);
|
||||
var err = d.error || (d.status && d.status.last_error) || '连接失败';
|
||||
syncCtpBadgeFromStatus(st);
|
||||
var err = d.error || st.last_error || '连接失败';
|
||||
showCtpError(err);
|
||||
}
|
||||
return d;
|
||||
@@ -1051,6 +1079,24 @@
|
||||
});
|
||||
}
|
||||
|
||||
function initCtpOnLoad() {
|
||||
fetch('/api/ctp/status')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
var st = d.status || {};
|
||||
syncCtpBadgeFromStatus(st);
|
||||
if (st.last_error) showCtpError(st.last_error);
|
||||
if (st.connected) {
|
||||
pollPositions();
|
||||
return;
|
||||
}
|
||||
if ((st.login_cooldown_sec || 0) > 0) return;
|
||||
if (isCtpLoginBanError(st.last_error)) return;
|
||||
if (!st.connecting) requestCtpConnect(false);
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
runWhenReady(function () {
|
||||
setPriceType('limit');
|
||||
if (isFixedMode() && lotsCalc) {
|
||||
@@ -1059,11 +1105,14 @@
|
||||
}
|
||||
var cached = loadPosCache();
|
||||
if (cached) {
|
||||
if (cached.ctp_status) {
|
||||
cached.ctp_status = Object.assign({}, cached.ctp_status, { connecting: false });
|
||||
}
|
||||
applyPositionsData(cached);
|
||||
}
|
||||
pollPositions();
|
||||
connectPositionStream();
|
||||
requestCtpConnect(false);
|
||||
initCtpOnLoad();
|
||||
connectRecommendStream();
|
||||
fetch('/api/recommend/list')
|
||||
.then(function (r) { return r.json(); })
|
||||
|
||||
+3
-1
@@ -251,10 +251,12 @@ class CtpBridge:
|
||||
self.ping()
|
||||
st = _setting_for_mode(mode)
|
||||
missing = [k for k in ("用户名", "密码", "交易服务器") if not st.get(k)]
|
||||
cooldown = self.login_cooldown_remaining()
|
||||
connecting = bool(self._connect_in_progress and cooldown <= 0)
|
||||
return {
|
||||
"vnpy_installed": self.available(),
|
||||
"connected": self._connected_mode == mode,
|
||||
"connecting": self._connect_in_progress,
|
||||
"connecting": connecting,
|
||||
"connected_mode": self._connected_mode,
|
||||
"mode_label": _mode_label(mode),
|
||||
"missing_config": missing,
|
||||
|
||||
Reference in New Issue
Block a user