From a18c7be7ebad92e0c85c1ca7d45d2b352d2a2b80 Mon Sep 17 00:00:00 2001 From: "GDP\\solonot" Date: Fri, 14 Nov 2025 11:45:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B5=8B=E8=AF=95=E4=B8=8E?= =?UTF-8?q?=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/eventbus.py | 2 + core/qmt.py | 6 +- core/sfgrid/sfgrid_strategy.py | 150 ++++++++++++++++++--------------- core/sfgrid/sfgrid_ui.py | 75 +++++------------ core/util.py | 28 +----- 5 files changed, 108 insertions(+), 153 deletions(-) diff --git a/core/eventbus.py b/core/eventbus.py index 8d25158..7c5a498 100644 --- a/core/eventbus.py +++ b/core/eventbus.py @@ -5,6 +5,8 @@ ActionEnableMarketData = "enable_market_data" ActionDisableMarketData = "disable_market_data" MarketDataEnabled = "market_data_enabled" MarketDataDisabled = "market_data_disabled" +MarketOrderCreated = "market_order_created" +MarketOrderTraded = "market_order_traded" # Pring Log EventPrintLog = "print_log" diff --git a/core/qmt.py b/core/qmt.py index 5cec9b1..fa95008 100644 --- a/core/qmt.py +++ b/core/qmt.py @@ -165,7 +165,7 @@ class QmtV(XtQuantTraderCallback): :param order: XtOrder对象 :return: """ - pass + print(f"委托回调 on_stock_order 投资备注 {order.strategy_name} {order.order_remark}") # 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] @@ -183,7 +183,7 @@ class QmtV(XtQuantTraderCallback): :param trade: XtTrade对象 :return: """ - print(f"委托回调 投资备注 {trade.stock_code}-{trade.instrument_name} {trade.strategy_name} 不匹配 {trade.order_remark}") + eBus.event_bus.publish(eBus.MarketOrderTraded, trade) # stockCode = trade.stock_code # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] # # 如果存在对应的StockTradeController,则调用其onDataUpdate方法 @@ -193,7 +193,7 @@ class QmtV(XtQuantTraderCallback): # print(f"委托回调 投资备注 {trade.strategy_name} 不匹配 {ctrl.getName()}") def on_order_stock_async_response(self, response:XtOrderResponse): - print(f"委托回调 投资备注 {response.error_msg}{response.strategy_name} {response.order_remark}") + print(f"委托回调 on_order_stock_async_response 投资备注 {response.error_msg}{response.strategy_name} {response.order_remark}") # stockCode = response.order_remark # ctrl:SFGridStrategy = self.stock_trade_ctrl[stockCode] diff --git a/core/sfgrid/sfgrid_strategy.py b/core/sfgrid/sfgrid_strategy.py index f9b110e..341a5c6 100644 --- a/core/sfgrid/sfgrid_strategy.py +++ b/core/sfgrid/sfgrid_strategy.py @@ -1,15 +1,16 @@ +from core.logger import LogLevel, PrintLog 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 event_bus from core.constants import OrderTypeBuy, OrderTypeInit, OrderTypeSell -from core.util import queryPendingOrder, is_trading_time +from core.util import is_trading_time from xtquant import xtconstant -from xtquant.xttype import XtOrder, XtTrade -import config +from xtquant.xttype import XtOrder, XtOrderResponse, XtTrade import threading +import core.eventbus as eBus class SFGridStrategy: @@ -17,18 +18,21 @@ class SFGridStrategy: def __init__(self, tradeTarget: model.SFGridTradeTarget): self.tradeTarget:model.SFGridTradeTarget = tradeTarget self.enabledTrading(tradeTarget.enabled) # type: ignore + event_bus.subscribe(eBus.MarketOrderTraded, self.onOrderTrade) + self.refreshPlanPrice() self.dataUpdateLock = threading.Lock() def updateTradeTarget(self, inTradeTarget:model.SFGridTradeTarget): - print(f'|- 标的{self.tradeTarget.targetName()}信息更新: START') + PrintLog(LogLevel.INFO, f'|- 标的{self.tradeTarget.targetName()}信息更新: START') self.dataUpdateLock.acquire() - print(f'|- 标的{self.tradeTarget.targetName()}信息更新: LOCKED') + PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: LOCKED') try: self.tradeTarget = inTradeTarget finally: - print(f'|- 标的{self.tradeTarget.targetName()}信息更新: UNLOCKED') + PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: UNLOCKED') self.dataUpdateLock.release() - print(f'|- 标的{self.tradeTarget.targetName()}信息更新: END') + self.refreshPlanPrice() + PrintLog(LogLevel.INFO ,f'|- 标的{self.tradeTarget.targetName()}信息更新: END') def enabledTrading(self, enabled: bool) -> model.SFGridTradeTarget: self.tradeTarget.enabled = enabled # type: ignore @@ -49,6 +53,10 @@ class SFGridStrategy: print(f' |- 仓位检查: 持仓需求不足, (gridVolume*gridIndex)={minRequirePosition}, 当前持仓:{self.tradeTarget.current_position}, 交易启动失败') self.tradeTarget.enabled = False # type: ignore else: + orders = qmtv.queryPendingOrder(self.tradeTarget.stock_code, self.getName()) # type: ignore + for order in orders: + qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id) + print(f' |- 取消未成交订单 {len(orders)}') print(f" |- 标的{self.tradeTarget.targetName()}交易监控暂停") self.saveProxy() @@ -63,12 +71,12 @@ class SFGridStrategy: if not is_trading_time(): return - if not self.tradeTarget.enabled: # 未建仓,自动交易暂停 + if not self.tradeTarget.enabled: # 策略中止,自动交易暂停 return - print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START') + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START') self.dataUpdateLock.acquire() - print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED') + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED') try: lastPrice = inTradeTarget.market_price @@ -77,27 +85,29 @@ class SFGridStrategy: index: int = self.tradeTarget.grid_index # pyright: ignore[reportAssignmentType] orderRemark= "" - gridBasePrice = -1 if index>=len(inTradeTarget.getPriceGrid()) or index < 0 else inTradeTarget.getPriceGrid()[int(index)] # pyright: ignore[reportArgumentType] - - if self.tradeTarget.enabled and self.tradeTarget.status == 0 and lastPrice <= inTradeTarget.getPriceGrid()[1]: # 已启用,未建仓,建仓 + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 策略运行状态{self.tradeTarget.enabled}, 初始化状态{self.tradeTarget.status}') + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 当前价{lastPrice}') + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 网格索引{index}, 网格价格{self.tradeTarget.getPriceGrid()[index]}') + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 计划买入价{self.tradeTarget.plan_buy_price}, 计划卖出价{self.tradeTarget.plan_sell_price}') + if self.tradeTarget.enabled and self.tradeTarget.status == 0 and lastPrice <= inTradeTarget.getPriceGrid()[1]: # 已启用,未建仓,准备建仓单信息 + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备建仓单信息') orderPrice = inTradeTarget.getPriceGrid()[index] orderType = xtconstant.STOCK_BUY orderRemark = OrderTypeInit - - if self.tradeTarget.enabled and self.tradeTarget.status == 1: # 已启用,已建仓,网格单 - lowPrice = -1 if index+1>=len(inTradeTarget.getPriceGrid()) else inTradeTarget.getPriceGrid()[int(index) + 1] # pyright: ignore[reportArgumentType] - highPrice = inTradeTarget.getPriceGrid()[index - 1] + elif self.tradeTarget.enabled and self.tradeTarget.status == 1 and self.tradeTarget.plan_buy_price > 0 and lastPrice <= self.tradeTarget.plan_buy_price: + # 已启用,已建仓,准备网格多单信息 + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备网格多单信息') + orderPrice = self.tradeTarget.plan_buy_price # type: ignore + orderType = xtconstant.STOCK_BUY + orderRemark = OrderTypeBuy + elif self.tradeTarget.enabled and self.tradeTarget.status == 1 and self.tradeTarget.plan_buy_price > 0 and lastPrice >= self.tradeTarget.plan_sell_price: + # 已启用,已建仓,准备网格空单信息 + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 准备网格空单信息') + orderPrice = self.tradeTarget.plan_sell_price # type: ignore + orderType = xtconstant.STOCK_SELL + orderRemark = OrderTypeSell - if lastPrice <= lowPrice: # 下下方多单 - orderPrice = lowPrice - orderType = xtconstant.STOCK_BUY - orderRemark = OrderTypeBuy - - elif lastPrice >= highPrice: # 下上方空单 - orderPrice = highPrice - orderType = xtconstant.STOCK_SELL - orderRemark = OrderTypeSell - + PrintLog(LogLevel.INFO, f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 下单信息: {orderType}, {orderPrice}, {orderRemark}') if orderType != -1: orders = qmtv.queryPendingOrder(str(self.tradeTarget.stock_code), self.getName()) if len([order for order in orders if order.order_type == orderType and order.price == orderPrice]) > 0: @@ -121,94 +131,94 @@ class SFGridStrategy: orderTypeName = "空单" elif orderRemark == OrderTypeInit: orderTypeName = "建仓单" - print(f' |- {orderTypeName}委托, 单号 {self.tradeTarget.current_order_no}, 网格基准价 {gridBasePrice}, 下单价 {orderPrice}, 下单量 {self.tradeTarget.grid_volume}') + gridBasePrice = -1 if index>=len(inTradeTarget.getPriceGrid()) or index < 0 else inTradeTarget.getPriceGrid()[int(index)] # pyright: ignore[reportArgumentType] + PrintLog(LogLevel.INFO, f' |- {orderTypeName}委托, 单号 {self.tradeTarget.current_order_no}, 网格基准价 {gridBasePrice}, 下单价 {orderPrice}, 下单量 {self.tradeTarget.grid_volume}') finally: print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - release lock') self.saveProxy() self.dataUpdateLock.release() print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - END') + def onOrderCreate(self, order:XtOrder): + if order.strategy_name == self.getName(): + print(f"委托创建通知 onOrderCreate[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {order.order_id}") + self.tradeTarget.current_order_no = order.order_id + self.saveProxy() - # def onAsyncOrderResponse(self, order:XtOrder): - # print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:START') - # self.dataUpdateLock.acquire() - # print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:LOCKED') - # try: - # if order.strategy_name == self.getName(): - # self.tradeTarget.current_order_no = order.order_id - # self.tradeTarget.current_order_type = order.order_remark - # self.saveProxy() - # else: - # print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]: 不在策略监控范围内{order.strategy_name}') - # finally: - # print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:release lock') - # self.dataUpdateLock.release() - # print(f' |- 委托回调[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{order.order_id}]:END') + def onOrderCreateAsync(self, response:XtOrderResponse): + if response.strategy_name == self.getName(): + print(f"委托创建通知 onOrderCreateAsync[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]: {response.order_id}") + self.tradeTarget.current_order_no = response.order_id + self.saveProxy() def onOrderTrade(self, trade:XtTrade): + if trade.strategy_name != self.getName(): + print(f"委托回调 投资备注 {trade.stock_code}-{trade.instrument_name} {trade.strategy_name} 不匹配 {trade.order_remark}") + return print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:START, {trade.order_id}') self.dataUpdateLock.acquire() print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:LOCKED') try: - if not trade.strategy_name == self.getName(): - print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]: 不在策略监控范围内{trade.strategy_name}') - return + type:str = "" if self.tradeTarget.status == 0 and trade.order_id == self.tradeTarget.current_order_no and trade.order_remark == constants.OrderTypeInit: # 此时为建仓成交 self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # 当前持仓数,账户原有持仓不在策略范围内 # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.grid_index = 1 # type: ignore - self.tradeTarget.plan_buy_price = float(config.grid_price[2]) # type: ignore - self.tradeTarget.plan_sell_price = float(config.grid_price[0]) # type: ignore self.tradeTarget.status = 1 # type: ignore - self.saveProxy() - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 建初始仓订单ID: {self.tradeTarget.current_order_no}已成交 ") - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') - print(f' 当前持仓: {self.tradeTarget.current_position}') - print(f' 网格坐标: {self.tradeTarget.grid_index}') + type = "建初始仓" elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_SELL: # type: ignore # 上涨一格:此时空单成交 self.tradeTarget.current_position = int(self.tradeTarget.current_position) - trade.traded_volume # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) - 1 # type: ignore - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 上涨 卖单已成交 订单ID: {self.tradeTarget.current_order_no} Price: {config.grid_price[int(self.tradeTarget.grid_index)]} Volume: {config.grid_volume} 手续费: {trade.commission}\n") # type: ignore - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') - print(f' 当前持仓: {self.tradeTarget.current_position}') - print(f' 网格坐标: {self.tradeTarget.grid_index}') + type = "上涨一格" elif trade.order_id == self.tradeTarget.current_order_no and self.tradeTarget.status == 1 and trade.order_type == xtconstant.STOCK_BUY: # type: ignore # 下跌一格:此时多单成交 self.tradeTarget.current_position = int(self.tradeTarget.current_position) + trade.traded_volume # type: ignore self.tradeTarget.last_trade_price = float(trade.traded_price) # type: ignore self.tradeTarget.grid_index = int(self.tradeTarget.grid_index) + 1 # type: ignore - print(f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} 下跌 买单已成交 订单ID: {self.tradeTarget.current_order_no} Price: {trade.traded_price} Volume: {config.grid_volume} 手续费: {trade.commission}") - print(f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') - print(f' 当前持仓: {self.tradeTarget.current_position}') - print(f' 网格坐标: {self.tradeTarget.grid_index}') + type = "下跌一格" else: - # 打印订单信息和订单状态 - print(f'|- 非策略内部订单,或订单状态不满足监控条件 {trade.order_id} {trade.stock_code}-{trade.instrument_name} {trade.commission}') - finally: + type = "其他异常状态" + self.refreshPlanPrice() + self.printTradeReport(trade, type) + finally: print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:release lock') self.dataUpdateLock.release() print(f' |- 委托成交通知[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}-{trade.order_id}]:END') - def refreshPlanPrice(self): - if self.tradeTarget.status == 0: - self.tradeTarget.grid_index = 1 # type: ignore + def printTradeReport(self, trade:XtTrade, type:str): + PrintLog(LogLevel.INFO, f"打印交易报告[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}]:START") + PrintLog(LogLevel.INFO, f"|- 标的{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name} {type}: {self.tradeTarget.current_order_no}已成交 ") + PrintLog(LogLevel.INFO, f' 成交价: {trade.traded_price} 成交量: {trade.traded_volume}') + PrintLog(LogLevel.INFO, f' 当前持仓: {self.tradeTarget.current_position}') + PrintLog(LogLevel.INFO, f' 网格坐标: {self.tradeTarget.grid_index}') + + + def refreshPlanPrice(self): + buyIdx = 0 + sellIdx= 0 + if self.tradeTarget.status == 0: # 未建仓 + self.tradeTarget.grid_index = 0 # type: ignore + buyIdx = 1 + sellIdx = 0 + else: + buyIdx: int = self.tradeTarget.grid_index + 1 # pyright: ignore[reportAssignmentType] + sellIdx: int = self.tradeTarget.grid_index - 1 - buyIdx: int = self.tradeTarget.grid_index + 1 # pyright: ignore[reportAssignmentType] - sellIdx: int = self.tradeTarget.grid_index - 1 if self.tradeTarget.grid_index > 0: # 可以下空单 self.tradeTarget.plan_sell_price = float(self.tradeTarget.getPriceGrid()[sellIdx]) # pyright: ignore[reportAttributeAccessIssue] else: self.tradeTarget.plan_sell_price = -1.0 # type: ignore + if self.tradeTarget.grid_index < len(self.tradeTarget.getPriceGrid()) - 1: self.tradeTarget.plan_buy_price = float(self.tradeTarget.getPriceGrid()[buyIdx]) # pyright: ignore[reportAttributeAccessIssue] else: self.tradeTarget.plan_buy_price = -1.0 # pyright: ignore[reportAttributeAccessIssue] - self.saveProxy() + event_bus.publish(EventTradeTargetUpdate, self.tradeTarget) def getName(self): return "SFGRID" diff --git a/core/sfgrid/sfgrid_ui.py b/core/sfgrid/sfgrid_ui.py index 89b7a5c..c02dffa 100644 --- a/core/sfgrid/sfgrid_ui.py +++ b/core/sfgrid/sfgrid_ui.py @@ -1,7 +1,7 @@ from typing import Any import tkinter as tk -from tkinter import ttk, messagebox, filedialog +from tkinter import ttk, messagebox from datetime import datetime import threading import time @@ -10,9 +10,6 @@ import core.eventbus as eBus from core.logger import LogLevel, PrintLog from core.sfgrid import bus_events 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_strategy import SFGridStrategy @@ -41,20 +38,9 @@ class TradeTargetUI(ttk.Frame): def init_trade_target_pool(self): results = SFGridTradeTarget.select() for temp in results: - tradeTarget :SFGridTradeTarget = temp - id = tradeTarget.get_id() - - status = "新建" if tradeTarget.status == 0 else "已建初始仓" + tradeTarget:SFGridTradeTarget = temp tradeTarget.current_position = qmtv.getStockPosition(tradeTarget.stock_code) # type: ignore - # 计算计划交易价格 - if tradeTarget.grid_index > 0: - tradeTarget.plan_buy_price = tradeTarget.getPriceGrid()[tradeTarget.grid_index - 1] # type: ignore - if tradeTarget.grid_index < len(tradeTarget.getPriceGrid()) - 1: - tradeTarget.plan_sell_price = tradeTarget.getPriceGrid()[tradeTarget.grid_index + 1] # type: ignore - tradeTarget.save() - PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {tradeTarget.stock_code}-{tradeTarget.stock_name} 当前持仓: {qmtv.getStockPosition(tradeTarget.stock_code)} 网格索引: {tradeTarget.grid_index} 基准价格 {tradeTarget.getPriceGrid()[tradeTarget.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if tradeTarget.enabled else '交易已停止'}') # type: ignore - PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {tradeTarget.stock_code}-{tradeTarget.stock_name}: {tradeTarget.plan_buy_price} {tradeTarget.plan_sell_price}') # type: ignore - self.updateTradeTarget(tradeTarget) + self.updateTradeTarget(tradeTarget, True) PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的') @@ -64,18 +50,16 @@ class TradeTargetUI(ttk.Frame): for stock_code, tickData in data.items(): if stock_code in self.stockCodeIdMap: id:int = self.stockCodeIdMap[stock_code] - PrintLog(LogLevel.INFO, f'股票代码: {stock_code} in trade pool, 市场数据更新 {tickData["lastPrice"]}') + PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {stock_code} in trade pool, 市场数据更新 {tickData["lastPrice"]}') tradeTarget = self.tradeTargetData[id] lastPrice = float("{:.3f}".format(tickData['lastPrice'])) tradeTarget.market_price = lastPrice # type: ignore - self.updateTradeTarget(tradeTarget) - stock_controller = self.strategy_ctrl[id] - stock_controller.onDataUpdate(tradeTarget) + self.updateTradeTarget(tradeTarget, False) else: # 非目标交易,发布市场数据更新事件用于市场监控 lastPrice = tickData['lastPrice'] if lastPrice == 10 or stock_code in self.listening_stock: - PrintLog(LogLevel.INFO, f'股票代码: {stock_code} 监听中, 市场数据更新 {tickData["lastPrice"]}') + # PrintLog(LogLevel.INFO, f'股票代码: {stock_code} 监听中, 市场数据更新 {tickData["lastPrice"]}') # 发布市场数据更新事件用于市场监控 market_target = SFGridTradeTarget() market_target.stock_code = stock_code @@ -94,11 +78,14 @@ class TradeTargetUI(ttk.Frame): # 来自策略的数据更新 def onStrategyUpdate(self, target: SFGridTradeTarget): - PrintLog(LogLevel.INFO, f'策略更新: {target.stock_code}-{target.stock_name}') - self.updateTradeTarget(target) + id = target.get_id() + self.tradeTargetData[id] = target - def updateTradeTarget(self, target: SFGridTradeTarget): + def updateTradeTarget(self, target: SFGridTradeTarget, save: bool = True): + if save: + target.save() + id = target.get_id() status = "新建" if target.status == 0 else "已建初始仓" PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {target.stock_code}-{target.stock_name} 当前持仓: {target.current_position} 网格索引: {target.grid_index} 基准价格 {target.getPriceGrid()[1]} 状态: {status} 启用交易线程: {'自动交易中' if target.enabled else '交易已停止'}') @@ -109,6 +96,8 @@ class TradeTargetUI(ttk.Frame): if id not in self.strategy_ctrl: self.stockCodeIdMap[target.stock_code] = id # type: ignore self.strategy_ctrl[id] = SFGridStrategy(target) # pyright: ignore[reportArgumentType] + else: + self.strategy_ctrl[id].updateTradeTarget(target) # UI CREATE def create_ui(self): @@ -132,8 +121,9 @@ class TradeTargetUI(ttk.Frame): command=self.btnHandlerStopSelectedTrade, width=12).pack(side=tk.LEFT, padx=2) ttk.Button(toolbar_frame, text="🛠 交易设置", command=self.btnHandlerTradeSettings, width=12).pack(side=tk.LEFT, padx=2) - ttk.Button(toolbar_frame, text="🛠 网格修正", - command=self.btnHandlerGridCorrect, width=12).pack(side=tk.LEFT, padx=2) + ttk.Button(toolbar_frame, text="🛠 网格修正(停用)", + # command=self.btnHandlerGridCorrect, + width=12).pack(side=tk.LEFT, padx=2) ttk.Button(toolbar_frame, text="▣ 实时监控", command=self.btnHandlerToggleMarketMonitor, width=12).pack(side=tk.RIGHT, padx=2) @@ -698,9 +688,10 @@ class TradeTargetUI(ttk.Frame): setattr(target, 'grid_volume', grid_volume) setattr(target, 'grid_upper_count', grid_upper_count) setattr(target, 'grid_lower_count', grid_lower_count) + setattr(target, 'status', 0) - # 保存到数据库 - target.save() + # 更新策略控制器 + self.updateTradeTarget(target, True) # 关闭窗口 config_window.destroy() @@ -940,26 +931,11 @@ class TradeTargetUI(ttk.Frame): current_order_type='', status=-1 ) - new_target.save() # 更新标的池 - self.updateTradeTarget(new_target) + self.updateTradeTarget(new_target, True) except Exception as e: PrintLog(LogLevel.ERROR, f'新增交易标的失败 {stock_code} {e}') - - # def update_trade_target_grid(self, data: GridFixData): - # """更新交易标的网格信息""" - # try: - # target = data.tradeTarget - # grid_index = data.grid_index - - # # 更新数据库中的网格索引 - # target.grid_index = grid_index - # target.save() - - # PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}") - # except Exception as e: - # PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}") # button handlers ============================================================================================= def btnHandlerGridCorrect(self): @@ -1045,16 +1021,9 @@ class TradeTargetUI(ttk.Frame): id = target.get_id() if id in self.strategy_ctrl: tradeController: SFGridStrategy = self.strategy_ctrl[target.get_id()] - tradeTarget = tradeController.enabledTrading(False) - orders = qmtv.queryPendingOrder(target.stock_code, tradeController.getName()) # type: ignore - for order in orders: - qmtv.xttrader.cancel_order_stock_async(qmtv.account, order.order_id) - print(f'取消未成交订单 {len(orders)}') - self.tradeTargetData[id] = tradeTarget + tradeController.enabledTrading(False) else: print(f"标的交易控制器不存在 {target.stock_code} {target.stock_name}\n") - # self.add_log("INFO", f"已暂停交易: {target.stock_code} - {target.stock_name}") - # messagebox.showinfo("暂停成功", f"已暂停 {target.stock_code} ({target.stock_name}) 的交易") def btnHandlerDelSelectedTradeTarget(self): """删除选中的交易标的""" diff --git a/core/util.py b/core/util.py index 27addb4..793e336 100644 --- a/core/util.py +++ b/core/util.py @@ -1,9 +1,5 @@ -import config -import xtquant.xtconstant as xtconstant -from xtquant import xtdata, xttrader -from xtquant.xttype import StockAccount, XtOrder, XtPosition - import datetime + def is_trading_time(): """ 判断当前时间是否在周一至周五的9:30~11:30或13:00~15:00时间段内 @@ -37,25 +33,3 @@ def is_trading_time(): return False - -def getStockPosition(stock_code: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount): - volume = 0 - positions = xt_trader.query_stock_positions(account) - if positions: - for temp in positions: - pos:XtPosition = temp - if pos.stock_code == stock_code: - volume = pos.volume - break - - return volume - -def minPosition(gridIndex:int): - return config.grid_volume * gridIndex - -def queryPendingOrder(stock_code:str, tag: str, xt_trader: xttrader.XtQuantTrader, account: StockAccount) -> list[XtOrder]: - if stock_code == None or tag == None: - return [] - orders = xt_trader.query_stock_orders(account) - result = [order for order in orders if order.order_status == xtconstant.ORDER_REPORTED and order.stock_code == stock_code and order.strategy_name == tag] - return result