ui: 手续费/设置布局优化,行情优先 CTP

手续费数据源与本地倍率并列双列;设置页去掉参考资金、缩小改密表单;CTP 连接时订阅柜台 tick 作为行情源。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 13:04:11 +08:00
parent 9d4aea60f0
commit eaca3d43ec
5 changed files with 204 additions and 105 deletions
+86
View File
@@ -89,6 +89,8 @@ class CtpBridge:
self._commission_waiters: dict[int, threading.Event] = {}
self._commission_results: dict[int, dict] = {}
self._commission_hooked = False
self._subscribed: set[str] = set()
self._tick_hooked = False
self._init_engine()
def _init_engine(self) -> None:
@@ -282,6 +284,78 @@ class CtpBridge:
self._commission_waiters.pop(reqid, None)
return self._commission_results.pop(reqid, {})
def _tick_key(self, symbol: str, ex_name: str) -> str:
return f"{symbol.lower()}:{ex_name.upper()}"
def _price_from_tick(self, tick: Any) -> Optional[float]:
for attr in ("last_price", "bid_price_1", "ask_price_1", "pre_close"):
try:
v = float(getattr(tick, attr, 0) or 0)
except (TypeError, ValueError):
v = 0.0
if v > 0:
return v
return None
def _lookup_tick(self, symbol: str, ex_name: str) -> Optional[float]:
if not self._engine:
return None
sym_l = symbol.lower()
ex_u = ex_name.upper()
try:
for tick in self._engine.get_all_ticks():
ts = (getattr(tick, "symbol", "") or "").lower()
te = getattr(tick, "exchange", None)
te_s = str(te.value if hasattr(te, "value") else te or "").upper()
if ts == sym_l and te_s == ex_u:
p = self._price_from_tick(tick)
if p:
return p
except Exception as exc:
logger.debug("lookup tick: %s", exc)
return None
def _ensure_tick_handler(self) -> None:
if self._tick_hooked or not self._ee:
return
self._tick_hooked = True
def subscribe_symbol(self, ths_code: str) -> None:
if not self._engine or not self._connected_mode:
return
try:
from vnpy.trader.object import SubscribeRequest
sym, ex_name = ths_to_vnpy_symbol(ths_code)
key = self._tick_key(sym, ex_name)
if key in self._subscribed:
return
exchange = to_vnpy_exchange(ex_name)
self._ensure_tick_handler()
req = SubscribeRequest(symbol=sym, exchange=exchange)
self._engine.subscribe(req, GATEWAY_NAME)
self._subscribed.add(key)
except Exception as exc:
logger.debug("CTP subscribe %s: %s", ths_code, exc)
def get_tick_price(self, ths_code: str, *, mode: str) -> Optional[float]:
if self._connected_mode != mode or not self._engine:
return None
try:
sym, ex_name = ths_to_vnpy_symbol(ths_code)
except Exception:
return None
price = self._lookup_tick(sym, ex_name)
if price:
return price
self.subscribe_symbol(ths_code)
for _ in range(8):
time.sleep(0.2)
price = self._lookup_tick(sym, ex_name)
if price:
return price
return None
def get_account(self) -> dict[str, Any]:
if not self._engine:
return {}
@@ -478,6 +552,18 @@ def ctp_list_active_orders(mode: str) -> list[dict[str, Any]]:
return b.list_active_orders()
def ctp_get_tick_price(mode: str, ths_code: str) -> Optional[float]:
"""CTP 柜台最新价(需已连接并订阅)。"""
b = get_bridge()
if b.connected_mode != mode:
return None
try:
return b.get_tick_price(ths_code, mode=mode)
except Exception as exc:
logger.debug("ctp_get_tick_price: %s", exc)
return None
def get_ctp_balance(mode: str) -> Optional[float]:
try:
acc = ctp_get_account(mode)