From 0262bfc71ba86441daf75a1bf6807e5996e694ae Mon Sep 17 00:00:00 2001 From: "GDP\\solonot" Date: Wed, 19 Nov 2025 10:29:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=A2=84=E4=B8=8B=E5=8D=95?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/qmt.py | 3 -- core/sfgrid/sfgrid_strategy.py | 93 ++++++++++++++++++++-------------- core/sfgrid/sfgrid_ui.py | 6 +-- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/core/qmt.py b/core/qmt.py index 15e1a29..6814d91 100644 --- a/core/qmt.py +++ b/core/qmt.py @@ -119,19 +119,16 @@ class QmtV(XtQuantTraderCallback): # ====== 市场回调方法 -- 以下方法由XtQuantData调用 ====== def onDataUpdate(self, data): # 收集所有市场数据用于市场监控 - PrintLog(LogLevel.INFO, f'- [市场数据更新] {len(data)}') eBus.event_bus.publish(eBus.MarketDataUpdate, data) now = time.time() if now - self.lastMarketDataUpdateTimestamp < 5: self.isMarketActive = True - PrintLog(LogLevel.INFO, f'- [市场状态变更] 市场已 Active') # 市场已 inactive self.lastMarketDataUpdateTimestamp = now def marketStatusNotifier(self): # 市场状态通知器 tmpMarketStatus = False while True: - PrintLog(LogLevel.INFO, f'- [市场状态检查器] {self.isMarketActive}') tmpTime = time.time() time.sleep(10) if tmpMarketStatus != self.isMarketActive and tmpTime - self.lastMarketDataUpdateTimestamp < 5: diff --git a/core/sfgrid/sfgrid_strategy.py b/core/sfgrid/sfgrid_strategy.py index bc92a6f..7608bb3 100644 --- a/core/sfgrid/sfgrid_strategy.py +++ b/core/sfgrid/sfgrid_strategy.py @@ -24,8 +24,16 @@ class SFGridStrategy: self.todayDownStopPrice=qmtv.dailyDownStop(tradeTarget.stock_code) # type: ignore PrintLog(LogLevel.INFO, f'|- 标的{tradeTarget.targetName()}初始化: 停涨价 {self.todayUpStopPrice}, 停跌价 {self.todayDownStopPrice}') self.orderGrid = {} # grid index, order_seq | order_id + self.loadExistOrders() self.enabledTrading(tradeTarget.enabled) # type: ignore self.dataUpdateLock = threading.Lock() + + def loadExistOrders(self): + orders = qmtv.queryPendingOrder(self.tradeTarget.stock_code, self.getName()) # type: ignore + for order in orders: + gridIdx = int(order.order_remark.split(',')[1]) + self.orderGrid[gridIdx] = order.order_id + PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 加载现有订单, grid-{gridIdx} order_id:{self.orderGrid[gridIdx]}') def onMarketActiveSwitch(self, isActive: bool): if isActive and self.tradeTarget.enabled: @@ -48,39 +56,50 @@ class SFGridStrategy: OrderTypeInit, # remark # type: ignore self.getName(), # strategy_name ) - self.orderGrid[xtconstant.STOCK_BUY] = tmpOrderSeq # seq + self.orderGrid[1] = tmpOrderSeq # seq PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 建仓单,建仓价: {price:.3f}') else: currentIdx = self.tradeTarget.grid_index # type: ignore + orders = qmtv.queryPendingOrder(self.tradeTarget.stock_code, self.getName()) # type: ignore # 向上下一单,向下下一单 if currentIdx > 0: # 可以下空单 - sellPrice = self.tradeTarget.getPriceGrid()[currentIdx - 1] - tmpOrderSeq = qmtv.orderAsync( - str(self.tradeTarget.stock_code), - self.tradeTarget.grid_volume, - xtconstant.STOCK_SELL, - sellPrice, - xtconstant.FIX_PRICE, - OrderTypeSell, # remark # type: ignore - self.getName(), # strategy_name - ) - self.orderGrid[xtconstant.STOCK_SELL] = tmpOrderSeq # seq - PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 下空单,价格: {sellPrice:.3f}') + sellIdx = currentIdx - 1 + sellPrice = self.tradeTarget.getPriceGrid()[sellIdx] + remark = f'{OrderTypeSell},{sellIdx}' + if len([order for order in orders if order.order_type == xtconstant.STOCK_SELL and order.price == sellPrice]) == 0: + # 不存在策略内同价位订单,下单 + tmpOrderSeq = qmtv.orderAsync( + str(self.tradeTarget.stock_code), + self.tradeTarget.grid_volume, + xtconstant.STOCK_SELL, + sellPrice, + xtconstant.FIX_PRICE, + remark, # remark # type: ignore + self.getName(), # strategy_name + ) + self.orderGrid[sellIdx] = tmpOrderSeq # seq + PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 下空单,价格: {sellPrice:.3f}') + else: + PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 已存在同价位空单,跳过下单') if currentIdx < len(self.tradeTarget.getPriceGrid()) - 1: # 可以下多单 - buyPrice = self.tradeTarget.getPriceGrid()[currentIdx + 1] - tmpOrderSeq = qmtv.orderAsync( + buyIdx = currentIdx + 1 + buyPrice = self.tradeTarget.getPriceGrid()[buyIdx] + remark = f'{OrderTypeBuy},{buyIdx}' + if len([order for order in orders if order.order_type == xtconstant.STOCK_BUY and order.price == buyPrice]) == 0: + tmpOrderSeq = qmtv.orderAsync( str(self.tradeTarget.stock_code), self.tradeTarget.grid_volume, xtconstant.STOCK_BUY, buyPrice, xtconstant.FIX_PRICE, - OrderTypeBuy, # remark # type: ignore + remark, # remark # type: ignore self.getName(), # strategy_name ) - self.orderGrid[xtconstant.STOCK_BUY] = tmpOrderSeq # seq - PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 下多单,价格: {buyPrice:.3f}') - + self.orderGrid[buyIdx] = tmpOrderSeq # seq + PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 下多单,价格: {buyPrice:.3f}') + else: + PrintLog(LogLevel.INFO, f'|- 标的[{self.tradeTarget.targetName()}] 初始化: 已存在同价位多单,跳过下单') def deleteTradeTarget(self, tradeTarget:model.SFGridTradeTarget): PrintLog(LogLevel.INFO, f'|- 标的{tradeTarget.targetName()}信息删除: START') @@ -96,18 +115,18 @@ class SFGridStrategy: self.tradeTarget.enabled = enabled # type: ignore if enabled: - print(f" |- 标的{self.tradeTarget.targetName()}交易启动, 持仓量:{self.tradeTarget.current_position}") + PrintLog(LogLevel.INFO, f" |- 标的{self.tradeTarget.targetName()}交易启动, 持仓量:{self.tradeTarget.current_position}") if self.tradeTarget.status == 0: # 未建仓 - print(f" |- 标的{self.tradeTarget.targetName()}初始状态, 设置网格序号 1,") + PrintLog(LogLevel.INFO, f" |- 标的{self.tradeTarget.targetName()}初始状态, 设置网格序号 1,") self.tradeTarget.grid_index = 1 # pyright: ignore[reportAttributeAccessIssue] else: # 已建仓 # 交易阶段,检查仓位,检查现有订单 - print(f" |- 标的{self.tradeTarget.targetName()}已有仓位或非初始状态 无需建初始仓 当前仓位: {self.tradeTarget.current_position} 状态: {self.tradeTarget.status}") + PrintLog(LogLevel.INFO, f" |- 标的{self.tradeTarget.targetName()}已有仓位或非初始状态 无需建初始仓 当前仓位: {self.tradeTarget.current_position} 状态: {self.tradeTarget.status}") minRequirePosition:int = self.tradeTarget.grid_volume * int(self.tradeTarget.grid_index) # type: ignore if minRequirePosition <= int(self.tradeTarget.current_position): # type: ignore - print(f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') + PrintLog(LogLevel.INFO, f' |- 仓位检查: 持仓需求充足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}') else: - print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}, 交易启动失败') + PrintLog(LogLevel.INFO, f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}, 交易启动失败') self.tradeTarget.enabled = False # type: ignore self.refreshGridOrder() else: @@ -128,11 +147,10 @@ class SFGridStrategy: self.dataUpdateLock.acquire() try: if response.strategy_name == self.getName() and response.seq == self.tradeTarget.current_order_no: - print(f"委托创建通知 onOrderCreateAsync[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {response.order_id}") - for gridIdx, orderNo in self.orderGrid.items(): - if orderNo == response.seq: - self.orderGrid[gridIdx] = response.order_id - break + PrintLog(LogLevel.INFO, f"委托创建通知 onOrderCreateAsync[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {response.order_id}") + idx = response.order_remark.split(',')[1] + self.orderGrid[idx] = response.order_id + PrintLog(LogLevel.INFO, f"委托创建通知 onOrderCreateAsync 更新 grid-{idx} seq:{response.seq} -> order_id:{response.order_id}") except Exception as e: PrintLog(LogLevel.ERROR, f"|- 委托创建通知 onOrderCreateAsync[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {response.order_id} - {str(e)}") finally: @@ -159,24 +177,23 @@ class SFGridStrategy: if tmpOrderNo == trade.order_id: if idx > self.tradeTarget.grid_index: type = "下移一格" + self.tradeTarget.grid_index +=1 elif idx < self.tradeTarget.grid_index: type = "上移一格" + self.tradeTarget.grid_index -= 1 elif idx == self.tradeTarget.grid_index: type = "保持格, 理论上不应该输出" - self.tradeTarget.grid_index = idx + self.saveProxy() break PrintLog(LogLevel.INFO, f'|- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} - 原网格位置 {oriIdx}, 现网格位置 {self.tradeTarget.grid_index}') - self.saveProxy() - self.printTradeReport(trade, type) + + PrintLog(LogLevel.INFO, f"|- 成交报告[{self.tradeTarget.targetName()}] : ====================================") + PrintLog(LogLevel.INFO, f"|- 标的[{self.tradeTarget.targetName()}] {type}-单号{self.tradeTarget.current_order_no}已成交 ") + PrintLog(LogLevel.INFO, f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') + PrintLog(LogLevel.INFO, f' 手续费 : {trade.commission:.3f}') self.refreshGridOrder() # 更新网格订单 finally: self.dataUpdateLock.release() - - def printTradeReport(self, trade:XtTrade, type:str): - PrintLog(LogLevel.INFO, f"|- 成交报告[{self.tradeTarget.targetName()}] : ====================================") - PrintLog(LogLevel.INFO, f"|- 标的[{self.tradeTarget.targetName()}] {type}-单号{self.tradeTarget.current_order_no}已成交 ") - PrintLog(LogLevel.INFO, f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') - PrintLog(LogLevel.INFO, f' 手续费 : {trade.commission:.3f}') def getName(self): diff --git a/core/sfgrid/sfgrid_ui.py b/core/sfgrid/sfgrid_ui.py index 0e5fc97..912fb79 100644 --- a/core/sfgrid/sfgrid_ui.py +++ b/core/sfgrid/sfgrid_ui.py @@ -57,10 +57,10 @@ class TradeTargetUI(ttk.Frame): if stock_code in self.stockCodeIdMap: id:int = self.stockCodeIdMap[stock_code] tradeTarget = self.tradeTargetData[id] - timeStr = datetime.fromtimestamp(tickData['time']/1000) - PrintLog(LogLevel.INFO, f'|- 市价更新[{tradeTarget.targetName()}] - {timeStr.strftime("%H:%M:%S")} 市场数据更新======================={id}') + # timeStr = datetime.fromtimestamp(tickData['time']/1000) lastPrice = float("{:.3f}".format(tickData['lastPrice'])) tradeTarget.market_price = lastPrice # type: ignore + # PrintLog(LogLevel.INFO, f'|- 市价更新[{tradeTarget.targetName()}] - {timeStr.strftime("%H:%M:%S")} 市价更新: {lastPrice}======================{id}') self.updateTradeTarget(tradeTarget, False) # 市价更新 else: # 非目标交易,发布市场数据更新事件用于市场监控 @@ -151,7 +151,7 @@ class TradeTargetUI(ttk.Frame): while True: self.after(0, self.refresh_table) self.after(0, self.populate_market_table) - time.sleep(0.2) # 每0.5秒刷新一次 + time.sleep(0.5) # 每0.5秒刷新一次 def create_tables_area(self, parent):