diff --git a/config.py b/config.py index 92afdaf..b6fe98e 100644 --- a/config.py +++ b/config.py @@ -3,15 +3,10 @@ import configparser from pathlib import Path import sys -# miniQMTPath = r'D:\\Programs\\DTQMT_MN\\userdata_mini' # miniQMT软件的安装路径 miniQMTPath = r'D:\\Programs\\DTQMT\\userdata_mini' # miniQMT软件的安装路径 # miniQMTPath = '' -# grid_price = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 网格价格设置,从高到低 -grid_price:List[float] = [] # 网格价格设置,从高到低 -grid_volume:int = 100 # 每个网格的交易手数 account_no:str = '99082560' console_log = True -# account_no:str = '89009170' # 交易账号 def get_config_path() -> Path: """获取配置文件的正确路径(兼容开发环境和打包后的可执行文件)""" @@ -31,8 +26,6 @@ def create_default_config(): config = configparser.ConfigParser() config['config'] = { 'miniQMTPath': r'D:/Programs/QMT/userdata_mini', - 'grid_price': '11.0,10.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0', - 'grid_volume': '100', 'account_no': '00000000' } config_path = get_config_path() @@ -53,7 +46,4 @@ def initConfig(): config = configparser.ConfigParser() config.read(config_path, encoding='utf-8') miniQMTPath = config.get('config','miniQMTPath') - str_list = config.get('config','grid_price').split(',') - grid_price = [float(item) for item in str_list] - grid_volume = config.getint('config','grid_volume') account_no = config.get('config','account_no') diff --git a/core/main_ui.py b/core/main_ui.py index 987a338..d0670fe 100644 --- a/core/main_ui.py +++ b/core/main_ui.py @@ -1,8 +1,7 @@ import tkinter as tk from tkinter import ttk -from core.logger import LogLevel, PrintLog, LogData +from core.logger import LogLevel, PrintLog from core.sfgrid.sfgrid_ui import TradeTargetUI -from core.eventbus import event_bus, EventPrintLog class MainWindow: @@ -17,12 +16,9 @@ class MainWindow: self.strategy_frames = {} # 日志面板可见性标志 self.log_visible = False - # 创建界面 + print(f'创建界面') self.create_ui() - - # 订阅日志事件 - event_bus.subscribe(EventPrintLog, self.on_log_event) def create_ui(self): @@ -211,10 +207,6 @@ class MainWindow: result = messagebox.askyesno("确认退出", "确定要退出系统吗?") if result: self.root.destroy() - - def on_log_event(self, log_data: LogData): - """处理日志事件""" - self.add_log(log_data.level, log_data.message) def run(self): """运行程序""" diff --git a/core/qmt.py b/core/qmt.py index eb90423..7119736 100644 --- a/core/qmt.py +++ b/core/qmt.py @@ -130,6 +130,8 @@ class QmtV(XtQuantTraderCallback): # ========================================# def startMarketDataSubscription(self): self.subscriptionId = xtdata.subscribe_whole_quote(['SH', 'SZ'], self.onDataUpdate) + + PrintLog(LogLevel.INFO, f'- [市场数据订阅成功-{self.subscriptionId}]') def stopMarketDataSubscription(self): PrintLog(LogLevel.INFO, '- 停止市场数据订阅') diff --git a/core/sfgrid/bus_events.py b/core/sfgrid/bus_events.py index 1542033..c4c234e 100644 --- a/core/sfgrid/bus_events.py +++ b/core/sfgrid/bus_events.py @@ -4,8 +4,6 @@ ActionEventAddTradeTarget = "add_trade_target" ResultEventTradeTargetAdded = "trade_target_added" ActionEventDeleteTradeTarget = "delete_trade_target" ResultEventTradeTargetDeleted = "trade_target_deleted" -# 网格修正事件 -ActionEventGridFix = "grid_fix" # 定义事件处理函数 ActionEventEnableTrade = "enable_trade" diff --git a/core/sfgrid/constants.py b/core/sfgrid/constants.py new file mode 100644 index 0000000..0beab3b --- /dev/null +++ b/core/sfgrid/constants.py @@ -0,0 +1,2 @@ +GridTypePercentage = "Percentage" +GridTypeFixed = "PriceBreak" diff --git a/core/sfgrid/model.py b/core/sfgrid/model.py index 96824fc..9fb6dc7 100644 --- a/core/sfgrid/model.py +++ b/core/sfgrid/model.py @@ -19,8 +19,30 @@ class SFGridTradeTarget(BaseModel): status = IntegerField(default=0) # 0表示新标的,1表示已建初始仓,正常交易中 enabled = BooleanField(default=False) # 是否启动交易线程 + grid_start_price = FloatField(default=10.0) # 基线价格 + grid_size = FloatField(default=0.1) # 网格价位差 + grid_volume = IntegerField(default=100) # 网格交易量 + grid_upper_count = IntegerField(default=1) # 基线价格上方网格数 + grid_lower_count = IntegerField(default=10) # 基线价格下方网格数 + def targetName(self): return f'{self.stock_name}[{self.stock_code}]' + + def getPriceGrid(self) -> list: + self.priceGrid: list = [] + # 网格大小,数量 + if self.priceGrid is None or len(self.priceGrid) == 0: + for i in range(self.grid_upper_count): # type: ignore + upperPrice = self.grid_start_price + (self.grid_upper_count - i) * self.grid_size + self.priceGrid.append(upperPrice) + + self.priceGrid.append(self.grid_start_price) + + for i in range(self.grid_lower_count): # type: ignore 5 + lowerPrice = self.grid_start_price - (i + 1) * self.grid_size + self.priceGrid.append(lowerPrice) + + return self.priceGrid db.create_tables([SFGridTradeTarget]) \ No newline at end of file diff --git a/core/sfgrid/sfgrid_strategy.py b/core/sfgrid/sfgrid_strategy.py index 8cc8065..c48cd12 100644 --- a/core/sfgrid/sfgrid_strategy.py +++ b/core/sfgrid/sfgrid_strategy.py @@ -40,7 +40,7 @@ class SFGridStrategy: else: # 已建仓 # 交易阶段,检查仓位,检查现有订单 print(f" |- 标的{self.tradeTarget.targetName()}已有仓位或非初始状态 无需建初始仓 当前仓位: {self.tradeTarget.current_position} 状态: {self.tradeTarget.status}") - minRequirePosition:int = config.grid_volume * int(self.tradeTarget.grid_index) # type: ignore + 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}') else: @@ -74,16 +74,16 @@ class SFGridStrategy: index: int = self.tradeTarget.grid_index # pyright: ignore[reportAssignmentType] orderRemark= "" - gridBasePrice = -1 if index>=len(config.grid_price) or index < 0 else config.grid_price[int(index)] # pyright: ignore[reportArgumentType] + 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 <= config.grid_price[1]: # 已启用,未建仓,建仓 - orderPrice = config.grid_price[index] + 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(config.grid_price) else config.grid_price[int(index) + 1] # pyright: ignore[reportArgumentType] - highPrice = config.grid_price[index - 1] + lowPrice = -1 if index+1>=len(inTradeTarget.getPriceGrid()) else inTradeTarget.getPriceGrid()[int(index) + 1] # pyright: ignore[reportArgumentType] + highPrice = inTradeTarget.getPriceGrid()[index - 1] if lastPrice <= lowPrice: # 下下方多单 orderPrice = lowPrice @@ -196,11 +196,11 @@ class SFGridStrategy: 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(config.grid_price[sellIdx]) # pyright: ignore[reportAttributeAccessIssue] + 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(config.grid_price) - 1: - self.tradeTarget.plan_buy_price = float(config.grid_price[buyIdx]) # pyright: ignore[reportAttributeAccessIssue] + 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] else: diff --git a/core/sfgrid/sfgrid_ui.py b/core/sfgrid/sfgrid_ui.py index 66e4137..3975659 100644 --- a/core/sfgrid/sfgrid_ui.py +++ b/core/sfgrid/sfgrid_ui.py @@ -8,7 +8,7 @@ import time from core import constants 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.bus_events import ActionEventAddTradeTarget from core.sfgrid.model import SFGridTradeTarget import configparser import config @@ -47,7 +47,8 @@ class TradeTargetUI(ttk.Frame): if stock_code in self.stockCodeIdMap: id:int = self.stockCodeIdMap[stock_code] tradeTarget = self.tradeTargetData[id] - lastPrice = float("{:.3f}".format(tickData['lastPrice'])) + lastPrice = float("{:.3f}".format(tickData['lastPrice'])) + print(f'股票代码: {stock_code} {id}, 市场数据更新 {lastPrice}') tradeTarget.market_price = lastPrice # type: ignore self.updateTradeTarget(tradeTarget) stock_controller: SFGridStrategy = self.strategy_ctrl[id] @@ -85,7 +86,7 @@ class TradeTargetUI(ttk.Frame): for id, tradeTarget in self.tradeTargetData.items(): status = "新建" if tradeTarget.status == 0 else "已建初始仓" - PrintLog(LogLevel.INFO, f' [序号-{id}] 股票代码: {tradeTarget.stock_code}-{tradeTarget.stock_name} 当前持仓: {qmtv.getStockPosition(tradeTarget.stock_code)} 网格索引: {tradeTarget.grid_index} 基准价格 {config.grid_price[tradeTarget.grid_index]} 状态: {status} 启用交易线程: {'自动交易中' if tradeTarget.enabled else '交易已停止'}') # type: ignore + 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 tradeTarget.current_position = qmtv.getStockPosition(tradeTarget.stock_code) # type: ignore result = tradeTarget.save() @@ -143,10 +144,10 @@ class TradeTargetUI(ttk.Frame): command=self.pause_selected_trade, width=12).pack(side=tk.LEFT, padx=2) ttk.Button(toolbar_frame, text="➕ 添加标的", command=self.add_trade_target, width=12).pack(side=tk.LEFT, padx=2) + ttk.Button(toolbar_frame, text="🛠 网格配置", + command=self.grid_settings, width=12).pack(side=tk.LEFT, padx=2) ttk.Button(toolbar_frame, text="🗑 删除标的", command=self.delete_selected_trade, width=12).pack(side=tk.LEFT, padx=2) - ttk.Button(toolbar_frame, text="🛠 网格修正", - command=self.grid_correction, width=12).pack(side=tk.LEFT, padx=2) # 添加抽屉按钮到工具栏最右侧 self.toggle_market_monitor_btn = ttk.Button(toolbar_frame, text="◀▶", @@ -246,7 +247,7 @@ class TradeTargetUI(ttk.Frame): column_configs = { "时间": (50, tk.CENTER), "股票名称": (80, tk.CENTER), - "最新价格": (80, tk.CENTER) + "最新价格": (50, tk.CENTER) } for col in columns: @@ -303,7 +304,8 @@ class TradeTargetUI(ttk.Frame): values = [ time_str, data['stock_name']+f"{stock_code}", - f"{data['last_price']:.3f}" + f"{data['last_price']:.3f}", + stock_code ] self.market_table.insert('', tk.END, values=values) @@ -320,9 +322,10 @@ class TradeTargetUI(ttk.Frame): if selected: item = selected[0] values = self.market_table.item(item)['values'] - stock_code = values[1] - stock_name = values[2] - last_price = values[3] + print(values) + stock_name = values[1] + last_price = values[2] + stock_code = values[3] # 检查是否已在交易池中 is_in_trade_pool = any(target.stock_code == stock_code for target in self.tradeTargetData.values()) @@ -501,7 +504,7 @@ class TradeTargetUI(ttk.Frame): del self.tradeTargetData[id] del self.strategy_ctrl[id] - del self.stockCodeIdMap[str(target.stock_code)] + del self.stockCodeIdMap[target.stock_code] # type: ignore # 添加日志 PrintLog(LogLevel.INFO, f"交易标的已删除,ID: {id} {target.targetName()}") except Exception as e: @@ -898,7 +901,7 @@ class TradeTargetUI(ttk.Frame): ttk.Button(button_frame, text="💾 保存配置", command=save_settings, width=15).pack(side=tk.LEFT, padx=5) ttk.Button(button_frame, text="❌ 取消", command=cancel_settings, width=15).pack(side=tk.LEFT, padx=5) - def grid_correction(self): + def grid_settings(self): """网格修正功能""" target = self.get_selected_target() if not target: @@ -1061,10 +1064,6 @@ class TradeTargetUI(ttk.Frame): if not result: return - # 发布网格修正事件,传递GridFixData对象 - grid_fix_data = GridFixData(new_grid_index, target) - eBus.event_bus.publish(ActionEventGridFix, grid_fix_data) - # 关闭窗口 window.destroy() diff --git a/core/sfgrid/ui.py b/core/sfgrid/ui.py deleted file mode 100644 index e69de29..0000000