Add CTP auto-connect toggle to stop off-hours reconnect attempts.

When disabled, disconnect immediately and skip auto-reconnect, premarket connect, and TCP probes that fail outside SimNow trading hours.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-26 18:53:49 +08:00
parent 3a150dd3d6
commit 631aa2c0ab
9 changed files with 231 additions and 18 deletions
+62 -5
View File
@@ -33,6 +33,7 @@
var hasSlTpMonitoring = false;
var ctpConnected = false;
var ctpConnecting = false;
var ctpAutoConnectEnabled = window.CTP_AUTO_CONNECT !== false;
var positionsRendered = false;
var selectedMaxLots = null;
var recommendMaxByProduct = {};
@@ -183,6 +184,10 @@
ctpConnecting = !!connecting;
isTradingSession = !!data.trading_session;
syncCtpBadgeFromStatus(data.ctp_status || { connected: connected, connecting: connecting });
if (data.ctp_status && typeof data.ctp_status.auto_connect_enabled === 'boolean') {
ctpAutoConnectEnabled = data.ctp_status.auto_connect_enabled;
updateCtpConnectButtonState();
}
if (syncBadge) {
if (data.sync_label && connected) {
syncBadge.hidden = false;
@@ -200,6 +205,8 @@
} else if (isCtpUnreachableError(data.ctp_status.last_error)) {
lastCtpUnreachableAt = Date.now();
}
} else if (!connected && data.ctp_status && data.ctp_status.disabled_hint) {
showCtpError(data.ctp_status.disabled_hint);
}
var riskBadge = document.getElementById('risk-badge');
if (riskBadge && data.risk_status) {
@@ -235,14 +242,20 @@
list.innerHTML = '<div class="empty-hint text-loss">' + err + '</div>';
return;
}
if (!ctpAutoConnectEnabled) {
var offHint = (data.ctp_status && data.ctp_status.disabled_hint) ||
'CTP 自动连接已关闭,请在系统设置中开启';
list.innerHTML = '<div class="empty-hint text-muted">' + offHint + '</div>';
return;
}
list.innerHTML = '<div class="empty-hint">CTP 未连接,正在尝试自动重连…</div>';
tryAutoCtpReconnect();
if (ctpAutoConnectEnabled) tryAutoCtpReconnect();
return;
}
list.innerHTML = '<div class="empty-hint">暂无持仓。</div>';
return;
}
if (!connected) {
if (!connected && ctpAutoConnectEnabled) {
tryAutoCtpReconnect();
}
list.innerHTML = rows.map(buildPosCard).join('');
@@ -350,11 +363,28 @@
updateCtpBadge(connected, connecting);
}
function updateCtpConnectButtonState() {
var btnConnect = document.getElementById('btn-ctp-connect');
var hint = document.getElementById('ctp-auto-hint');
if (hint) {
hint.textContent = ctpAutoConnectEnabled
? '断线自动重连 · 开盘前 30 分钟自动连接'
: 'CTP 自动连接已关闭(系统设置可开启)';
}
if (btnConnect && !ctpAutoConnectEnabled) {
btnConnect.disabled = true;
btnConnect.title = '请先在系统设置 → CTP 连接 中开启自动连接';
}
}
function updateCtpBadge(connected, connecting) {
var ctpBadge = document.getElementById('ctp-badge');
var btnConnect = document.getElementById('btn-ctp-connect');
if (ctpBadge) {
if (connecting) {
if (!ctpAutoConnectEnabled && !connected) {
ctpBadge.textContent = 'CTP 已关闭';
ctpBadge.className = 'badge planned';
} else if (connecting) {
ctpBadge.textContent = 'CTP 连接中';
ctpBadge.className = 'badge planned';
} else {
@@ -363,11 +393,17 @@
}
}
if (btnConnect) {
if (connecting) {
if (!ctpAutoConnectEnabled) {
btnConnect.textContent = connected ? '重连 CTP' : '连接 CTP';
btnConnect.disabled = true;
btnConnect.title = '请先在系统设置 → CTP 连接 中开启自动连接';
} else if (connecting) {
btnConnect.textContent = '连接中…';
btnConnect.disabled = true;
btnConnect.title = '';
} else {
btnConnect.disabled = false;
btnConnect.title = '';
btnConnect.textContent = connected ? '重连 CTP' : '连接 CTP';
}
}
@@ -418,6 +454,10 @@
}
function requestCtpConnect(force) {
if (!force && !ctpAutoConnectEnabled) {
showCtpError('CTP 自动连接已关闭,请在系统设置中开启');
return Promise.resolve({ ok: false, disabled: true });
}
if (!force && ctpConnectInflight) {
return Promise.resolve({});
}
@@ -449,6 +489,13 @@
return d;
});
}
if (d.disabled || st.auto_connect_enabled === false) {
ctpAutoConnectEnabled = false;
updateCtpConnectButtonState();
syncCtpBadgeFromStatus(st);
showCtpError(st.disabled_hint || d.error || 'CTP 自动连接已关闭');
return d;
}
if (!d.ok) {
syncCtpBadgeFromStatus(st);
var err = d.error || st.last_error || '连接失败';
@@ -564,6 +611,7 @@
}
function tryAutoCtpReconnect() {
if (!ctpAutoConnectEnabled) return;
if (ctpReconnecting || ctpConnectInflight) return;
var now = Date.now();
if (now - lastCtpReconnectAt < 60000) return;
@@ -1517,14 +1565,23 @@
.then(function (r) { return r.json(); })
.then(function (d) {
var st = d.status || {};
if (typeof st.auto_connect_enabled === 'boolean') {
ctpAutoConnectEnabled = st.auto_connect_enabled;
}
updateCtpConnectButtonState();
syncCtpBadgeFromStatus(st);
if (st.last_error) showCtpError(st.last_error);
if (st.disabled_hint) {
showCtpError(st.disabled_hint);
} else if (st.last_error) {
showCtpError(st.last_error);
}
if (st.connected) pollPositions();
})
.catch(function () {});
}
runWhenReady(function () {
updateCtpConnectButtonState();
setPriceType('limit');
if (isFixedMode() && lotsCalc) {
lotsCalc.value = String(window.TRADE_FIXED_LOTS || 1);