diff --git a/core/objects.py b/core/objects.py new file mode 100644 index 0000000..2156859 --- /dev/null +++ b/core/objects.py @@ -0,0 +1,7 @@ +from core.strategy_db import TradeTarget + + +class GridFixData: + def __init__(self, grid_index, tradeTarget:TradeTarget): + self.grid_index = grid_index + self.tradeTarget = tradeTarget diff --git a/core/ui.py b/core/ui.py index 38bcac5..4f2812b 100644 --- a/core/ui.py +++ b/core/ui.py @@ -106,7 +106,8 @@ class TradeTargetUI: command=self.add_trade_target, 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="🛠 网格修正", 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) # 添加分隔符 ttk.Separator(toolbar_frame, orient='vertical').pack(side=tk.LEFT, fill=tk.Y, padx=10) @@ -829,6 +830,201 @@ class TradeTargetUI: 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): + """网格修正功能""" + target = self.get_selected_target() + if not target: + return + + # 创建网格修正窗口 + self.create_grid_correction_window(target) + + def create_grid_correction_window(self, target: TradeTarget): + """创建网格修正窗口""" + # 创建顶层窗口 + correction_window = tk.Toplevel(self.root) + correction_window.title(f"网格修正 - {target.stock_code} ({target.stock_name})") + correction_window.geometry("500x400") + correction_window.resizable(False, False) + + # 设置窗口模态 + correction_window.transient(self.root) + correction_window.grab_set() + + # 居中显示 + self.root.update_idletasks() + x = self.root.winfo_x() + (self.root.winfo_width() // 2) - 250 + y = self.root.winfo_y() + (self.root.winfo_height() // 2) - 200 + correction_window.geometry(f"500x400+{x}+{y}") + + # 创建主框架 + main_frame = ttk.Frame(correction_window, padding=20) + main_frame.pack(fill=tk.BOTH, expand=True) + + # 显示股票信息 + info_frame = ttk.LabelFrame(main_frame, text="标的详情", padding=10) + info_frame.pack(fill=tk.X, pady=(0, 10)) + + ttk.Label(info_frame, text=f"股票代码: {target.stock_code}").grid(row=0, column=0, sticky=tk.W, pady=2) + ttk.Label(info_frame, text=f"股票名称: {target.stock_name}").grid(row=0, column=1, sticky=tk.W, padx=(20, 0), pady=2) + + # 创建修正选项框架 + options_frame = ttk.LabelFrame(main_frame, text="修正选项", padding=10) + options_frame.pack(fill=tk.X, pady=(0, 10)) + + # 网格序号 + grid_index_frame = ttk.Frame(options_frame) + grid_index_frame.pack(fill=tk.X, pady=5) + + ttk.Label(grid_index_frame, text="网格序号:", width=12).pack(side=tk.LEFT) + + # 网格序号调整控件 + grid_index_var = tk.IntVar(value=getattr(target, 'grid_index')) + + # 当前持仓量 + position_frame = ttk.Frame(options_frame) + position_frame.pack(fill=tk.X, pady=5) + + current_position_value = getattr(target, 'current_position') + ttk.Label(position_frame, text="当前持仓量:", width=12).pack(side=tk.LEFT) + ttk.Label(position_frame, text=str(current_position_value), width=10, anchor=tk.CENTER).pack(side=tk.LEFT, padx=5) + + # 需求持仓量 + required_position_frame = ttk.Frame(options_frame) + required_position_frame.pack(fill=tk.X, pady=5) + + grid_index_value = getattr(target, 'grid_index') + required_position = grid_index_value * sfgrid_constants.grid_volume + ttk.Label(required_position_frame, text="需求持仓量:", width=12).pack(side=tk.LEFT) + required_position_label = ttk.Label(required_position_frame, text=str(required_position), width=10, anchor=tk.CENTER) + required_position_label.pack(side=tk.LEFT, padx=5) + + # 持仓量状态提示 + position_status_frame = ttk.Frame(options_frame) + position_status_frame.pack(fill=tk.X, pady=5) + + position_status_label = ttk.Label(position_status_frame, text="", foreground="red") + position_status_label.pack(side=tk.LEFT, padx=(12, 0)) + + # 初始化持仓量状态 + self.update_position_status(current_position_value, required_position, position_status_label) + + # 网格序号显示和按钮 + grid_index_label = ttk.Label(grid_index_frame, textvariable=grid_index_var, width=10, anchor=tk.CENTER) + grid_index_label.pack(side=tk.LEFT, padx=5) + + # 减少按钮 + ttk.Button(grid_index_frame, text="-", width=3, + command=lambda: self.decrease_grid_index(grid_index_var, target, required_position_label, position_status_label)).pack(side=tk.LEFT, padx=(5, 5)) + + # 增加按钮 + ttk.Button(grid_index_frame, text="+", width=3, + command=lambda: self.increase_grid_index(grid_index_var, len(sfgrid_constants.grid_price)-1, target, required_position_label, position_status_label)).pack(side=tk.LEFT, padx=(5, 0)) + + # 当前价格(实时更新) + price_frame = ttk.Frame(options_frame) + price_frame.pack(fill=tk.X, pady=5) + + ttk.Label(price_frame, text="当前价格:", width=12).pack(side=tk.LEFT) + current_price_var = tk.StringVar(value="-") + current_price_label = ttk.Label(price_frame, textvariable=current_price_var, width=10, anchor=tk.CENTER) + current_price_label.pack(side=tk.LEFT, padx=5) + + # 保存按钮框架 + button_frame = ttk.Frame(main_frame) + button_frame.pack(fill=tk.X, pady=(10, 0)) + + # 保存按钮 + ttk.Button(button_frame, text="确认修正", + command=lambda: self.save_grid_correction(correction_window, target, grid_index_var.get())).pack(side=tk.RIGHT, padx=5) + + # 取消按钮 + ttk.Button(button_frame, text="取消", + command=correction_window.destroy).pack(side=tk.RIGHT, padx=5) + + # 监听市场数据更新 + def on_market_data_update(updated_target: TradeTarget): + if updated_target.get_id() == target.get_id(): + current_price_var.set(f"{updated_target.market_price:.3f}" if updated_target.market_price else "-") + + # 订阅市场数据更新事件 + eBus.event_bus.subscribe(eBus.MarketDataUpdate, on_market_data_update) + + # 窗口关闭时取消订阅 + def on_window_close(): + if eBus.MarketDataUpdate in eBus.event_bus.listeners and on_market_data_update in eBus.event_bus.listeners[eBus.MarketDataUpdate]: + eBus.event_bus.listeners[eBus.MarketDataUpdate].remove(on_market_data_update) + correction_window.destroy() + + correction_window.protocol("WM_DELETE_WINDOW", on_window_close) + + # 初始化当前价格 + if target.market_price is not None: + current_price_var.set(f"{target.market_price:.3f}") + + def update_position_status(self, current_position: int, required_position: int, status_label: ttk.Label): + """更新持仓量状态提示""" + if current_position >= required_position: + status_label.config(text="持仓量充足", foreground="green") + else: + shortage = required_position - current_position + status_label.config(text=f"还需补充 {shortage} 手仓位", foreground="red") + + def save_grid_correction(self, window, target: TradeTarget, new_grid_index: int): + """保存网格修正""" + # 更新网格序号 + setattr(target, 'grid_index', new_grid_index) + + # 重新计算需求持仓量 + required_position = new_grid_index * sfgrid_constants.grid_volume + + # 检查持仓量是否满足要求 + current_position = getattr(target, 'current_position') + if current_position < required_position: + shortage = required_position - current_position + result = messagebox.askyesno( + "持仓量不足", + f"当前持仓量({current_position}手)小于需求持仓量({required_position}手)\n" + f"还需补充 {shortage} 手仓位,是否继续保存?" + ) + if not result: + return + + # 保存到数据库(这里需要发布事件让控制器处理) + # TODO: 发布保存事件到控制器 + + # 关闭窗口 + window.destroy() + + # 添加日志 + self.add_log(LogLevel.INFO, f"网格修正已保存: {target.stock_code} - {target.stock_name}, 网格序号: {new_grid_index}") + def run(self): """运行程序""" - self.root.mainloop() \ No newline at end of file + self.root.mainloop() + + def decrease_grid_index(self, grid_index_var: tk.IntVar, target: TradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label): + """减少网格序号""" + current_value = grid_index_var.get() + if current_value > 0: + grid_index_var.set(current_value - 1) + # 同步更新需求持仓量和持仓状态 + self.update_required_position_and_status(grid_index_var.get(), target, required_position_label, position_status_label) + + def increase_grid_index(self, grid_index_var: tk.IntVar, max_index: int, target: TradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label): + """增加网格序号""" + current_value = grid_index_var.get() + if current_value < max_index: + grid_index_var.set(current_value + 1) + # 同步更新需求持仓量和持仓状态 + self.update_required_position_and_status(grid_index_var.get(), target, required_position_label, position_status_label) + + def update_required_position_and_status(self, grid_index: int, target: TradeTarget, required_position_label: ttk.Label, position_status_label: ttk.Label): + """更新需求持仓量和持仓状态""" + # 计算需求持仓量 + required_position = grid_index * sfgrid_constants.grid_volume + required_position_label.config(text=str(required_position)) + + # 更新持仓量状态 + current_position = getattr(target, 'current_position') + self.update_position_status(current_position, required_position, position_status_label)