476 lines
18 KiB
Python
476 lines
18 KiB
Python
import random
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
from typing import List
|
|
from datetime import datetime
|
|
from core.strategy_db import TradeTarget
|
|
|
|
class TradeTargetUI:
|
|
def __init__(self):
|
|
self.root = tk.Tk()
|
|
self.root.title("交易标的监控系统")
|
|
self.root.geometry("1200x700")
|
|
|
|
# 创建界面
|
|
self.create_ui()
|
|
|
|
def create_ui(self):
|
|
"""创建UI界面"""
|
|
# 主框架
|
|
main_frame = ttk.Frame(self.root)
|
|
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
# 表格区域
|
|
self.create_tables_area(main_frame)
|
|
|
|
# 按钮区域
|
|
self.create_buttons_area(main_frame)
|
|
|
|
def create_tables_area(self, parent):
|
|
"""创建表格区域"""
|
|
tables_frame = ttk.Frame(parent)
|
|
tables_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# 左侧表格框架
|
|
left_frame = ttk.LabelFrame(tables_frame, text="交易标的详情", padding=10)
|
|
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
|
|
|
|
# 右侧表格框架
|
|
right_frame = ttk.LabelFrame(tables_frame, text="操作日志", padding=10)
|
|
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
|
|
|
|
# 创建左侧交易标的表格
|
|
self.create_trade_target_table(left_frame)
|
|
|
|
# 创建右侧操作日志表格
|
|
self.create_log_table(right_frame)
|
|
|
|
def create_trade_target_table(self, parent):
|
|
"""创建交易标的表格"""
|
|
# 创建Treeview
|
|
columns = (
|
|
"id", "stock_code", "stock_name", "current_position", "grid_index",
|
|
"last_trade_price", "current_buy_price", "current_sell_price",
|
|
"current_buy_order_no", "current_sell_order_no",
|
|
"status", "enabled"
|
|
)
|
|
|
|
self.trade_table = ttk.Treeview(parent, columns=columns, show='headings', height=12)
|
|
|
|
# 定义列标题和宽度
|
|
column_configs = {
|
|
"id": ("ID", 80),
|
|
"stock_code": ("股票代码", 80),
|
|
"stock_name": ("股票名称", 100),
|
|
"current_position": ("持仓数量", 90),
|
|
"grid_index": ("网格索引", 80),
|
|
"last_trade_price": ("最新成交价", 90),
|
|
"current_buy_price": ("当前买入价", 90),
|
|
"current_sell_price": ("当前卖出价", 90),
|
|
"current_buy_order_no": ("买入订单号", 120),
|
|
"current_sell_order_no": ("卖出订单号", 120),
|
|
"status": ("状态", 70),
|
|
"enabled": ("启用状态", 80)
|
|
}
|
|
|
|
for col in columns:
|
|
title, width = column_configs[col]
|
|
self.trade_table.heading(col, text=title)
|
|
self.trade_table.column(col, width=width, anchor=tk.CENTER)
|
|
|
|
# 填充数据
|
|
self.populate_trade_table()
|
|
|
|
# 滚动条
|
|
scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.trade_table.yview)
|
|
self.trade_table.configure(yscrollcommand=scrollbar.set)
|
|
|
|
# 布局
|
|
self.trade_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
# 绑定双击事件
|
|
self.trade_table.bind("<Double-1>", self.on_table_double_click)
|
|
|
|
def populate_trade_table(self):
|
|
"""填充交易标的表格数据"""
|
|
# 颜色标签
|
|
self.trade_table.tag_configure('enabled', background='#f0f8ff') # 淡蓝色
|
|
self.trade_table.tag_configure('disabled', background='#f5f5f5') # 淡灰色
|
|
|
|
def create_log_table(self, parent):
|
|
"""创建操作日志表格"""
|
|
columns = ("timestamp", "level", "message")
|
|
|
|
self.log_table = ttk.Treeview(parent, columns=columns, show='headings', height=12)
|
|
|
|
log_column_configs = {
|
|
"timestamp": ("时间", 120),
|
|
"level": ("级别", 60),
|
|
"message": ("消息", 200)
|
|
}
|
|
|
|
for col in columns:
|
|
title, width = log_column_configs[col]
|
|
self.log_table.heading(col, text=title)
|
|
self.log_table.column(col, width=width, anchor=tk.W)
|
|
|
|
# 填充示例日志
|
|
sample_logs = [
|
|
("2024-01-15 10:30:15", "INFO", "系统启动成功"),
|
|
("2024-01-15 10:31:22", "DEBUG", "加载交易标的: 5个"),
|
|
("2024-01-15 10:32:45", "INFO", "000001 - 网格交易线程启动"),
|
|
("2024-01-15 10:33:10", "WARNING", "601318 - 未启用交易"),
|
|
("2024-01-15 10:34:30", "ERROR", "300750 - 订单提交失败"),
|
|
("2024-01-15 10:35:18", "INFO", "600036 - 买入订单创建成功"),
|
|
("2024-01-15 10:36:05", "INFO", "数据刷新完成")
|
|
]
|
|
|
|
for log in sample_logs:
|
|
self.log_table.insert('', tk.END, values=log)
|
|
|
|
# 滚动条
|
|
scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.log_table.yview)
|
|
self.log_table.configure(yscrollcommand=scrollbar.set)
|
|
|
|
self.log_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
def create_buttons_area(self, parent):
|
|
"""创建按钮区域"""
|
|
buttons_frame = ttk.LabelFrame(parent, text="操作面板", padding=15)
|
|
buttons_frame.pack(fill=tk.X, pady=(10, 0))
|
|
|
|
# 创建五个功能按钮
|
|
self.create_five_buttons(buttons_frame)
|
|
|
|
def create_five_buttons(self, parent):
|
|
"""创建五个功能按钮"""
|
|
button_configs = [
|
|
("刷新数据", self.refresh_data, "🔄"),
|
|
("启用交易", self.enable_trading, "✅"),
|
|
("禁用交易", self.disable_trading, "⛔"),
|
|
("修改参数", self.modify_parameters, "⚙️"),
|
|
("系统设置", self.system_settings, "🔧")
|
|
]
|
|
|
|
for text, command, icon in button_configs:
|
|
btn = ttk.Button(
|
|
parent,
|
|
text=f"{icon} {text}",
|
|
command=command,
|
|
width=15
|
|
)
|
|
btn.pack(side=tk.LEFT, padx=8)
|
|
|
|
def refresh_data(self):
|
|
"""刷新数据功能"""
|
|
# 模拟数据更新
|
|
for target in self.trade_targets:
|
|
if target.enabled:
|
|
# 随机更新价格和仓位
|
|
target.last_trade_price += round((random.random() - 0.5) * 0.5, 2)
|
|
target.current_position += random.randint(-50, 50)
|
|
|
|
# 重新填充表格
|
|
for item in self.trade_table.get_children():
|
|
self.trade_table.delete(item)
|
|
|
|
for target in self.trade_targets:
|
|
values = [
|
|
target.id,
|
|
target.stock_code,
|
|
target.stock_name,
|
|
target.current_position,
|
|
target.grid_index,
|
|
target.last_trade_price,
|
|
target.current_buy_price,
|
|
target.current_buy_order_no,
|
|
target.current_sell_price,
|
|
target.current_sell_order_no,
|
|
self.get_status_text(target.status),
|
|
"是" if target.enabled else "否"
|
|
]
|
|
|
|
tags = ('enabled',) if target.enabled else ('disabled',)
|
|
self.trade_table.insert('', tk.END, values=values, tags=tags)
|
|
|
|
# 添加日志
|
|
self.add_log("INFO", "数据刷新完成")
|
|
|
|
def enable_trading(self):
|
|
"""启用交易功能"""
|
|
selected = self.trade_table.selection()
|
|
if selected:
|
|
item = selected[0]
|
|
values = self.trade_table.item(item)['values']
|
|
# 在实际应用中,这里会调用实际的启用逻辑
|
|
self.add_log("INFO", f"启用交易标的: {values[0]}")
|
|
|
|
def disable_trading(self):
|
|
"""禁用交易功能"""
|
|
selected = self.trade_table.selection()
|
|
if selected:
|
|
item = selected[0]
|
|
values = self.trade_table.item(item)['values']
|
|
self.add_log("INFO", f"禁用交易标的: {values[0]}")
|
|
|
|
def modify_parameters(self):
|
|
"""修改参数功能"""
|
|
selected = self.trade_table.selection()
|
|
if selected:
|
|
item = selected[0]
|
|
values = self.trade_table.item(item)['values']
|
|
# 弹出修改对话框
|
|
self.show_parameter_dialog()
|
|
|
|
def system_settings(self):
|
|
"""系统设置功能"""
|
|
# 弹出系统设置对话框
|
|
settings_window = tk.Toplevel(self.root)
|
|
settings_window.title("系统设置")
|
|
settings_window.geometry("400x300")
|
|
|
|
ttk.Label(settings_window, text="网格交易系统设置", font=('Arial', 12, 'bold')).pack(pady=20)
|
|
|
|
# 添加一些设置选项
|
|
options = [
|
|
("自动刷新间隔", "5秒"),
|
|
("价格变动阈值", "0.1%"),
|
|
("最大持仓数量", "10000"),
|
|
("最小交易数量", "100")
|
|
]
|
|
|
|
for label, value in options:
|
|
frame = ttk.Frame(settings_window)
|
|
frame.pack(fill=tk.X, padx=20, pady=10)
|
|
|
|
ttk.Label(frame, text=label, width=20).pack(side=tk.LEFT)
|
|
ttk.Label(frame, text=value).pack(side=tk.RIGHT)
|
|
|
|
def get_status_text(self, status):
|
|
"""获取状态文本"""
|
|
status_map = {
|
|
0: "新标的",
|
|
1: "交易中"
|
|
}
|
|
return status_map.get(status, "未知")
|
|
|
|
def on_table_double_click(self, event):
|
|
"""表格双击事件"""
|
|
selected = self.trade_table.selection()
|
|
if selected:
|
|
item = selected[0]
|
|
values = self.trade_table.item(item)['values']
|
|
self.add_log("DEBUG", f"双击查看详情: {values[0]} - {values[1]}")
|
|
|
|
def add_log(self, level, message):
|
|
"""添加日志记录"""
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
self.log_table.insert('', 0, values=(timestamp, level, message))
|
|
|
|
def run(self):
|
|
"""运行程序"""
|
|
# 初始填充数据
|
|
for target in self.trade_targets:
|
|
values = [
|
|
target.stock_code,
|
|
target.stock_name,
|
|
target.current_position,
|
|
target.grid_index,
|
|
target.last_trade_price,
|
|
target.current_buy_price,
|
|
target.current_buy_order_no,
|
|
target.current_sell_price,
|
|
target.current_sell_order_no,
|
|
self.get_status_text(target.status),
|
|
"是" if target.enabled else "否"
|
|
]
|
|
|
|
tags = ('enabled',) if target.enabled else ('disabled',)
|
|
self.trade_table.insert('', tk.END, values=values, tags=tags)
|
|
|
|
self.root.mainloop()
|
|
|
|
# 更专业的版本,集成实际的TradeTarget对象
|
|
class ProfessionalTradeUI(TradeTargetUI):
|
|
def __init__(self, trade_targets: List[TradeTarget] = None):
|
|
if trade_targets is not None:
|
|
self.trade_targets = trade_targets
|
|
else:
|
|
self.trade_targets = self.create_advanced_sample_data()
|
|
super().__init__()
|
|
|
|
def create_trade_target_table(self, parent):
|
|
"""专业版的交易标的表格"""
|
|
columns = ("ID",
|
|
"股票代码", "股票名称", "持仓数量", "网格索引",
|
|
"最新成交价", "当前买入价", "当前买入订单号", "当前卖出价", "当前卖出订单号",
|
|
"启用状态", "交易状态"
|
|
)
|
|
|
|
self.trade_table = ttk.Treeview(parent, columns=columns, show='headings', height=15)
|
|
|
|
# 专业化的列配置
|
|
column_configs = {
|
|
"ID": (50, tk.CENTER),
|
|
"股票代码": (90, tk.CENTER),
|
|
"股票名称": (100, tk.CENTER),
|
|
"持仓数量": (90, tk.CENTER),
|
|
"网格索引": (80, tk.CENTER),
|
|
"最新成交价": (100, tk.CENTER),
|
|
"当前买入价": (100, tk.CENTER),
|
|
"当前买入订单号": (100, tk.CENTER),
|
|
"当前卖出订单号": (100, tk.CENTER),
|
|
"当前卖出价": (100, tk.CENTER),
|
|
"启用状态": (80, tk.CENTER),
|
|
"交易状态": (80, tk.CENTER),
|
|
"买入订单号": (120, tk.CENTER),
|
|
"卖出订单号": (120, tk.CENTER)
|
|
}
|
|
|
|
for col in columns:
|
|
width, anchor = column_configs[col]
|
|
self.trade_table.heading(col, text=col)
|
|
self.trade_table.column(col, width=width, anchor=anchor)
|
|
|
|
# 带颜色的标签
|
|
self.trade_table.tag_configure('trading', background='#e8f5e8') # 交易中的绿色背景
|
|
self.trade_table.tag_configure('paused', background='#fff3cd') # 暂停的黄色背景
|
|
self.trade_table.tag_configure('inactive', background='#f8d7da') # 禁用的红色背景
|
|
|
|
# 填充数据
|
|
for temp in self.trade_targets:
|
|
target:TradeTarget = temp
|
|
values = [
|
|
target.id,
|
|
target.stock_code,
|
|
target.stock_name,
|
|
target.current_position,
|
|
target.grid_index,
|
|
f"{target.last_trade_price:.2f}",
|
|
f"{target.current_buy_price:.2f}",
|
|
target.current_buy_order_no,
|
|
f"{target.current_sell_price:.2f}",
|
|
target.current_sell_order_no,
|
|
"已启用" if target.enabled else "未启用",
|
|
"交易中" if target.status == 1 else "新标的"
|
|
]
|
|
|
|
# 根据状态设置标签
|
|
if target.enabled and target.status == 1:
|
|
tags = ('trading',)
|
|
elif target.enabled and target.status == 0:
|
|
tags = ('paused',)
|
|
else:
|
|
tags = ('inactive',)
|
|
|
|
self.trade_table.insert('', tk.END, values=values, tags=tags)
|
|
|
|
# 滚动条
|
|
scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.trade_table.yview)
|
|
self.trade_table.configure(yscrollcommand=scrollbar.set)
|
|
|
|
self.trade_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
def refresh_data(self):
|
|
"""专业版的刷新数据功能"""
|
|
for target in self.trade_targets:
|
|
if target.enabled:
|
|
# 模拟实时的价格变动
|
|
price_change = (random.random() - 0.5) * 0.1
|
|
target.last_trade_price = round(target.last_trade_price + price_change, 2)
|
|
|
|
# 更新表格
|
|
for item in self.trade_table.get_children():
|
|
self.trade_table.delete(item)
|
|
|
|
for target in self.trade_targets:
|
|
values = [
|
|
target.id,
|
|
target.stock_code,
|
|
target.stock_name,
|
|
target.current_position,
|
|
target.grid_index,
|
|
f"{target.last_trade_price:.2f}",
|
|
f"{target.current_buy_price:.2f}",
|
|
f"{target.current_sell_price:.2f}",
|
|
"已启用" if target.enabled else "未启用",
|
|
"交易中" if target.status == 1 else "新标的"
|
|
]
|
|
|
|
# 设置标签
|
|
if target.enabled and target.status == 1:
|
|
tags = ('trading',)
|
|
elif target.enabled and target.status == 0:
|
|
tags = ('paused',)
|
|
else:
|
|
tags = ('inactive',)
|
|
|
|
self.trade_table.insert('', tk.END, values=values, tags=tags)
|
|
|
|
self.add_log("INFO", "专业版数据刷新完成 - 包含实时价格模拟")
|
|
|
|
def show_parameter_dialog(self):
|
|
"""显示参数修改对话框"""
|
|
dialog = tk.Toplevel(self.root)
|
|
dialog.title("交易参数设置")
|
|
dialog.geometry("500x400")
|
|
|
|
# 创建配置表单
|
|
ttk.Label(dialog, text="交易标的参数配置", font=('Arial', 12, 'bold')).pack(pady=20)
|
|
|
|
# 创建标签和输入框
|
|
form_frame = ttk.Frame(dialog)
|
|
form_frame.pack(fill=tk.BOTH, expand=True, padx=20)
|
|
|
|
# 这里可以添加具体的参数配置表单
|
|
ttk.Label(form_frame, text="双击表格项可查看详情", font=('Arial', 10)).pack(pady=10)
|
|
|
|
def system_settings(self):
|
|
"""专业版的系统设置"""
|
|
settings_window = tk.Toplevel(self.root)
|
|
settings_window.title("网格交易系统配置")
|
|
settings_window.geometry("600x400")
|
|
|
|
# 创建选项卡
|
|
notebook = ttk.Notebook(settings_window)
|
|
notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
# 基础设置
|
|
basic_frame = ttk.Frame(notebook)
|
|
notebook.add(basic_frame, text="基础设置")
|
|
|
|
# 高级设置
|
|
advanced_frame = ttk.Frame(notebook)
|
|
notebook.add(advanced_frame, text="高级设置")
|
|
|
|
# 添加具体的配置选项
|
|
settings = [
|
|
("网格宽度", "0.5%"),
|
|
("网格数量", "10层"),
|
|
("交易间隔", "30秒"),
|
|
("单笔数量", "100股")
|
|
]
|
|
|
|
for i, (label, default) in enumerate(settings):
|
|
frame = ttk.Frame(basic_frame)
|
|
frame.pack(fill=tk.X, padx=20, pady=10)
|
|
ttk.Label(frame, text=label, width=15).pack(side=tk.LEFT)
|
|
entry = ttk.Entry(frame, width=20)
|
|
entry.insert(0, default)
|
|
entry.pack(side=tk.RIGHT)
|
|
|
|
# 使用示例
|
|
if __name__ == "__main__":
|
|
print("交易标的监控系统启动...")
|
|
print("功能说明:")
|
|
print(" - 左侧表格显示所有交易标的详细信息")
|
|
print(" - 右侧表格显示操作日志")
|
|
print(" - 底部五个功能按钮提供操作")
|
|
|
|
# 创建并运行界面
|
|
app = ProfessionalTradeUI()
|
|
app.run()
|