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