This commit is contained in:
2025-11-12 11:51:40 +08:00
parent 0d54f8b05a
commit 5e64e93172
3 changed files with 86 additions and 43 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ class MainWindow:
# 创建Tab按钮(垂直排列,文字垂直显示) # 创建Tab按钮(垂直排列,文字垂直显示)
self.tab_buttons = [] self.tab_buttons = []
strategy_names = ["三疯\n网格", "通用\n网格", "涨停\n分析"] strategy_names = ["蒙派\n策略", "涨停\n分析"]
for idx, name in enumerate(strategy_names): for idx, name in enumerate(strategy_names):
btn = ttk.Button( btn = ttk.Button(
+1 -3
View File
@@ -56,16 +56,14 @@ class SFGridStrategy:
return bool(self.tradeTarget.enabled) # 修复返回类型问题 return bool(self.tradeTarget.enabled) # 修复返回类型问题
def onDataUpdate(self, inTradeTarget:model.SFGridTradeTarget): def onDataUpdate(self, inTradeTarget:model.SFGridTradeTarget):
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START')
if not is_trading_time(): if not is_trading_time():
print(f"|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 非交易时间,不进行自动交易")
return return
if not self.tradeTarget.enabled: # 未建仓,自动交易暂停 if not self.tradeTarget.enabled: # 未建仓,自动交易暂停
print(f"|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - 未建仓或交易监控暂停,不进行自动交易")
return return
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - START')
self.dataUpdateLock.acquire() self.dataUpdateLock.acquire()
print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED') print(f'|- 市价更新[{self.tradeTarget.stock_code}-{self.tradeTarget.stock_name}] - LOCKED')
+84 -39
View File
@@ -32,6 +32,9 @@ class TradeTargetUI(ttk.Frame):
# 市场监控数据 # 市场监控数据
self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}} self.marketData: dict[str, Any] = {} # 存储市场数据 {stock_code: {stock_name, last_price, time}}
# 市场监控窗口显示状态
self.market_monitor_visible = True
# 创建界面 # 创建界面
self.create_ui() self.create_ui()
@@ -40,20 +43,18 @@ class TradeTargetUI(ttk.Frame):
def onMarketDataUpdated(self, data): def onMarketDataUpdated(self, data):
# 收集所有市场数据用于市场监控 # 收集所有市场数据用于市场监控
for stock_code, tickData in data.items(): for stock_code, tickData in data.items():
id = self.stockCodeIdMap.get(stock_code) if stock_code in self.stockCodeIdMap:
if id is not None and stock_code in self.tradeTargetData: id:int = self.stockCodeIdMap[stock_code]
tradeTarget = self.tradeTargetData[id] tradeTarget = self.tradeTargetData[id]
PrintLog(LogLevel.INFO, f' [市价更新 序号-{id}] {stock_code} - {tickData}')
lastPrice = float("{:.3f}".format(tickData['lastPrice'])) lastPrice = float("{:.3f}".format(tickData['lastPrice']))
tradeTarget.market_price = lastPrice # type: ignore tradeTarget.market_price = lastPrice # type: ignore
self.updateTradeTarget(tradeTarget)
stock_controller: SFGridStrategy = self.strategy_ctrl[id] stock_controller: SFGridStrategy = self.strategy_ctrl[id]
stock_controller.onDataUpdate(tradeTarget) stock_controller.onDataUpdate(tradeTarget)
else: else:
# 非目标交易,发布市场数据更新事件用于市场监控 # 非目标交易,发布市场数据更新事件用于市场监控
lastPrice = tickData['lastPrice'] lastPrice = tickData['lastPrice']
if lastPrice == 10 or stock_code in self.listening_stock: if lastPrice == 10 or stock_code in self.listening_stock:
PrintLog(LogLevel.INFO, f' [市价更新 序号-X] {stock_code} - {lastPrice}')
# 发布市场数据更新事件用于市场监控 # 发布市场数据更新事件用于市场监控
market_target = SFGridTradeTarget() market_target = SFGridTradeTarget()
market_target.stock_code = stock_code market_target.stock_code = stock_code
@@ -61,7 +62,13 @@ class TradeTargetUI(ttk.Frame):
market_target.market_price = lastPrice # type: ignore market_target.market_price = lastPrice # type: ignore
if stock_code not in self.listening_stock: if stock_code not in self.listening_stock:
self.listening_stock.append(stock_code) self.listening_stock.append(stock_code)
# 更新市场监控数据用于UI显示
current_time = datetime.now().strftime("%H:%M:%S")
self.marketData[str(stock_code)] = {
'stock_name': qmtv.getInstrumentName(stock_code),
'last_price': tickData['lastPrice'],
'time': current_time
}
def refresh_targets(self): def refresh_targets(self):
# 更新标的池 # 更新标的池
@@ -84,7 +91,6 @@ class TradeTargetUI(ttk.Frame):
PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]') PrintLog(LogLevel.INFO, f' |- 同步[{tradeTarget.stock_code}-{tradeTarget.stock_name}]持仓信息[{'成功' if result == 1 else '失败'}]')
stockTradeController = SFGridStrategy(tradeTarget) # type: ignore stockTradeController = SFGridStrategy(tradeTarget) # type: ignore
self.strategy_ctrl[id] = stockTradeController # pyright: ignore[reportArgumentType] self.strategy_ctrl[id] = stockTradeController # pyright: ignore[reportArgumentType]
# eBus.event_bus.publish(eBus.EventTradeTargetUpdate, tradeTarget)
self.updateTradeTarget(tradeTarget) self.updateTradeTarget(tradeTarget)
PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的') PrintLog(LogLevel.INFO, f'- [成功]交易标的信息初始化, 共 {len(self.tradeTargetData)} 个标的')
@@ -99,9 +105,9 @@ class TradeTargetUI(ttk.Frame):
"""刷新循环""" """刷新循环"""
while self.refresh_thread_running: while self.refresh_thread_running:
# 在主线程中更新UI # 在主线程中更新UI
PrintLog(LogLevel.INFO, "刷新UI")
self.after(0, self.refresh_table) self.after(0, self.refresh_table)
time.sleep(0.5) # 每0.5秒刷新一次 self.after(0, self.populate_market_table)
time.sleep(0.2) # 每0.5秒刷新一次
def stop_refresh_thread(self): def stop_refresh_thread(self):
"""停止刷新线程""" """停止刷新线程"""
@@ -113,7 +119,6 @@ class TradeTargetUI(ttk.Frame):
def onTradeDisabled(self, target:SFGridTradeTarget): def onTradeDisabled(self, target:SFGridTradeTarget):
PrintLog(LogLevel.INFO, f"交易禁用: {target.stock_code} - {target.stock_name}") PrintLog(LogLevel.INFO, f"交易禁用: {target.stock_code} - {target.stock_name}")
def updateTradeTarget(self, target: SFGridTradeTarget): def updateTradeTarget(self, target: SFGridTradeTarget):
# 更新或添加数据到本地缓存 # 更新或添加数据到本地缓存
@@ -142,8 +147,10 @@ class TradeTargetUI(ttk.Frame):
ttk.Button(toolbar_frame, text="🛠 网格修正", ttk.Button(toolbar_frame, text="🛠 网格修正",
command=self.grid_correction, width=12).pack(side=tk.LEFT, padx=2) command=self.grid_correction, width=12).pack(side=tk.LEFT, padx=2)
# 添加分隔符 # 添加抽屉按钮到工具栏最右侧
ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10) self.toggle_market_monitor_btn = ttk.Button(toolbar_frame, text="◀▶",
command=self.toggle_market_monitor, width=3)
self.toggle_market_monitor_btn.pack(side=tk.RIGHT, padx=2)
# 表格区域 # 表格区域
self.create_tables_area(main_frame) self.create_tables_area(main_frame)
@@ -163,7 +170,6 @@ class TradeTargetUI(ttk.Frame):
PrintLog(LogLevel.INFO, "UI刷新线程已停止") PrintLog(LogLevel.INFO, "UI刷新线程已停止")
def create_tables_area(self, parent): def create_tables_area(self, parent):
"""创建表格区域""" """创建表格区域"""
# 创建主表格框架(水平排列) # 创建主表格框架(水平排列)
@@ -178,17 +184,17 @@ class TradeTargetUI(ttk.Frame):
self.create_trade_target_table(trade_frame) self.create_trade_target_table(trade_frame)
# 右侧市场监控区域 # 右侧市场监控区域
market_frame = ttk.LabelFrame(tables_frame, text="市场监控", padding=10) self.market_frame = ttk.LabelFrame(tables_frame, text="市场监控", padding=10)
market_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0)) self.market_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
# 创建市场监控表格 # 创建市场监控表格
self.create_market_monitor_table(market_frame) self.create_market_monitor_table(self.market_frame)
def create_trade_target_table(self, parent): def create_trade_target_table(self, parent):
"""创建交易标的表格""" """创建交易标的表格"""
columns = ("ID", columns = ("ID",
"股票代码", "股票名称", "市场价", "持仓数量", "网格索引", "股票代码", "股票名称", "市场价", "持仓数量",
"最新成交价", "计划买入价", "计划卖出价", "当前订单价", "当前订单号", "当前订单类型", "最新成交价", "计划买入价", "计划卖出价", "当前订单价", "当前订单号", "当前订单类型",
"交易状态" "交易状态"
) )
@@ -199,17 +205,16 @@ class TradeTargetUI(ttk.Frame):
column_configs = { column_configs = {
"ID": (50, tk.CENTER), "ID": (50, tk.CENTER),
"股票代码": (90, tk.CENTER), "股票代码": (90, tk.CENTER),
"股票名称": (80, tk.CENTER), "股票名称": (80, tk.E),
"市场价": (70, tk.CENTER), "市场价": (70, tk.E),
"持仓数量": (80, tk.CENTER), "持仓数量": (80, tk.E),
"网格索引": (80, tk.CENTER), "最新成交价": (90, tk.E),
"最新成交": (90, tk.CENTER), "计划买入": (90, tk.E),
"计划买入": (90, tk.CENTER), "计划卖出": (90, tk.E),
"计划卖出": (90, tk.CENTER), "当前订单": (90, tk.E),
"当前订单": (90, tk.CENTER), "当前订单": (90, tk.E),
"当前订单": (90, tk.CENTER), "当前订单类型": (90, tk.E),
"当前订单类型": (90, tk.CENTER), "交易状态": (80, tk.E)
"交易状态": (80, tk.CENTER)
} }
for col in columns: for col in columns:
@@ -232,16 +237,15 @@ class TradeTargetUI(ttk.Frame):
def create_market_monitor_table(self, parent): def create_market_monitor_table(self, parent):
"""创建市场监控表格""" """创建市场监控表格"""
columns = ("时间", "股票代码", "股票名称", "最新价格") columns = ("时间", "股票名称", "最新价格")
self.market_table = ttk.Treeview(parent, columns=columns, show='headings', height=15) self.market_table = ttk.Treeview(parent, columns=columns, show='headings', height=15)
# 列配置 # 列配置
column_configs = { column_configs = {
"时间": (120, "center"), "时间": (50, tk.CENTER),
"股票代码": (90, "center"), "股票名称": (80, tk.CENTER),
"股票名称": (80, "center"), "最新价格": (80, tk.CENTER)
"最新价格": (80, "center")
} }
for col in columns: for col in columns:
@@ -264,7 +268,14 @@ class TradeTargetUI(ttk.Frame):
def populate_market_table(self): def populate_market_table(self):
"""填充市场监控表格数据""" """填充市场监控表格数据"""
pass # 保存当前选中的项
selected_items = self.market_table.selection()
selected_values = []
for item in selected_items:
values = self.market_table.item(item)['values']
if values:
selected_values.append(values[1]) # 保存股票代码
# 清空现有数据 # 清空现有数据
for item in self.market_table.get_children(): for item in self.market_table.get_children():
self.market_table.delete(item) self.market_table.delete(item)
@@ -272,13 +283,35 @@ class TradeTargetUI(ttk.Frame):
# 填充市场数据 # 填充市场数据
tmp = self.marketData.copy() tmp = self.marketData.copy()
for stock_code, data in tmp.items(): for stock_code, data in tmp.items():
# 处理时间格式,仅显示 hh:mm:ss
time_str = data['time']
# 如果时间字符串包含空格,说明包含日期和时间,只取时间部分
if ' ' in time_str:
time_str = time_str.split(' ')[1]
# 确保时间格式为 hh:mm:ss,如果只有 hh:mm 则补充 :00
if ':' in time_str:
time_components = time_str.split(':')
if len(time_components) == 2:
# 只有小时和分钟,补充秒
time_str = f"{time_components[0]}:{time_components[1]}:00"
elif len(time_components) >= 3:
# 有小时、分钟和秒,只取前三个部分
time_str = f"{time_components[0]}:{time_components[1]}:{time_components[2]}"
values = [ values = [
data['time'], time_str,
stock_code, data['stock_name']+f"{stock_code}",
data['stock_name'],
f"{data['last_price']:.3f}" f"{data['last_price']:.3f}"
] ]
self.market_table.insert('', tk.END, values=values) self.market_table.insert('', tk.END, values=values)
# 恢复之前选中的项
if selected_values:
for item in self.market_table.get_children():
values = self.market_table.item(item)['values']
if values and values[1] in selected_values: # 比较股票代码
self.market_table.selection_add(item)
def on_market_table_double_click(self, event): def on_market_table_double_click(self, event):
"""市场监控表格双击事件""" """市场监控表格双击事件"""
@@ -324,7 +357,6 @@ class TradeTargetUI(ttk.Frame):
target.stock_name, target.stock_name,
"-" if target.market_price is None else f"{target.market_price:.3f}", "-" if target.market_price is None else f"{target.market_price:.3f}",
target.current_position, target.current_position,
target.grid_index,
'-' if target.last_trade_price is None else f"{target.last_trade_price:.3f}", '-' if target.last_trade_price is None else f"{target.last_trade_price:.3f}",
'-' if target.plan_buy_price is None else f"{target.plan_buy_price:.3f}", '-' if target.plan_buy_price is None else f"{target.plan_buy_price:.3f}",
'-' if target.plan_sell_price is None else f"{target.plan_sell_price:.3f}", '-' if target.plan_sell_price is None else f"{target.plan_sell_price:.3f}",
@@ -1105,4 +1137,17 @@ class TradeTargetUI(ttk.Frame):
PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}") PrintLog(LogLevel.INFO, f"网格修正已应用: {target.stock_code} - {target.stock_name}, 网格索引: {grid_index}")
except Exception as e: except Exception as e:
PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}") PrintLog(LogLevel.ERROR, f"网格修正更新失败: {str(e)}")
def toggle_market_monitor(self):
"""切换市场监控窗口显示/隐藏"""
if self.market_monitor_visible:
# 隐藏市场监控窗口
self.market_frame.pack_forget()
self.toggle_market_monitor_btn.config(text="")
self.market_monitor_visible = False
else:
# 显示市场监控窗口
self.market_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
self.toggle_market_monitor_btn.config(text="◀▶")
self.market_monitor_visible = True