init new structure
This commit is contained in:
+4
-7
@@ -7,6 +7,10 @@ MarketOrderTraded = "market_order_traded" # 市价单成交
|
|||||||
# Pring Log
|
# Pring Log
|
||||||
EventPrintLog = "print_log" # 打印日志
|
EventPrintLog = "print_log" # 打印日志
|
||||||
|
|
||||||
|
# 订阅与发布事件示例
|
||||||
|
# event_bus.subscribe('my_event', handle_event)
|
||||||
|
# event_bus.publish('my_event', {'key': 'value'})
|
||||||
|
|
||||||
class EventBus:
|
class EventBus:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.listeners = {} # 管理各种event的订阅情况
|
self.listeners = {} # 管理各种event的订阅情况
|
||||||
@@ -21,12 +25,5 @@ class EventBus:
|
|||||||
for listener in self.listeners[event_type]:
|
for listener in self.listeners[event_type]:
|
||||||
listener(data)
|
listener(data)
|
||||||
|
|
||||||
|
|
||||||
# # 订阅事件
|
|
||||||
# event_bus.subscribe('my_event', handle_event)
|
|
||||||
|
|
||||||
# # 发布事件
|
|
||||||
# event_bus.publish('my_event', {'key': 'value'})
|
|
||||||
|
|
||||||
# 创建事件总线实例
|
# 创建事件总线实例
|
||||||
event_bus = EventBus()
|
event_bus = EventBus()
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# coding:utf-8
|
||||||
|
import tkinter as tk
|
||||||
|
from core.logger import LogLevel, PrintLog
|
||||||
|
from PIL import Image
|
||||||
|
import pystray
|
||||||
|
import threading
|
||||||
|
|
||||||
|
class MainEntry:
|
||||||
|
def __init__(self, master):
|
||||||
|
self.master = master
|
||||||
|
self.master.title("Main Board")
|
||||||
|
self.master.geometry("800x600")
|
||||||
|
self.master.configure(bg="#f0f0f0")
|
||||||
|
self.master.resizable(False, False)
|
||||||
|
self.master.protocol("WM_DELETE_WINDOW", self.hide_window)
|
||||||
|
self.qmt_enabled = False
|
||||||
|
self.icon = None
|
||||||
|
self.create_systray_icon()
|
||||||
|
|
||||||
|
def create_systray_icon(self):
|
||||||
|
# 加载图标文件(需确保路径正确)
|
||||||
|
image = Image.open("logo.png")
|
||||||
|
# 定义托盘菜单
|
||||||
|
menu = (
|
||||||
|
pystray.MenuItem('交易大师', None, enabled=False),
|
||||||
|
pystray.MenuItem(" - 交易复盘", self.handler),
|
||||||
|
pystray.MenuItem(" - 市场数据", self.handler),
|
||||||
|
pystray.MenuItem(" - 快速下单", self.handler),
|
||||||
|
pystray.MenuItem('策略交易', None, enabled=False),
|
||||||
|
pystray.MenuItem(" - 交易看板", self.handler),
|
||||||
|
pystray.MenuItem(" - 策略中心", None),
|
||||||
|
pystray.MenuItem(" - 策略定制", None),
|
||||||
|
pystray.MenuItem('实时数据', None, enabled=False),
|
||||||
|
pystray.MenuItem(" - QMT (已关闭)" if not self.qmt_enabled else " - QMT (已开启)", self.marketDataSwitch),
|
||||||
|
pystray.Menu.SEPARATOR,
|
||||||
|
pystray.MenuItem(" - 控制台", self.show_window, default=True),
|
||||||
|
pystray.MenuItem(" - 设置", self.marketDataSwitch),
|
||||||
|
pystray.MenuItem(" - 退出", self.quit_window)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.icon:
|
||||||
|
self.icon.menu = menu
|
||||||
|
self.icon.update_menu()
|
||||||
|
else:
|
||||||
|
# 创建托盘图标
|
||||||
|
self.icon = pystray.Icon("name", image, "标题", menu)
|
||||||
|
PrintLog(LogLevel.INFO, "创建托盘图标 start threading")
|
||||||
|
self.trayThread = threading.Thread(target=self.icon.run, daemon=True)
|
||||||
|
self.trayThread.start()
|
||||||
|
# 在后台线程运行托盘
|
||||||
|
|
||||||
|
def marketDataSwitch(self):
|
||||||
|
if self.qmt_enabled:
|
||||||
|
self.qmt_enabled = False
|
||||||
|
PrintLog(LogLevel.INFO, "QMT 市场数据已关闭")
|
||||||
|
else:
|
||||||
|
self.qmt_enabled = True
|
||||||
|
PrintLog(LogLevel.INFO, "QMT 市场数据已开启")
|
||||||
|
self.create_systray_icon()
|
||||||
|
|
||||||
|
def handler(self):
|
||||||
|
PrintLog(LogLevel.INFO, f"点击了")
|
||||||
|
|
||||||
|
def hide_window(self):
|
||||||
|
PrintLog(LogLevel.INFO, "隐藏主窗口")
|
||||||
|
self.master.withdraw() # 隐藏主窗口
|
||||||
|
|
||||||
|
def show_window(self):
|
||||||
|
self.icon.visible = True
|
||||||
|
PrintLog(LogLevel.INFO, "显示主窗口")
|
||||||
|
self.master.deiconify() # 显示主窗口
|
||||||
|
|
||||||
|
def quit_window(self, icon: pystray.Icon):
|
||||||
|
icon.stop()
|
||||||
|
PrintLog(LogLevel.INFO, "退出应用")
|
||||||
|
self.master.quit()
|
||||||
|
self.master.destroy()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.master.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# 软件介绍
|
||||||
|
软件名称:神之一手交易系统
|
||||||
|
软件介绍:面向个人的交易管理系统,提供交易记录、复盘工具、持仓管理、资产监控、策略交易等功能。
|
||||||
|
|
||||||
|
# 模块介绍
|
||||||
|
1. /core/daily_review: 每日复盘模块目录
|
||||||
|
2. /core/market_data: 市场数据模块目录
|
||||||
|
3. /core/quick_trade: 快速交易模块目录
|
||||||
|
4. /core/strategy/builder: 策略构建模块目录
|
||||||
|
5. /core/strategy/trade: 策略交易模块目录
|
||||||
|
6. /core: 应用核心程序目录
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# coding:utf-8
|
||||||
|
import os
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, filedialog, messagebox
|
||||||
|
import configparser
|
||||||
|
from core.main_ui import MainWindow
|
||||||
|
import config as sdConstants
|
||||||
|
from core.qmt import qmtv
|
||||||
|
|
||||||
|
class ConfigWindow:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("系统配置")
|
||||||
|
self.root.geometry("500x250")
|
||||||
|
self.root.resizable(False, False)
|
||||||
|
|
||||||
|
# 居中显示
|
||||||
|
self.root.withdraw() # 先隐藏窗口
|
||||||
|
self.root.update_idletasks()
|
||||||
|
x = (self.root.winfo_screenwidth() // 2) - (500 // 2)
|
||||||
|
y = (self.root.winfo_screenheight() // 2) - (250 // 2)
|
||||||
|
self.root.geometry(f"500x250+{x}+{y}")
|
||||||
|
self.root.deiconify() # 再显示窗口
|
||||||
|
|
||||||
|
self.miniQMTPath = tk.StringVar()
|
||||||
|
self.account_no = tk.StringVar()
|
||||||
|
|
||||||
|
self.create_widgets()
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
# 创建主框架
|
||||||
|
main_frame = ttk.Frame(self.root, padding="20")
|
||||||
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# miniQMT路径配置
|
||||||
|
path_frame = ttk.Frame(main_frame)
|
||||||
|
path_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
path_label = ttk.Label(path_frame, text="miniQMT路径:")
|
||||||
|
path_label.pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
path_entry = ttk.Entry(path_frame, textvariable=self.miniQMTPath, width=40)
|
||||||
|
path_entry.pack(side=tk.LEFT, padx=(10, 5), fill=tk.X, expand=True)
|
||||||
|
|
||||||
|
browse_btn = ttk.Button(path_frame, text="浏览", command=self.browse_folder)
|
||||||
|
browse_btn.pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
# 资金账号配置
|
||||||
|
account_frame = ttk.Frame(main_frame)
|
||||||
|
account_frame.pack(fill=tk.X, pady=5)
|
||||||
|
|
||||||
|
account_label = ttk.Label(account_frame, text="资金账号:")
|
||||||
|
account_label.pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
account_entry = ttk.Entry(account_frame, textvariable=self.account_no, width=40)
|
||||||
|
account_entry.pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
# 说明文本
|
||||||
|
info_label = ttk.Label(
|
||||||
|
main_frame,
|
||||||
|
text="请配置miniQMT的userdata_mini路径和资金账号\n路径示例: D:/Programs/DTQMT/userdata_mini",
|
||||||
|
foreground="gray"
|
||||||
|
)
|
||||||
|
info_label.pack(pady=10)
|
||||||
|
|
||||||
|
# 按钮框架
|
||||||
|
button_frame = ttk.Frame(main_frame)
|
||||||
|
button_frame.pack(fill=tk.X, pady=10)
|
||||||
|
|
||||||
|
save_btn = ttk.Button(button_frame, text="保存配置", command=self.save_config)
|
||||||
|
save_btn.pack(side=tk.RIGHT)
|
||||||
|
|
||||||
|
cancel_btn = ttk.Button(button_frame, text="取消", command=self.root.destroy)
|
||||||
|
cancel_btn.pack(side=tk.RIGHT, padx=(0, 10))
|
||||||
|
|
||||||
|
def browse_folder(self):
|
||||||
|
folder_selected = filedialog.askdirectory()
|
||||||
|
if folder_selected:
|
||||||
|
self.miniQMTPath.set(folder_selected)
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
mini_qmt_path = self.miniQMTPath.get().strip()
|
||||||
|
account_number = self.account_no.get().strip()
|
||||||
|
|
||||||
|
# 检查miniQMT路径
|
||||||
|
if not mini_qmt_path:
|
||||||
|
messagebox.showerror("错误", "请选择miniQMT路径")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not os.path.exists(mini_qmt_path):
|
||||||
|
messagebox.showerror("错误", "miniQMT路径不存在")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 检查账号
|
||||||
|
if not account_number:
|
||||||
|
messagebox.showerror("错误", "请输入资金账号")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 保存配置
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config['config'] = {
|
||||||
|
'miniQMTPath': mini_qmt_path.replace('\\', '/'),
|
||||||
|
'account_no': account_number,
|
||||||
|
'log_level': 'INFO'
|
||||||
|
}
|
||||||
|
|
||||||
|
config_path = sdConstants.get_config_path()
|
||||||
|
try:
|
||||||
|
with open(config_path, 'w') as configfile:
|
||||||
|
config.write(configfile)
|
||||||
|
messagebox.showinfo("成功", "配置已保存")
|
||||||
|
self.root.destroy()
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("错误", f"保存配置失败: {str(e)}")
|
||||||
|
|
||||||
|
def check_and_create_config():
|
||||||
|
"""检查配置文件,如果不存在则打开配置窗口"""
|
||||||
|
root = tk.Tk()
|
||||||
|
config_window = ConfigWindow(root)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
def initialize_system():
|
||||||
|
"""初始化系统"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
# 初始化配置
|
||||||
|
if sdConstants.exist_config() and sdConstants.initConfig():
|
||||||
|
# 初始化qmtv
|
||||||
|
qmtv.init_qmtv()
|
||||||
|
connected = qmtv.connect()
|
||||||
|
if connected:
|
||||||
|
# 连接成功,启动主窗口
|
||||||
|
window = MainWindow(sdConstants.log_level)
|
||||||
|
window.run()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
option = messagebox.askokcancel("连接失败", "QMT连接失败,请检查")
|
||||||
|
if option:
|
||||||
|
check_and_create_config()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
option = messagebox.askokcancel("错误", "请检查配置")
|
||||||
|
if option:
|
||||||
|
check_and_create_config()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("错误", f"系统初始化失败: {str(e)}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import tkinter as tk
|
||||||
|
root = tk.Tk()
|
||||||
|
app = MainBoardWindow(root)
|
||||||
|
app.run()
|
||||||
|
|
||||||
|
# initialize_system()
|
||||||
+8
-149
@@ -1,153 +1,12 @@
|
|||||||
# coding:utf-8
|
# coding:utf-8
|
||||||
import os
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk, filedialog, messagebox
|
from core.main_entry import MainEntry
|
||||||
import configparser
|
|
||||||
from core.main_ui import MainWindow
|
|
||||||
import config as sdConstants
|
|
||||||
from core.qmt import qmtv
|
|
||||||
|
|
||||||
class ConfigWindow:
|
# 这是应用的启动入口程序,负责初始化并启动主窗口。
|
||||||
def __init__(self, root):
|
# 它创建一个Tkinter根窗口,实例化主窗口类MainBoardWindow,
|
||||||
self.root = root
|
# 并调用其run方法启动主事件循环。
|
||||||
self.root.title("系统配置")
|
if __name__ == "__main__":
|
||||||
self.root.geometry("500x250")
|
import tkinter as tk
|
||||||
self.root.resizable(False, False)
|
|
||||||
|
|
||||||
# 居中显示
|
|
||||||
self.root.withdraw() # 先隐藏窗口
|
|
||||||
self.root.update_idletasks()
|
|
||||||
x = (self.root.winfo_screenwidth() // 2) - (500 // 2)
|
|
||||||
y = (self.root.winfo_screenheight() // 2) - (250 // 2)
|
|
||||||
self.root.geometry(f"500x250+{x}+{y}")
|
|
||||||
self.root.deiconify() # 再显示窗口
|
|
||||||
|
|
||||||
self.miniQMTPath = tk.StringVar()
|
|
||||||
self.account_no = tk.StringVar()
|
|
||||||
|
|
||||||
self.create_widgets()
|
|
||||||
|
|
||||||
def create_widgets(self):
|
|
||||||
# 创建主框架
|
|
||||||
main_frame = ttk.Frame(self.root, padding="20")
|
|
||||||
main_frame.pack(fill=tk.BOTH, expand=True)
|
|
||||||
|
|
||||||
# miniQMT路径配置
|
|
||||||
path_frame = ttk.Frame(main_frame)
|
|
||||||
path_frame.pack(fill=tk.X, pady=5)
|
|
||||||
|
|
||||||
path_label = ttk.Label(path_frame, text="miniQMT路径:")
|
|
||||||
path_label.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
path_entry = ttk.Entry(path_frame, textvariable=self.miniQMTPath, width=40)
|
|
||||||
path_entry.pack(side=tk.LEFT, padx=(10, 5), fill=tk.X, expand=True)
|
|
||||||
|
|
||||||
browse_btn = ttk.Button(path_frame, text="浏览", command=self.browse_folder)
|
|
||||||
browse_btn.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
# 资金账号配置
|
|
||||||
account_frame = ttk.Frame(main_frame)
|
|
||||||
account_frame.pack(fill=tk.X, pady=5)
|
|
||||||
|
|
||||||
account_label = ttk.Label(account_frame, text="资金账号:")
|
|
||||||
account_label.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
account_entry = ttk.Entry(account_frame, textvariable=self.account_no, width=40)
|
|
||||||
account_entry.pack(side=tk.LEFT, padx=(10, 0))
|
|
||||||
|
|
||||||
# 说明文本
|
|
||||||
info_label = ttk.Label(
|
|
||||||
main_frame,
|
|
||||||
text="请配置miniQMT的userdata_mini路径和资金账号\n路径示例: D:/Programs/DTQMT/userdata_mini",
|
|
||||||
foreground="gray"
|
|
||||||
)
|
|
||||||
info_label.pack(pady=10)
|
|
||||||
|
|
||||||
# 按钮框架
|
|
||||||
button_frame = ttk.Frame(main_frame)
|
|
||||||
button_frame.pack(fill=tk.X, pady=10)
|
|
||||||
|
|
||||||
save_btn = ttk.Button(button_frame, text="保存配置", command=self.save_config)
|
|
||||||
save_btn.pack(side=tk.RIGHT)
|
|
||||||
|
|
||||||
cancel_btn = ttk.Button(button_frame, text="取消", command=self.root.destroy)
|
|
||||||
cancel_btn.pack(side=tk.RIGHT, padx=(0, 10))
|
|
||||||
|
|
||||||
def browse_folder(self):
|
|
||||||
folder_selected = filedialog.askdirectory()
|
|
||||||
if folder_selected:
|
|
||||||
self.miniQMTPath.set(folder_selected)
|
|
||||||
|
|
||||||
def save_config(self):
|
|
||||||
mini_qmt_path = self.miniQMTPath.get().strip()
|
|
||||||
account_number = self.account_no.get().strip()
|
|
||||||
|
|
||||||
# 检查miniQMT路径
|
|
||||||
if not mini_qmt_path:
|
|
||||||
messagebox.showerror("错误", "请选择miniQMT路径")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.exists(mini_qmt_path):
|
|
||||||
messagebox.showerror("错误", "miniQMT路径不存在")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 检查账号
|
|
||||||
if not account_number:
|
|
||||||
messagebox.showerror("错误", "请输入资金账号")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 保存配置
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config['config'] = {
|
|
||||||
'miniQMTPath': mini_qmt_path.replace('\\', '/'),
|
|
||||||
'account_no': account_number,
|
|
||||||
'log_level': 'INFO'
|
|
||||||
}
|
|
||||||
|
|
||||||
config_path = sdConstants.get_config_path()
|
|
||||||
try:
|
|
||||||
with open(config_path, 'w') as configfile:
|
|
||||||
config.write(configfile)
|
|
||||||
messagebox.showinfo("成功", "配置已保存")
|
|
||||||
self.root.destroy()
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("错误", f"保存配置失败: {str(e)}")
|
|
||||||
|
|
||||||
def check_and_create_config():
|
|
||||||
"""检查配置文件,如果不存在则打开配置窗口"""
|
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
config_window = ConfigWindow(root)
|
app = MainEntry(root)
|
||||||
root.mainloop()
|
app.run()
|
||||||
|
|
||||||
def initialize_system():
|
|
||||||
"""初始化系统"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
# 初始化配置
|
|
||||||
if sdConstants.exist_config() and sdConstants.initConfig():
|
|
||||||
# 初始化qmtv
|
|
||||||
qmtv.init_qmtv()
|
|
||||||
connected = qmtv.connect()
|
|
||||||
if connected:
|
|
||||||
# 连接成功,启动主窗口
|
|
||||||
window = MainWindow(sdConstants.log_level)
|
|
||||||
window.run()
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
option = messagebox.askokcancel("连接失败", "QMT连接失败,请检查")
|
|
||||||
if option:
|
|
||||||
check_and_create_config()
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
option = messagebox.askokcancel("错误", "请检查配置")
|
|
||||||
if option:
|
|
||||||
check_and_create_config()
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("错误", f"系统初始化失败: {str(e)}")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
initialize_system()
|
|
||||||
Reference in New Issue
Block a user