![]() ![]() ![]() import jsonimport osimport platformimport subprocessimport threadingimport wximport wx.gizmos as gizmos#from common import LogEventfrom config import DATA_DIR_QUOTES, DATA_TASKSclass StrategyPanel(wx.Panel): def __init__(self, parent): #from core.backtrader_extends.task import local_tasks super(StrategyPanel, self).__init__(parent) items = [ ] self.init_ui() def init_ui(self): sizer = wx.BoxSizer(wx.VERTICAL) # 策略列表標(biāo)題 title = wx.StaticText(self, label="策略管理", style=wx.ALIGN_CENTER) title.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) sizer.Add(title, 0, wx.EXPAND | wx.ALL, 5) # 創(chuàng)建普通的 TreeCtrl 控件 self.tree = wx.TreeCtrl(self, style= wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_ROW_LINES | wx.WANTS_CHARS ) # 設(shè)置根節(jié)點 root = self.tree.AddRoot("所有策略") # 綁定雙擊事件 #self.tree_list.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_item_double_click) self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.on_tree_select) # 綁定右鍵菜單事件 self.tree.Bind(wx.EVT_CONTEXT_MENU, self.on_context_menu) # 加載策略數(shù)據(jù) self.load_strategies() sizer.Add(self.tree, 1, wx.EXPAND | wx.ALL, 5) # 策略操作按鈕 btn_sizer = wx.BoxSizer(wx.HORIZONTAL) self.open_btn = wx.Button(self, label="策略目錄") self.reload_btn = wx.Button(self, label="重新加載") btn_sizer.Add(self.open_btn, 0, wx.ALIGN_LEFT |wx.RIGHT, 5) btn_sizer.Add(self.reload_btn, 0, wx.ALIGN_LEFT | wx.RIGHT, 5) sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10) self.SetSizer(sizer) # 綁定事件 self.open_btn.Bind(wx.EVT_BUTTON, self.open_task_dir) self.reload_btn.Bind(wx.EVT_BUTTON, self.reload_tasks) def on_context_menu(self, event): print('on_context..') """右鍵菜單事件處理""" pos = event.GetPosition() item, flags = self.tree.HitTest(pos) if item.IsOk(): self.tree.SelectItem(item) # 選中右鍵點擊的節(jié)點 self.selected_item = item # 創(chuàng)建菜單 menu = wx.Menu() download_item = menu.Append(wx.ID_ANY, "下載策略到本地") self.Bind(wx.EVT_MENU, self.on_download, download_item) self.tree.PopupMenu(menu) menu.Destroy() def on_download(self, event): """下載菜單項點擊事件""" if not hasattr(self, 'selected_item') or not self.selected_item.IsOk(): wx.MessageBox("請先選擇一個策略", "錯誤", wx.OK | wx.ICON_ERROR) return # 獲取策略ID(示例數(shù)據(jù),需根據(jù)實際情況實現(xiàn)) item = self.selected_item # print(item) data = self.tree.GetItemPyData(item) strategy_id = data['id'] if not strategy_id: wx.MessageBox("無法獲取策略ID", "錯誤", wx.OK | wx.ICON_ERROR) return # 在后臺線程執(zhí)行網(wǎng)絡(luò)請求 print(strategy_id) threading.Thread(target=self.fetch_strategy, args=(strategy_id,)).start() def fetch_strategy(self, strategy_id): """執(zhí)行網(wǎng)絡(luò)請求并處理響應(yīng)""" try: from common.api import fetch_strategy data,code = fetch_strategy(strategy_id) # 在主線程更新UI if code != 200: wx.CallAfter(wx.MessageBox, data['message'], "下載失敗", wx.OK | wx.ICON_ERROR) else: data['id'] = strategy_id wx.CallAfter(self.save_strategy, data) except Exception as e: wx.CallAfter(wx.MessageBox, f"發(fā)生異常: {str(e)}", "錯誤", wx.OK | wx.ICON_ERROR) def save_strategy(self, data): from config import DATA_TASKS from core.task import json_to_task, task_to_toml, dict_to_task try: task = dict_to_task(data) toml_data = task_to_toml(task) path = DATA_TASKS.joinpath(f"{data['name']}_{data['id']}.toml").resolve() with open(path, "w") as f: f.write(toml_data) wx.MessageBox(f"保存{path}成功!", "提示", wx.OK | wx.ICON_INFORMATION) except IOError as e: wx.MessageBox(f"文件保存失敗: {str(e)}", "錯誤", wx.OK | wx.ICON_ERROR) def on_tree_select(self, event): """處理樹節(jié)點選擇事件""" item = event.GetItem() #print(item) data = self.tree.GetItemPyData(item) if data and 'id' in data.keys(): from config import HOST url = f'{HOST}/strategy/{data["id"]}' self.Parent.Parent.show_page(url,"策略詳情") def reload_tasks(self, event): self.load_strategies() wx.MessageBox('重新加載策略列表成功!') def open_task_dir(self, event): # 指定要打開的目錄路徑 from config import DATA_TASKS # 檢查目錄是否存在 target_dir = str(DATA_TASKS.resolve()) if not os.path.exists(str(DATA_TASKS.resolve())): wx.MessageBox(f"目錄不存在: {target_dir}", "錯誤", wx.OK | wx.ICON_ERROR) return # 根據(jù)不同操作系統(tǒng)打開目錄 system = platform.system() try: if system == "Windows": os.startfile(target_dir) elif system == "Darwin": # macOS os.system(f'open "{target_dir}"') else: # Linux os.system(f'xdg-open "{target_dir}"') except Exception as e: wx.MessageBox(f"無法打開目錄: {str(e)}", "錯誤", wx.OK | wx.ICON_ERROR) def on_item_double_click(self, event): item = event.GetItem() item_data = self.tree.GetItemPyData(item) # 修改為GetItemPyData if item_data and item_data["type"] == "strategy": data = item_data["data"] file_path = DATA_TASKS.joinpath(data['name'] + '.toml') self.open_file_with_default_editor(str(file_path.resolve())) # wx.PostEvent(self.GetParent(), LogEvent( # message=f"雙擊策略: {strategy['name']}" # )) def fetch_all_strategies(self): from common.api import fetch_strategies try: # 發(fā)送HTTP請求 data = fetch_strategies() # 更新UI wx.CallAfter(self.update_all_strategies, data) except (json.JSONDecodeError, ValueError) as e: wx.CallAfter(self.show_error, f"數(shù)據(jù)錯誤: {str(e)}") except Exception as e: wx.CallAfter(self.show_error, f"未知錯誤: {str(e)}") def fetch_my_strategies(self): from common.api import fetch_my_strategies try: # 發(fā)送HTTP請求 data = fetch_my_strategies() # 更新UI wx.CallAfter(self.update_ui, data) except (json.JSONDecodeError, ValueError) as e: wx.CallAfter(self.show_error, f"數(shù)據(jù)錯誤: {str(e)}") except Exception as e: wx.CallAfter(self.show_error, f"未知錯誤: {str(e)}") def update_all_strategies(self, strategies): count_public = 0 count_vip = 0 count_official = 0 count_points = 0 for strategy in strategies: #print(strategy) if strategy['is_vip_only'] == True: item = self.tree.AppendItem(self.vip_only_node, strategy["name"]) self.tree.SetItemPyData(item, strategy) # 修改為SetItemPyData count_vip += 1 if strategy['is_official'] == True: item = self.tree.AppendItem(self.official_node, strategy["name"]) self.tree.SetItemPyData(item, strategy) # 修改為SetItemPyData count_official += 1 if strategy['access_type'] == 'points': item = self.tree.AppendItem(self.points_node, strategy["name"]) self.tree.SetItemPyData(item, strategy) # 修改為SetItemPyData count_points += 1 if strategy['access_type'] == 'public': item = self.tree.AppendItem(self.public_node, strategy["name"]) # self.tree.SetItemText(item, strategy["status"], 1) # self.tree.SetItemText(item, f"{strategy.get('return', 0):.2f}", 2) # self.tree.SetItemText(item, str(strategy.get("position", 0)), 3) self.tree.SetItemPyData(item, strategy) # 修改為SetItemPyData count_public += 1 text = self.tree.GetItemText(self.official_node) + f'({count_official})' self.tree.SetItemText(self.official_node, text) text = self.tree.GetItemText(self.vip_only_node) + f'({count_vip})' self.tree.SetItemText(self.vip_only_node, text) text = self.tree.GetItemText(self.public_node) + f'({count_public})' self.tree.SetItemText(self.public_node, text) text = self.tree.GetItemText(self.points_node) + f'({count_points})' self.tree.SetItemText(self.points_node, text) def update_ui(self, strategies): count = len(strategies) text = self.tree.GetItemText(self.my_strategies) + f'({count})' self.tree.SetItemText(self.my_strategies, text) for strategy in strategies: item = self.tree.AppendItem(self.my_strategies, strategy["name"]) # self.tree_list.SetItemText(item, strategy["status"], 1) # self.tree_list.SetItemText(item, f"{strategy.get('return', 0):.2f}", 2) # self.tree_list.SetItemText(item, str(strategy.get("position", 0)), 3) self.tree.SetItemPyData(item, strategy) # 修改為SetItemPyData def load_strategies(self): """加載策略到樹形列表""" self.tree.DeleteAllItems() # 添加根節(jié)點(TreeListCtrl需要根節(jié)點) root = self.tree.AddRoot("所有策略") #root = self.tree.GetRootItem() # 添加分類節(jié)點 self.official_node = self.tree.AppendItem(root, "實驗室策略") self.vip_only_node = self.tree.AppendItem(root, "星球會員專屬策略") self.public_node = self.tree.AppendItem(root, "公開策略") self.points_node = self.tree.AppendItem(root, "積分查看策略") self.my_strategies = self.tree.AppendItem(root, "我創(chuàng)建的策略") self.local_node = self.tree.AppendItem(root, "本地策略") thread = threading.Thread(target=self.fetch_my_strategies()) thread.start() thread_all = threading.Thread(target=self.fetch_all_strategies()) thread_all.start() # 展開所有節(jié)點 self.tree.ExpandAll() def open_file_with_default_editor(self, file_path): """用系統(tǒng)默認(rèn)編輯器打開文件""" if not os.path.exists(file_path): wx.MessageBox(f"文件不存在: {file_path}", "錯誤", wx.OK | wx.ICON_ERROR) return try: if platform.system() == "Windows": os.startfile(file_path) elif platform.system() == "Darwin": # macOS subprocess.run(["open", file_path]) else: # Linux subprocess.run(["xdg-open", file_path]) except Exception as e: wx.MessageBox(f"無法打開文件: {str(e)}", "錯誤", wx.OK | wx.ICON_ERROR) AI量化實驗室 星球,已經(jīng)運行三年多,1600+會員。 aitrader代碼,因子表達(dá)式引擎、遺傳算法(Deap)因子挖掘引擎等,支持vnpy,qlib,backtrader和bt引擎,內(nèi)置多個年化30%+的策略,每周五迭代一次,代碼和數(shù)據(jù)在星球全部開源。 擴(kuò)展 · 歷史文章 |
|