Fix slow CTP position sync after restart and link positions to 15m K-line.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-26 11:05:13 +08:00
parent deb9501cbe
commit 7a4a3f08e5
4 changed files with 80 additions and 10 deletions
+36 -1
View File
@@ -73,6 +73,8 @@ def _load_persisted_last_error() -> str:
return (get_setting(CTP_LAST_ERROR_KEY, "") or "").strip()
_position_refresh_callback: Optional[Callable[[], None]] = None
_position_refresh_debounce_lock = threading.Lock()
_position_refresh_debounce_ts: float = 0.0
def set_position_refresh_callback(fn: Optional[Callable[[], None]]) -> None:
@@ -89,6 +91,23 @@ def _fire_position_refresh_callback() -> None:
except Exception as exc:
logger.debug("position refresh callback: %s", exc)
def _fire_position_refresh_callback_debounced(*, min_interval: float = 0.35) -> None:
global _position_refresh_debounce_ts
now = time.monotonic()
with _position_refresh_debounce_lock:
if now - _position_refresh_debounce_ts < min_interval:
return
_position_refresh_debounce_ts = now
_fire_position_refresh_callback()
def _fire_position_refresh_burst() -> None:
"""连接后持仓回报可能分批到达,分多次触发快照刷新。"""
_fire_position_refresh_callback()
for delay in (1.5, 4.0, 10.0, 25.0):
threading.Timer(delay, _fire_position_refresh_callback).start()
_bridge: Optional["CtpBridge"] = None
_bridge_lock = threading.Lock()
_ctp_td_lock = threading.RLock()
@@ -203,6 +222,7 @@ class CtpBridge:
self._last_trade_query_ts: float = 0.0
self._last_connect_ok_ts: float = 0.0
self._tick_hooked = False
self._position_hooked = False
self._bar_generators: dict[str, Any] = {}
self._bars_1m: dict[str, deque] = {}
self._init_engine()
@@ -217,11 +237,26 @@ class CtpBridge:
self._ee = EventEngine()
self._engine = MainEngine(self._ee)
self._engine.add_gateway(CtpGateway)
self._ensure_position_event_hook()
except ImportError:
self._last_error = "未安装 vnpy / vnpy_ctp,请 pip install vnpy vnpy_ctp"
except Exception as exc:
self._last_error = str(exc)
def _ensure_position_event_hook(self) -> None:
if self._position_hooked or not self._ee:
return
try:
from vnpy.trader.event import EVENT_POSITION
except ImportError:
return
def _on_position(_event) -> None:
_fire_position_refresh_callback_debounced()
self._ee.register(EVENT_POSITION, _on_position)
self._position_hooked = True
def available(self) -> bool:
return self._engine is not None
@@ -414,7 +449,7 @@ class CtpBridge:
mode, self._td_logged_in(),
len(self._engine.get_all_accounts() or []))
self._schedule_fee_sync(mode)
_fire_position_refresh_callback()
_fire_position_refresh_burst()
return
finally:
self._ee.unregister(EVENT_LOG, _on_log)