diff --git a/core/eventbus.py b/core/eventbus.py index 713c16b..8d25158 100644 --- a/core/eventbus.py +++ b/core/eventbus.py @@ -1,22 +1,10 @@ -# 定义事件处理函数 -ActionEventEnableTrade = "enable_trade" -ResultEventTradeEnabled = "trade_enabled" -ActionEventDisableTrade = "disable_trade" -ResultEventTradeDisabled = "trade_disabled" + # 市场数据监听控制事件 MarketDataUpdate = "market_data_update" ActionEnableMarketData = "enable_market_data" ActionDisableMarketData = "disable_market_data" MarketDataEnabled = "market_data_enabled" MarketDataDisabled = "market_data_disabled" -# 删除交易标的事件 -EventTradeTargetUpdate = "trade_target_update" -ActionEventAddTradeTarget = "add_trade_target" -ResultEventTradeTargetAdded = "trade_target_added" -ActionEventDeleteTradeTarget = "delete_trade_target" -ResultEventTradeTargetDeleted = "trade_target_deleted" -# 网格修正事件 -ActionEventGridFix = "grid_fix" # Pring Log EventPrintLog = "print_log" diff --git a/core/qmt.py b/core/qmt.py index 0a64c15..cdff455 100644 --- a/core/qmt.py +++ b/core/qmt.py @@ -75,6 +75,13 @@ class QmtV(XtQuantTraderCallback): strategy_name, # strategy_name orderRemark # remark # type: ignore ) + + def getInstrumentName(self, stock_code:str): + # print(f"getInstrumentName: 获取标的名称 {stock_code}") + detail = xtdata.get_instrument_detail(stock_code, False) + if detail is None: + return None + return detail['InstrumentName'] # def print_position_info(self): # positions:list[XtPosition] = self.xt_trader.query_stock_positions(self.account) diff --git a/core/sfgrid/bus_events.py b/core/sfgrid/bus_events.py new file mode 100644 index 0000000..1542033 --- /dev/null +++ b/core/sfgrid/bus_events.py @@ -0,0 +1,14 @@ +# 删除交易标的事件 +EventTradeTargetUpdate = "trade_target_update" +ActionEventAddTradeTarget = "add_trade_target" +ResultEventTradeTargetAdded = "trade_target_added" +ActionEventDeleteTradeTarget = "delete_trade_target" +ResultEventTradeTargetDeleted = "trade_target_deleted" +# 网格修正事件 +ActionEventGridFix = "grid_fix" + +# 定义事件处理函数 +ActionEventEnableTrade = "enable_trade" +ResultEventTradeEnabled = "trade_enabled" +ActionEventDisableTrade = "disable_trade" +ResultEventTradeDisabled = "trade_disabled" \ No newline at end of file diff --git a/core/sfgrid/sfgrid_controller.py b/core/sfgrid/sfgrid_controller.py index 41a14bf..bbcf010 100644 --- a/core/sfgrid/sfgrid_controller.py +++ b/core/sfgrid/sfgrid_controller.py @@ -1,6 +1,10 @@ # coding:utf-8 +from typing import Any + + from core.sfgrid.model import SFGridTradeTarget as TradeTarget -from core.eventbus import ActionDisableMarketData, ActionEnableMarketData, ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, EventTradeTargetUpdate, MarketDataUpdate, MarketDataEnabled, MarketDataDisabled, ResultEventTradeDisabled, ResultEventTradeEnabled, ResultEventTradeTargetDeleted, ActionEventGridFix, event_bus +from .bus_events import ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, EventTradeTargetUpdate, ResultEventTradeDisabled, ResultEventTradeEnabled, ResultEventTradeTargetAdded, ResultEventTradeTargetDeleted, ActionEventGridFix +from core.eventbus import event_bus, MarketDataEnabled, MarketDataDisabled, MarketDataUpdate from xtquant import xttrader from xtquant.xttrader import XtQuantTrader import time @@ -9,7 +13,7 @@ from peewee import ModelSelect import core.sfgrid.model as model import config from core.sfgrid.sfgrid_strategy import SFGridStrategy -from core.util import getInstrumentName, getStockPosition, queryPendingOrder +from core.util import getStockPosition, queryPendingOrder from xtquant.xttrader import XtQuantTrader from xtquant.xttype import StockAccount, XtAsset, XtOrder, XtPosition, XtTrade from xtquant import xtdata @@ -21,52 +25,79 @@ from core.qmt import qmtv from core.sfgrid.objects import GridFixData # 量化核心控制对象 -class SFGridController(XtQuantTraderCallback): +class SFGridController: def __init__(self): super().__init__() self.registerEventHandler() - self.listening_stock = [] - self.stock_trade_ctrl = {} - self.init_instrument_pool(qmtv.xttrader, qmtv.account) # type: ignore - self.seq = None PrintLog(LogLevel.INFO, '- [成功]三疯交易系统初始化完成') - self.startMarketData() + def registerEventHandler(self): event_bus.subscribe(ActionEventEnableTrade, self.onEnableTrade) event_bus.subscribe(ActionEventDisableTrade, self.onDisableTrade) - event_bus.subscribe(ActionEnableMarketData, self.onMarketDataEnabled) - event_bus.subscribe(ActionDisableMarketData, self.onMarketDataDisabled) event_bus.subscribe(ActionEventAddTradeTarget, self.onAddTradeTarget) event_bus.subscribe(ActionEventDeleteTradeTarget, self.onDeleteTradeTarget) event_bus.subscribe(ActionEventGridFix, self.onGridFix) - def onDeleteTradeTarget(self, id: int): + def onDeleteTradeTarget(self, target: TradeTarget): """处理删除交易标的事件""" - self.del_trade_target(id) - # 发布删除完成事件 - event_bus.publish(ResultEventTradeTargetDeleted, id) + id = target.get_id() + try: + # 从数据库中删除 + target.delete_instance() + + PrintLog(LogLevel.INFO, f"已删除交易标的: id{id} {target.stock_code} - {target.stock_name}") + # 发布删除完成事件 + event_bus.publish(ResultEventTradeTargetDeleted, target) + except Exception as e: + PrintLog(LogLevel.ERROR, f"删除交易标的失败 ID {id}: {str(e)}") def onAddTradeTarget(self, stock_code: str): """处理添加交易标的事件""" - self.add_trade_target(stock_code) - - def onMarketDataEnabled(self, data): - """处理市场数据监听启用事件""" - self.startMarketData() - - def onMarketDataDisabled(self, data): - """处理市场数据监听禁用事件""" - self.stopMarketData() + try: + stock_name = qmtv.getInstrumentName(stock_code) + if not stock_name: + PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确') + return + + # 检查是否已存在该标的 + existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code) + if existing_target: + PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在') + return + + # 刷新标的持仓 + pos = qmtv.getStockPosition(stock_code) # type: ignore + new_target = TradeTarget.create( + stock_name=stock_name, + stock_code=stock_code, + market_price=0.0, + current_position=pos, + grid_index=0, + last_trade_price=0.0, + plan_buy_price=0.0, + plan_sell_price=0.0, + current_order_price=0.0, + current_order_no='', + current_order_type='' + ) + new_target.save() + # 更新标的池 + event_bus.publish(ResultEventTradeTargetAdded, new_target) + + except Exception as e: + PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}') def onEnableTrade(self, id: int): - self.start_stock_trade(id) + pass + # self.start_stock_trade(id) def onDisableTrade(self, id: int): - self.pause_stock_trade(id) + pass + # self.pause_stock_trade(id) def onGridFix(self, data: GridFixData): """处理网格修正事件""" @@ -82,28 +113,9 @@ class SFGridController(XtQuantTraderCallback): target.grid_index = grid_index target.save() - # 更新内存中的交易标的 - if target.get_id() in self.instrument_pool: - self.instrument_pool[target.get_id()] = target - - # 更新交易控制器中的网格信息 - if target.stock_code in self.stock_trade_ctrl: - trade_controller: SFGridStrategy = self.stock_trade_ctrl[target.stock_code] - trade_controller.updateGridIndex(grid_index) # type: ignore - PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}") except Exception as e: PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}") - - def startMarketData(self): - PrintLog(LogLevel.INFO, '- 启动市场数据订阅') - - self.seq = xtdata.subscribe_whole_quote(['SH', 'SZ'], callback=self.onDataUpdate) - if self.seq == -1: - PrintLog(LogLevel.ERROR, '- 市场数据订阅失败') - else: - event_bus.publish(MarketDataEnabled, True) - PrintLog(LogLevel.INFO, f'- 市场数据订阅成功, 订阅号={self.seq}') @@ -114,222 +126,53 @@ class SFGridController(XtQuantTraderCallback): xtdata.unsubscribe_quote(self.seq) event_bus.publish(MarketDataDisabled, False) - - def add_trade_target(self, stock_code: str): - try: - stock_name = getInstrumentName(stock_code) - if not stock_name: - PrintLog(LogLevel.ERROR, f'无法获取股票代码 {stock_code} 的名称,请检查代码是否正确') - return - - # 检查是否已存在该标的 - existing_target = TradeTarget.get_or_none(TradeTarget.stock_code == stock_code) - if existing_target: - PrintLog(LogLevel.INFO, f'交易标的 {stock_code} {stock_name} 已存在') - return - - new_target = TradeTarget.create( - stock_name=stock_name, - stock_code=stock_code, - market_price=0.0, - current_position=0, - grid_index=0, - last_trade_price=0.0, - plan_buy_price=0.0, - plan_sell_price=0.0, - current_order_price=0.0, - current_order_no='', - current_order_type='' - ) - new_target.save() - PrintLog(LogLevel.INFO, f'新增交易标的 {stock_code} {stock_name}, {new_target.id}') - # 刷新标的持仓 - pos = getStockPosition(stock_code, self.xt_trader, self.account) # type: ignore - TradeTarget.update(current_position=pos).where(TradeTarget.stock_code == stock_code).execute() - # 更新标的池 - self.refresh_targets() - # 添加交易控制器 - stockTradeController = SFGridStrategy(new_target, self.xt_trader, self.account) # type: ignore - self.stock_trade_ctrl[stock_code] = stockTradeController - - except Exception as e: - PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}') - - - def del_trade_target(self, id:int): - try: - # 检查标的是否存在 - if id not in self.instrument_pool: - PrintLog(LogLevel.ERROR, f"交易标的 ID {id} 不存在") - return - - target: TradeTarget = self.instrument_pool[id] - - # 如果存在交易控制器,先停止交易 - if target.stock_code in self.stock_trade_ctrl: - # 停止交易控制器 - del self.stock_trade_ctrl[target.stock_code] - - # 从数据库中删除 - target.delete_instance() - - # 从内存中删除 - del self.instrument_pool[id] - - # 刷新标的池 - self.refresh_targets() - - PrintLog(LogLevel.INFO, f"已删除交易标的: {target.stock_code} - {target.stock_name}") - except Exception as e: - PrintLog(LogLevel.ERROR, f"删除交易标的失败 ID {id}: {str(e)}") - def init_instrument_pool(self, xtTrader:XtQuantTrader, account:StockAccount): - self.refresh_targets() - - for id in self.instrument_pool: - target:TradeTarget = self.instrument_pool[id] - status = "新建" if target.status == 0 else "已建初始仓" - PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {getStockPosition(target.stock_code, self.xt_trader, self.account)} 网格索引: {target.grid_index} 基准价格 {config.grid_price[target.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') # type: ignore - - tradeTarget:TradeTarget = self.instrument_pool[id] - tradeTarget.current_position = getStockPosition(tradeTarget.stock_code, xtTrader, account) # type: ignore - result = tradeTarget.save() - PrintLog(LogLevel.INFO, f' |- 同步[{target.stock_code}-{target.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]') - stockTradeController = SFGridStrategy(tradeTarget, self.xt_trader, self.account) # type: ignore - self.stock_trade_ctrl[tradeTarget.stock_code] = stockTradeController - event_bus.publish(EventTradeTargetUpdate, tradeTarget) - - PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.instrument_pool)} 个标的') + # # 初始化指定标的交易控制器 + # def start_stock_trade(self, tradeTarget: TradeTarget): + # # check existing thread + # if tradeTarget.stock_code in self.stock_trade_ctrl: + # tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code] + + # tradeTarget = tradeController.enabledTrading(True) + # self.instrument_pool[id] = tradeTarget + # event_bus.publish(ResultEventTradeEnabled, tradeTarget) + # else: + # PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}") - def refresh_targets(self): - # 更新标的池 - results:ModelSelect = TradeTarget.select() - self.instrument_pool: dict[int, TradeTarget] = {} - for temp in results: - result :TradeTarget = temp - self.instrument_pool[result.get_id()] = result - - - # 初始化指定标的交易控制器 - def start_stock_trade(self, id: int): - tradeTarget: TradeTarget = self.instrument_pool[id] - # check existing thread - if tradeTarget.stock_code in self.stock_trade_ctrl: - tradeController: SFGridStrategy = self.stock_trade_ctrl[tradeTarget.stock_code] - - tradeTarget = tradeController.enabledTrading(True) - self.instrument_pool[id] = tradeTarget - event_bus.publish(ResultEventTradeEnabled, tradeTarget) - else: - PrintLog(LogLevel.INFO, f"\t创建标的交易控制器 {tradeTarget.stock_code} {getInstrumentName(tradeTarget.stock_code)}") - - - def pause_stock_trade(self, id: int): - localTarget: TradeTarget = self.instrument_pool[id] - print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}') - if localTarget.stock_code in self.stock_trade_ctrl: - tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code] - tradeTarget = tradeController.enabledTrading(False) - orders = queryPendingOrder(localTarget.stock_code, tradeController.getName(), self.xt_trader, self.account) # type: ignore - for order in orders: - qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id) - print(f'取消未成交订单 {len(orders)}') - self.instrument_pool[id] = tradeTarget - event_bus.publish(ResultEventTradeDisabled, tradeTarget) - else: - print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n") + # def pause_stock_trade(self, id: int): + # localTarget: TradeTarget = self.instrument_pool[id] + # print(f'暂停标的交易 {localTarget.stock_code} - enabled {localTarget.enabled}') + # if localTarget.stock_code in self.stock_trade_ctrl: + # tradeController: SFGridStrategy = self.stock_trade_ctrl[localTarget.stock_code] + # tradeTarget = tradeController.enabledTrading(False) + # orders = queryPendingOrder(localTarget.stock_code, tradeController.getName(), self.xt_trader, self.account) # type: ignore + # for order in orders: + # qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id) + # print(f'取消未成交订单 {len(orders)}') + # self.instrument_pool[id] = tradeTarget + # event_bus.publish(ResultEventTradeDisabled, tradeTarget) + # else: + # print(f"标的交易控制器不存在 {localTarget.stock_code} {localTarget.stock_name}\n") # ====== 市场回调方法 -- 以下方法由XtQuantData调用 ====== - def onDataUpdate(self, data): - # 收集所有市场数据用于市场监控 - for stock_code, tickData in data.items(): - if stock_code in self.stock_trade_ctrl: - stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code] - stock_controller.onDataUpdate(data) - else: - # 非目标交易,发布市场数据更新事件用于市场监控 - lastPrice = tickData['lastPrice'] - if lastPrice == 10 or stock_code in self.listening_stock: - # 发布市场数据更新事件用于市场监控 - market_target = TradeTarget() - market_target.stock_code = stock_code - market_target.stock_name = getInstrumentName(stock_code) # type: ignore - market_target.market_price = lastPrice # type: ignore - event_bus.publish(MarketDataUpdate, market_target) - if stock_code not in self.listening_stock: - self.listening_stock.append(stock_code) + # def onDataUpdate(self, data): + # # 收集所有市场数据用于市场监控 + # for stock_code, tickData in data.items(): + # if stock_code in self.stock_trade_ctrl: + # stock_controller: SFGridStrategy = self.stock_trade_ctrl[stock_code] + # stock_controller.onDataUpdate(data) + # else: + # # 非目标交易,发布市场数据更新事件用于市场监控 + # lastPrice = tickData['lastPrice'] + # if lastPrice == 10 or stock_code in self.listening_stock: + # # 发布市场数据更新事件用于市场监控 + # market_target = TradeTarget() + # market_target.stock_code = stock_code + # market_target.stock_name = getInstrumentName(stock_code) # type: ignore + # market_target.market_price = lastPrice # type: ignore + # event_bus.publish(MarketDataUpdate, market_target) + # if stock_code not in self.listening_stock: + # self.listening_stock.append(stock_code) - - # ====== 市场回调方法 -- 以下方法由XtQuantTrader调用 ====== - def on_connected(self): - """ - 连接成功推送 - """ - print(datetime.datetime.now(), '连接成功回调') - - def on_disconnected(self): - """ - 连接断开 - :return: - """ - print(datetime.datetime.now(), '连接断开回调') - - def on_stock_order(self, order:XtOrder): - """ - 委托回报推送 - :param order: XtOrder对象 - :return: - """ - print(f'orderd {order.strategy_name}-{order.stock_code} {order.order_id} {order.order_volume}-{order.order_status}') - stockCode = order.stock_code - ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] - # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - if ctrl is not None and order.strategy_name == ctrl.getName(): - print(f'controller info {ctrl.getName()}') - ctrl.onAsyncOrderResponse(order) # type: ignore - else: - print(f"委托下单回调 投资备注 orderId: {order.order_sysid} [{order.stock_code}-{order.instrument_name}] volume: {order.order_volume} 订单策略: '{order.strategy_name}'<-->'{ctrl.getName()}'") - - - def on_stock_trade(self, trade:XtTrade): - """ - 成交变动推送 - :param trade: XtTrade对象 - :return: - """ - stockCode = trade.stock_code - ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] - # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - if ctrl is not None and trade.strategy_name == ctrl.getName(): - ctrl.onOrderTrade(trade) - else: - print(f"委托回调 投资备注 {trade.strategy_name} 不匹配 {ctrl.getName()}") - - # def on_order_stock_async_response(self, response:XtOrderResponse): - # stockCode = response.order_remark - # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] - # # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 - # if ctrl is not None and response.strategy_name == ctrl.getName(): - # ctrl.onAsyncOrderResponse(response) - # else: - # print(f"委托回调 投资备注 {response.strategy_name} 不匹配 {ctrl.getName()}") - - def on_order_error(self, order_error): - """ - 委托失败推送 - :param order_error:XtOrderError 对象 - :return: - """ - # print("on order_error callback") - # print(order_error.order_id, order_error.error_id, order_error.error_msg) - print(f"\n委托报错回调 {order_error.order_remark} {order_error.error_msg}") - - - def on_account_status(self, status): - """ - :param response: XtAccountStatus 对象 - :return: - """ - print(datetime.datetime.now(), status) \ No newline at end of file diff --git a/core/sfgrid/sfgrid_strategy.py b/core/sfgrid/sfgrid_strategy.py index 723bfe8..3283b99 100644 --- a/core/sfgrid/sfgrid_strategy.py +++ b/core/sfgrid/sfgrid_strategy.py @@ -1,12 +1,13 @@ from core.qmt import qmtv +from core.sfgrid.bus_events import EventTradeTargetUpdate import core.sfgrid.model as model from core import constants -from core.eventbus import EventTradeTargetUpdate, event_bus +from core.eventbus import event_bus from core.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell from core.util import queryPendingOrder, is_trading_time -from xtquant import xttrader, xtconstant -from xtquant.xttype import StockAccount, XtOrder, XtTrade +from xtquant import xtconstant +from xtquant.xttype import XtOrder, XtTrade import config import threading diff --git a/core/sfgrid/sfgrid_ui.py b/core/sfgrid/sfgrid_ui.py index 9b4901b..7f19c43 100644 --- a/core/sfgrid/sfgrid_ui.py +++ b/core/sfgrid/sfgrid_ui.py @@ -7,31 +7,36 @@ import threading import time import core.eventbus as eBus from core.logger import LogLevel, PrintLog +from core.sfgrid.bus_events import ActionEventAddTradeTarget, ActionEventDeleteTradeTarget, ActionEventDisableTrade, ActionEventEnableTrade, ActionEventGridFix, EventTradeTargetUpdate, ResultEventTradeTargetAdded, ResultEventTradeTargetDeleted from core.sfgrid.model import SFGridTradeTarget import configparser import config from core.sfgrid.objects import GridFixData from core.qmt import qmtv +from core.sfgrid.sfgrid_controller import SFGridController from core.sfgrid.sfgrid_strategy import SFGridStrategy class TradeTargetUI(ttk.Frame): def __init__(self, parent): super().__init__(parent) + self.controller = SFGridController() self.tradeTargetData:dict[int, SFGridTradeTarget] = {} # id->trade_target - self.strategy_ctrl:dict[str, SFGridStrategy] = {} # stock_code->trade_target + self.strategy_ctrl:dict[int, SFGridStrategy] = {} # stock_code->trade_target self.init_trade_target_pool() self.registerEventHandler() # 创建刷新线程标志 - self.refresh_thread_running = True # 默认不启动刷新线程 + self.refresh_thread_running = False # 默认不启动刷新线程 # 市场监控数据 self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}} # 创建界面 self.create_ui() + + self.start_ui_refresh() def refresh_targets(self): # 更新标的池 @@ -52,20 +57,21 @@ class TradeTargetUI(ttk.Frame): result = tradeTarget.save() PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]') stockTradeController = SFGridStrategy(tradeTarget) # type: ignore - self.strategy_ctrl[tradeTarget.stock_code] = stockTradeController # pyright: ignore[reportArgumentType] + self.strategy_ctrl[id] = stockTradeController # pyright: ignore[reportArgumentType] # eBus.event_bus.publish(eBus.EventTradeTargetUpdate, tradeTarget) PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的') def registerEventHandler(self): - # eBus.event_bus.subscribe(eBus.EventTradeTargetUpdate, self.onTradeTargetUpdated) + eBus.event_bus.subscribe(EventTradeTargetUpdate, self.onTradeTargetUpdated) # eBus.event_bus.subscribe(eBus.MarketDataUpdate, self.onMarketDataUpdated) # eBus.event_bus.subscribe(eBus.ResultEventTradeEnabled, self.onTradeEnabled) # eBus.event_bus.subscribe(eBus.ResultEventTradeDisabled, self.onTradeDisabled) # eBus.event_bus.subscribe(eBus.MarketDataEnabled, self.onMarketDataToggled) # eBus.event_bus.subscribe(eBus.MarketDataDisabled, self.onMarketDataToggled) - eBus.event_bus.subscribe(eBus.ResultEventTradeTargetDeleted, self.onTradeTargetDeleted) + eBus.event_bus.subscribe(ResultEventTradeTargetDeleted, self.onTradeTargetDeleted) + eBus.event_bus.subscribe(ResultEventTradeTargetAdded, self.onTradeTargetUpdated) def start_refresh_thread(self): """启动刷新线程""" @@ -84,22 +90,17 @@ class TradeTargetUI(ttk.Frame): """停止刷新线程""" self.refresh_thread_running = False - def onTradeTargetDeleted(self, id: int): + def onTradeTargetDeleted(self, target: SFGridTradeTarget): """处理交易标的删除完成事件""" # 从本地数据中删除 + id = target.get_id() if id in self.tradeTargetData: + PrintLog(LogLevel.DEBUG, f"删除交易标的,ID: {id}") del self.tradeTargetData[id] + del self.strategy_ctrl[id] # 添加日志 PrintLog(LogLevel.INFO, f"交易标的已删除,ID: {id}") - - def onMarketDataToggled(self, data:bool): - self.market_data_enabled = self.market_data_switch_var.get() - PrintLog(LogLevel.INFO, "市场数据监听已" + ("启用" if data else "禁用")) - # 同步UI刷新线程状态 - if data: - self.start_ui_refresh() - else: - self.stop_ui_refresh() + def onTradeEnabled(self, target:SFGridTradeTarget): PrintLog(LogLevel.INFO, f"交易启用: {target.stock_code} - {target.stock_name}") @@ -147,33 +148,9 @@ class TradeTargetUI(ttk.Frame): # 添加分隔符 ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10) - # 市场数据监听开关 - self.market_data_switch_var = tk.BooleanVar(value=False) - # self.market_data_switch = ttk.Checkbutton( - # toolbar_frame, - # text="📊 市场数据", - # variable=self.market_data_switch_var, - # command=self.toggle_market_data, - # width=12 - # ) - # self.market_data_switch.pack(side=tk.LEFT, padx=2) - # 表格区域 self.create_tables_area(main_frame) - def toggle_market_data(self): - """切换市场数据监听状态""" - print(f'市场数据监听开关') - self.market_data_enabled = self.market_data_switch_var.get() - if self.market_data_enabled: - eBus.event_bus.publish(eBus.ActionEnableMarketData, True) - # 同步开启UI刷新线程 - self.start_ui_refresh() - else: - eBus.event_bus.publish(eBus.ActionDisableMarketData, True) - # 同步关闭UI刷新线程 - self.stop_ui_refresh() - def start_ui_refresh(self): """启动UI刷新线程""" if not self.refresh_thread_running: @@ -333,7 +310,7 @@ class TradeTargetUI(ttk.Frame): if result: # 发布事件通知主控制器添加标的 - eBus.event_bus.publish(eBus.ActionEventAddTradeTarget, stock_code) + eBus.event_bus.publish(ActionEventAddTradeTarget, stock_code) PrintLog(LogLevel.INFO, f"已发送添加请求: {stock_code} - {stock_name}") def get_status_indicator(self, target: SFGridTradeTarget) -> str: @@ -432,12 +409,12 @@ class TradeTargetUI(ttk.Frame): if result: target.enabled = True # type: ignore - eBus.event_bus.publish(eBus.ActionEventEnableTrade, target.get_id()) + eBus.event_bus.publish(ActionEventEnableTrade, target.get_id()) # self.add_log("INFO", f"已启动交易: {target.stock_code} - {target.stock_name}") # messagebox.showinfo("启动成功", f"已启动 {target.stock_code} ({target.stock_name}) 的交易") def on_trade_enabled(self, target: SFGridTradeTarget): - eBus.event_bus.publish(eBus.ActionEventEnableTrade, target) + eBus.event_bus.publish(ActionEventEnableTrade, target) def pause_selected_trade(self): """暂停选中的交易""" @@ -458,7 +435,7 @@ class TradeTargetUI(ttk.Frame): if result: target.enabled = False # type: ignore - eBus.event_bus.publish(eBus.ActionEventDisableTrade, target.get_id()) + eBus.event_bus.publish(ActionEventDisableTrade, target.get_id()) # self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}") # messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易") @@ -479,7 +456,7 @@ class TradeTargetUI(ttk.Frame): if result: # 通过事件总线发出删除动作 - eBus.event_bus.publish(eBus.ActionEventDeleteTradeTarget, target.get_id()) + eBus.event_bus.publish(ActionEventDeleteTradeTarget, target) PrintLog(LogLevel.INFO, f"已发送删除请求: {target.stock_code} - {target.stock_name}") def add_trade_target(self): @@ -524,7 +501,7 @@ class TradeTargetUI(ttk.Frame): return # 发布事件通知主控制器添加标的 - eBus.event_bus.publish(eBus.ActionEventAddTradeTarget, stock_code) + eBus.event_bus.publish(ActionEventAddTradeTarget, stock_code) add_window.destroy() def cancel_add(): @@ -540,7 +517,6 @@ class TradeTargetUI(ttk.Frame): PrintLog(LogLevel.INFO, "点击添加交易标的按钮") - def refresh_table(self): """刷新表格数据""" # 保存当前选中的项 @@ -1039,7 +1015,7 @@ class TradeTargetUI(ttk.Frame): # 发布网格修正事件,传递GridFixData对象 grid_fix_data = GridFixData(new_grid_index, target) - eBus.event_bus.publish(eBus.ActionEventGridFix, grid_fix_data) + eBus.event_bus.publish(ActionEventGridFix, grid_fix_data) # 关闭窗口 window.destroy() diff --git a/core/util.py b/core/util.py index 5811fac..27addb4 100644 --- a/core/util.py +++ b/core/util.py @@ -37,13 +37,6 @@ def is_trading_time(): return False -def getInstrumentName(stock_code): - # print(f"getInstrumentName: 获取标的名称 {stock_code}") - detail = xtdata.get_instrument_detail(stock_code, False) - if detail is None: - return "UnNamed" - return detail['InstrumentName'] - def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount): volume = 0