ui: 手续费/设置布局优化,行情优先 CTP
手续费数据源与本地倍率并列双列;设置页去掉参考资金、缩小改密表单;CTP 连接时订阅柜台 tick 作为行情源。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user