Isolate CTP in worker process and improve strategy roll UX.
Split vn.py into qihuo-ctp worker with IPC client bridge, keep CTP connected during breaks with cached account fallback, speed up strategy page loads, and allow off-session breakout roll submissions. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+61
-17
@@ -34,6 +34,8 @@
|
||||
var ctpConnecting = false;
|
||||
var ctpAutoConnectEnabled = true;
|
||||
var positionsRendered = false;
|
||||
var posFastPollTimer = null;
|
||||
var posFastPollCount = 0;
|
||||
var lastPosRowCount = 0;
|
||||
var selectedMaxLots = null;
|
||||
var recommendMaxByProduct = {};
|
||||
@@ -248,6 +250,24 @@
|
||||
});
|
||||
}
|
||||
|
||||
function stopPosFastPoll() {
|
||||
if (posFastPollTimer) {
|
||||
clearInterval(posFastPollTimer);
|
||||
posFastPollTimer = null;
|
||||
}
|
||||
posFastPollCount = 0;
|
||||
}
|
||||
|
||||
function startPosFastPoll() {
|
||||
if (posFastPollTimer) return;
|
||||
posFastPollCount = 0;
|
||||
posFastPollTimer = setInterval(function () {
|
||||
pollPositions();
|
||||
posFastPollCount += 1;
|
||||
if (posFastPollCount >= 90) stopPosFastPoll();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function applyPositionsData(data) {
|
||||
if (!data) return;
|
||||
var cap = document.getElementById('cap-display');
|
||||
@@ -312,6 +332,7 @@
|
||||
if (!connected) {
|
||||
if (connecting) {
|
||||
list.innerHTML = '<div class="empty-hint">CTP 连接中,请稍候…</div>';
|
||||
startPosFastPoll();
|
||||
return;
|
||||
}
|
||||
if (cooldownSec > 0 || (data.ctp_status && data.ctp_status.last_error)) {
|
||||
@@ -325,8 +346,8 @@
|
||||
list.innerHTML = '<div class="empty-hint text-muted">' + offHint + '</div>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = '<div class="empty-hint">CTP 未连接,正在尝试自动重连…</div>';
|
||||
if (ctpAutoConnectEnabled) tryAutoCtpReconnect();
|
||||
list.innerHTML = '<div class="empty-hint">CTP 未连接,后台自动连接中…</div>';
|
||||
if (ctpAutoConnectEnabled) refreshCtpStatusPassive();
|
||||
return;
|
||||
}
|
||||
var syncing = data.sync_state === 'syncing';
|
||||
@@ -339,6 +360,7 @@
|
||||
syncBadge.textContent = data.sync_label || '持仓同步中…';
|
||||
syncBadge.className = 'sync-badge text-accent';
|
||||
}
|
||||
startPosFastPoll();
|
||||
return;
|
||||
}
|
||||
list.innerHTML = '<div class="empty-hint">暂无持仓。</div>';
|
||||
@@ -347,9 +369,7 @@
|
||||
return;
|
||||
}
|
||||
lastPosRowCount = rows.length;
|
||||
if (!connected && ctpAutoConnectEnabled) {
|
||||
tryAutoCtpReconnect();
|
||||
}
|
||||
stopPosFastPoll();
|
||||
list.innerHTML = rows.map(buildPosCard).join('');
|
||||
syncPositionListScroll(rows.length);
|
||||
bindPendingDismiss(list);
|
||||
@@ -610,8 +630,9 @@
|
||||
}
|
||||
if (st.connecting && Date.now() < deadline) {
|
||||
syncCtpBadgeFromStatus(st);
|
||||
pollPositions();
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(function () { resolve(tick()); }, 2000);
|
||||
setTimeout(function () { resolve(tick()); }, 800);
|
||||
});
|
||||
}
|
||||
syncCtpBadgeFromStatus(st);
|
||||
@@ -795,18 +816,31 @@
|
||||
});
|
||||
}
|
||||
|
||||
function tryAutoCtpReconnect() {
|
||||
if (!ctpAutoConnectEnabled) return;
|
||||
if (ctpReconnecting || ctpConnectInflight) return;
|
||||
/** 只读 CTP 状态;连接由 qihuo-ctp 后台 worker 负责,前端不发起 connect。 */
|
||||
function refreshCtpStatusPassive() {
|
||||
if (ctpConnected || ctpConnecting) return;
|
||||
var now = Date.now();
|
||||
if (now - lastCtpReconnectAt < 60000) return;
|
||||
if (lastCtpLoginBanAt && now - lastCtpLoginBanAt < 2700000) return;
|
||||
if (lastCtpUnreachableAt && now - lastCtpUnreachableAt < 300000) return;
|
||||
if (now - lastCtpReconnectAt < 8000) return;
|
||||
lastCtpReconnectAt = now;
|
||||
ctpReconnecting = true;
|
||||
requestCtpConnect(false).finally(function () {
|
||||
ctpReconnecting = false;
|
||||
});
|
||||
fetch('/api/ctp/status')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
var st = d.status || {};
|
||||
syncCtpBadgeFromStatus(st);
|
||||
if (st.connected) {
|
||||
showCtpError('');
|
||||
pollPositions();
|
||||
startPosFastPoll();
|
||||
} else if (st.connecting) {
|
||||
updateCtpBadge(false, true);
|
||||
startPosFastPoll();
|
||||
} else if (st.last_error) {
|
||||
showCtpError(st.last_error);
|
||||
} else if (st.disabled_hint) {
|
||||
showCtpError(st.disabled_hint);
|
||||
}
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function showOrderMsg(text, ok) {
|
||||
@@ -1911,12 +1945,22 @@
|
||||
} else if (st.last_error) {
|
||||
showCtpError(st.last_error);
|
||||
}
|
||||
if (st.connected) pollPositions();
|
||||
if (st.connected) {
|
||||
pollPositions();
|
||||
startPosFastPoll();
|
||||
} else if (st.connecting) {
|
||||
startPosFastPoll();
|
||||
waitForCtpConnected(90000);
|
||||
} else if (ctpAutoConnectEnabled && !(st.login_cooldown_sec > 0)) {
|
||||
refreshCtpStatusPassive();
|
||||
startPosFastPoll();
|
||||
}
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function cleanupTradePage() {
|
||||
stopPosFastPoll();
|
||||
if (sessionClockTickTimer) {
|
||||
clearInterval(sessionClockTickTimer);
|
||||
sessionClockTickTimer = null;
|
||||
|
||||
Reference in New Issue
Block a user