This commit is contained in:
2026-06-12 16:25:41 +08:00
parent ef4c1cca32
commit 2d8a0c3bca
23 changed files with 2904 additions and 525 deletions
+19 -187
View File
@@ -1,191 +1,23 @@
# coding:utf-8
import os
"""
启动入口 — 自动探测 QMT 环境。
默认使用 Tkinter UI,使用 --flet 参数切换到 Flet (Flutter) UI。
"""
import sys
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import configparser
import config as sdConstants
class ConfigWindow:
def __init__(self, root):
self.root = root
self.root.title("系统配置")
self.root.geometry("500x300")
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) - (300 // 2)
self.root.geometry(f"500x300+{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))
# 模拟模式复选框
self.use_simulated = tk.BooleanVar(value=False)
simulated_check = ttk.Checkbutton(
main_frame,
text="使用模拟交易模式(无需真实 QMT 连接)",
variable=self.use_simulated
)
simulated_check.pack(fill=tk.X, pady=5)
# 说明文本
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,
'use_simulated_qmt': str(self.use_simulated.get()),
'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 resolve_simulated_mode() -> bool:
"""确定是否使用模拟模式(CLI > 配置文件 > 默认 real"""
if '--simulated' in sys.argv:
print('[配置] 命令行指定: 模拟交易模式')
return True
if sdConstants.exist_config():
sdConstants.initConfig()
if sdConstants.use_simulated_qmt:
print('[配置] 配置文件指定: 模拟交易模式')
return True
print('[配置] 默认: 真实交易模式')
return False
def initialize_system():
"""初始化系统"""
simulated = resolve_simulated_mode()
sdConstants.use_simulated_qmt = simulated
try:
if simulated:
from core.qmt_dummy import qmtv as selected_qmtv
print("[模拟模式] 使用模拟交易器")
sdConstants.miniQMTPath = '/dummy/path'
sdConstants.account_no = 'DUMMY_ACCOUNT'
sdConstants.log_level = 'INFO'
selected_qmtv.init_qmtv()
selected_qmtv.connect()
from core.main_ui import MainWindow
window = MainWindow(sdConstants.log_level)
window.run()
else:
from core.qmt_real import qmtv as selected_qmtv
while True:
if sdConstants.exist_config() and sdConstants.initConfig():
selected_qmtv.init_qmtv()
connected = selected_qmtv.connect()
if connected:
from core.main_ui import MainWindow
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()
if '--flet2' in sys.argv:
from core.ui.flet.app_v2 import run
run()
elif '--flet' in sys.argv:
from core.ui.flet.app import run
run()
else:
from tkinter import messagebox
from core.ui.tkinter.splash import SplashWindow
try:
window = SplashWindow().run()
if window:
window.run()
except Exception as e:
messagebox.showerror("错误", f"系统初始化失败: {str(e)}")