Allow scheduled CTP connect when auto-connect setting is off.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-29 20:38:30 +08:00
parent c5262a0a54
commit 94c566fbe5
8 changed files with 39 additions and 36 deletions
+2 -6
View File
@@ -12,7 +12,6 @@ import threading
import time
from typing import Callable
from ctp_settings import is_ctp_auto_connect_enabled
from market_sessions import in_premarket_connect_window, is_trading_session
from vnpy_bridge import ctp_start_connect, ctp_status
@@ -60,10 +59,7 @@ def start_ctp_premarket_connect_worker(
while True:
sleep_sec = max(30, interval)
try:
gs = get_setting_fn
if gs is None:
from fee_specs import get_setting as gs
if is_ctp_auto_connect_enabled(gs) and should_auto_connect_now():
if should_auto_connect_now():
mode = get_mode_fn()
st = ctp_status(mode)
if (
@@ -71,7 +67,7 @@ def start_ctp_premarket_connect_worker(
and not st.get("connecting")
and int(st.get("login_cooldown_sec") or 0) <= 0
):
info = ctp_start_connect(mode, force=False)
info = ctp_start_connect(mode, force=False, scheduled=True)
if info.get("started"):
if is_trading_session():
logger.info("交易时段内自动连接 CTP [%s]", mode)
+1 -9
View File
@@ -13,7 +13,6 @@ import time
from typing import Callable
from ctp_premarket_connect import should_auto_connect_now
from ctp_settings import is_ctp_auto_connect_enabled
from vnpy_bridge import ctp_try_auto_reconnect
logger = logging.getLogger(__name__)
@@ -40,14 +39,7 @@ def start_ctp_reconnect_worker(
def _loop() -> None:
while True:
try:
gs = get_setting_fn
if gs is None:
from fee_specs import get_setting as gs
if (
is_ctp_auto_connect_enabled(gs)
and _auto_reconnect_enabled()
and should_auto_connect_now()
):
if _auto_reconnect_enabled() and should_auto_connect_now():
mode = get_mode_fn()
if ctp_try_auto_reconnect(mode):
logger.debug("CTP 连接正常 [%s]", mode)
+2 -2
View File
@@ -35,11 +35,11 @@ LIVE_FIELDS: tuple[tuple[str, str, str, str], ...] = (
PASSWORD_DB_KEYS = frozenset({"simnow_password", "ctp_live_password"})
CTP_AUTO_CONNECT_KEY = "ctp_auto_connect"
CTP_DISABLED_HINT = "CTP 自动连接已关闭(非交易时段建议关闭,避免反复连接失败"
CTP_DISABLED_HINT = "CTP 自动连接已关闭(非交易时段不重连;开盘前 30 分钟仍会按计划连接"
def is_ctp_auto_connect_enabled(get_setting=None) -> bool:
"""系统设置:是否允许 CTP 连接(含自动重连盘前连接、手动连接)。"""
"""系统设置:是否允许手动连接及非交易时段自动重连盘前/交易时段计划连接不受此限制)。"""
if get_setting is None:
from fee_specs import get_setting as _gs
+5 -3
View File
@@ -1667,10 +1667,12 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
threading.Thread(target=_warm, daemon=True, name="position-bootstrap").start()
try:
if is_ctp_auto_connect_enabled(get_setting):
from vnpy_bridge import ctp_start_connect
from ctp_premarket_connect import should_auto_connect_now
from vnpy_bridge import ctp_start_connect
if should_auto_connect_now():
mode = get_trading_mode(get_setting)
ctp_start_connect(mode, force=False)
ctp_start_connect(mode, force=False, scheduled=True)
except Exception as exc:
logger.debug("bootstrap ctp connect: %s", exc)
+1 -1
View File
@@ -484,7 +484,7 @@
if (hint) {
hint.textContent = ctpAutoConnectEnabled
? '断线自动重连 · 开盘前 30 分钟自动连接'
: 'CTP 自动连接已关闭(系统设置可开启)';
: '自动连接已关闭 · 开盘前 30 分钟仍会按计划连接';
}
if (btnConnect && !ctpAutoConnectEnabled) {
btnConnect.disabled = true;
+1 -1
View File
@@ -271,7 +271,7 @@
<span>
<strong>CTP 自动连接</strong>
<span class="hint" style="display:block;margin:.25rem 0 0;font-size:.78rem;line-height:1.55">
开启:盘前自动连接、断线重连、持仓页可连 CTP。关闭:立即断开所有 CTP 连接,不再尝试重连
开启:盘前自动连接、断线重连、持仓页可连 CTP。关闭:立即断开,非交易时段不再重连;开盘前 30 分钟及交易时段仍会自动连接
SimNow 非交易时段前置常不可用(与快期相同),建议收盘后关闭。
</span>
</span>
+1 -1
View File
@@ -40,7 +40,7 @@
{% if not ctp_auto_connect %}disabled title="请先在系统设置 → CTP 连接 中开启自动连接"{% endif %}>
{% if ctp_status.connected %}重连 CTP{% else %}连接 CTP{% endif %}
</button>
<span class="text-muted trade-top-hint" id="ctp-auto-hint">{% if ctp_auto_connect %}断线自动重连 · 开盘前 30 分钟自动连接{% else %}CTP 自动连接已关闭{% endif %}</span>
<span class="text-muted trade-top-hint" id="ctp-auto-hint">{% if ctp_auto_connect %}断线自动重连 · 开盘前 30 分钟自动连接{% else %}自动连接已关闭 · 开盘前 30 分钟仍会按计划连接{% endif %}</span>
</div>
</div>
+26 -13
View File
@@ -575,10 +575,10 @@ class CtpBridge:
"td_address": st.get("交易服务器", ""),
}
def connect(self, mode: str, *, force: bool = False) -> None:
from ctp_settings import CTP_DISABLED_HINT, is_ctp_auto_connect_enabled
def connect(self, mode: str, *, force: bool = False, scheduled: bool = False) -> None:
from ctp_settings import CTP_DISABLED_HINT
if not is_ctp_auto_connect_enabled():
if not _ctp_connect_permitted(scheduled=scheduled):
self._last_error = CTP_DISABLED_HINT
_persist_last_error(CTP_DISABLED_HINT)
raise RuntimeError(CTP_DISABLED_HINT)
@@ -680,11 +680,13 @@ class CtpBridge:
finally:
self._connect_in_progress = False
def start_connect_async(self, mode: str, *, force: bool = False) -> dict[str, Any]:
def start_connect_async(
self, mode: str, *, force: bool = False, scheduled: bool = False,
) -> dict[str, Any]:
"""后台连接,不阻塞 HTTP 请求。"""
from ctp_settings import CTP_DISABLED_HINT, is_ctp_auto_connect_enabled
from ctp_settings import CTP_DISABLED_HINT
if not is_ctp_auto_connect_enabled():
if not _ctp_connect_permitted(scheduled=scheduled):
self._last_error = CTP_DISABLED_HINT
_persist_last_error(CTP_DISABLED_HINT)
return {
@@ -709,7 +711,7 @@ class CtpBridge:
def _run() -> None:
try:
self.connect(mode, force=force)
self.connect(mode, force=force, scheduled=scheduled)
except Exception as exc:
logger.warning("CTP 后台连接失败: %s", exc)
@@ -1915,6 +1917,19 @@ def vnpy_available() -> bool:
return get_bridge().available()
def _ctp_connect_permitted(*, scheduled: bool = False) -> bool:
"""scheduled=True:盘前/交易时段计划连接,不受「自动连接」开关限制。"""
from ctp_settings import is_ctp_auto_connect_enabled
if is_ctp_auto_connect_enabled():
return True
if not scheduled:
return False
from ctp_premarket_connect import should_auto_connect_now
return should_auto_connect_now()
def ctp_disconnect(*, set_disabled_hint: bool = False) -> None:
"""主动断开 CTP 并清理内存状态。"""
from ctp_settings import CTP_DISABLED_HINT
@@ -1935,19 +1950,17 @@ def ctp_connect(mode: str, *, force: bool = False) -> dict[str, Any]:
return b.status(mode)
def ctp_start_connect(mode: str, *, force: bool = False) -> dict[str, Any]:
def ctp_start_connect(mode: str, *, force: bool = False, scheduled: bool = False) -> dict[str, Any]:
"""非阻塞发起连接,供 Web API 使用。"""
b = get_bridge()
info = b.start_connect_async(mode, force=force)
info = b.start_connect_async(mode, force=force, scheduled=scheduled)
st = b.status(mode)
return {**info, "status": st}
def ctp_try_auto_reconnect(mode: str) -> bool:
"""断线时静默异步重连;已连接且交易通道正常则不再重复 connect。"""
from ctp_settings import is_ctp_auto_connect_enabled
if not is_ctp_auto_connect_enabled():
if not _ctp_connect_permitted(scheduled=True):
return False
b = get_bridge()
if not b.available():
@@ -1974,7 +1987,7 @@ def ctp_try_auto_reconnect(mode: str) -> bool:
"请更新 SIMNOW_TD_ADDRESS 并确认服务器出网。"
)
return False
info = b.start_connect_async(mode, force=False)
info = b.start_connect_async(mode, force=False, scheduled=True)
return bool(
info.get("connected")
or info.get("connecting")