import copy import threading import time import wx import local_api from local_api.limit_up_manager import KPLLimitUpDataManager from local_api.log_module import log_export from local_api.util import tool, gui_util APP_TITLE = "低吸" __symbol_name_dict = {} # 系统启动时间 system_start_time = tool.get_now_time_str() def get_symbols_names(symbols): request_symbols = [] name_dict = {} for symbol in symbols: if symbol not in __symbol_name_dict: request_symbols.append(symbol) else: name_dict[symbol] = __symbol_name_dict.get(symbol) name_dict_temp = local_api.trade_api.get_symbol_names(request_symbols) for symbol in name_dict_temp: name_dict[symbol] = name_dict_temp[symbol] return name_dict class MainFrame(wx.Frame): mark_lines = {} def __init__(self): """ 初始化函数 """ wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE, size=(1000, 500)) self.__init_view() self.__init_data() def __init_view(self): root_sizer = wx.BoxSizer(wx.HORIZONTAL) left_sizer = wx.BoxSizer(wx.VERTICAL) right_sizer = wx.BoxSizer(wx.VERTICAL) root_sizer.Add(left_sizer, 1, wx.EXPAND | wx.TOP | wx.LEFT | wx.BOTTOM, 5) root_sizer.Add(right_sizer, 0, wx.EXPAND | wx.ALL, 5) self.SetSizer(root_sizer) self.system_log_ctrl = wx.TextCtrl(self, size=wx.Size(250, -1), style=wx.TE_MULTILINE | wx.TE_READONLY) self.system_log_ctrl.AppendText("---系统日志区域---") right_sizer.Add(self.system_log_ctrl, 1) self.trade_log_ctrl = wx.TextCtrl(self, size=wx.Size(250, -1), style=wx.TE_MULTILINE | wx.TE_READONLY) self.trade_log_ctrl.AppendText("---交易日志区域---") right_sizer.Add(self.trade_log_ctrl, 1) self.main_panel = wx.Panel(self, size=wx.Size(-1, -1)) self.main_panel.SetBackgroundColour(wx.Colour(255, 255, 255)) left_sizer.Add(self.main_panel, 1, wx.EXPAND | wx.TOP | wx.LEFT | wx.BOTTOM, 5) self.SetBackgroundColour(wx.Colour(225, 225, 225)) # -------添加操作按钮-------- panel_sizer = wx.BoxSizer(wx.VERTICAL) # 板块与涨停代码数量 sizer = wx.BoxSizer(wx.HORIZONTAL) self.btn_request_blocks = wx.Button(self.main_panel, 101, "刷新板块") sizer.Add(self.btn_request_blocks, 0, wx.TOP | wx.LEFT, 5) self.label_block_info = wx.StaticText(self.main_panel) sizer.Add(self.label_block_info, 0, wx.TOP | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) panel_sizer.Add(sizer) sizer = wx.BoxSizer(wx.HORIZONTAL) self.btn_repaire_limit_up_task = wx.Button(self.main_panel, 102, "修复涨停") sizer.Add(self.btn_repaire_limit_up_task, 0, wx.TOP | wx.LEFT, 5) self.label_limit_up_info = wx.StaticText(self.main_panel, size=wx.Size(100, -1)) sizer.Add(self.label_limit_up_info, 0, wx.TOP | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) self.label_limit_up_info.SetLabelText("涨停列表更新:") panel_sizer.Add(sizer) self.list_ctrl_position = wx.ListCtrl(self.main_panel, style=wx.LC_REPORT, size=wx.Size(-1, 300)) panel_sizer.Add(wx.StaticText(self.main_panel, label="持仓:"), 0, wx.LEFT | wx.TOP, 5) panel_sizer.Add(self.list_ctrl_position, 0, wx.EXPAND | wx.ALL, 5) # (p["symbol"], p["amount"], p["volume"], p["available"], p["cost"], p["price"],) self.list_ctrl_position.InsertColumn(0, "代码") self.list_ctrl_position.InsertColumn(1, "名称") self.list_ctrl_position.InsertColumn(2, "持仓金额") self.list_ctrl_position.InsertColumn(3, "持仓数量") self.list_ctrl_position.InsertColumn(4, "可用数量") self.list_ctrl_position.InsertColumn(5, "持仓成本") self.list_ctrl_position.InsertColumn(6, "现价") self.list_ctrl_position.InsertColumn(7, "委卖量") self.list_ctrl_position.InsertColumn(8, "委卖价格") self.main_panel.SetSizer(panel_sizer) # 卖出面板 sell_panel = wx.Panel(self.main_panel, size=wx.Size(-1, 50)) sell_pannel_sizer = wx.BoxSizer(wx.HORIZONTAL) sell_panel.SetSizer(sell_pannel_sizer) sizer1 = wx.BoxSizer(wx.VERTICAL) sizer1.Add(wx.StaticText(sell_panel, label="代码:")) self.label_sell_code = wx.StaticText(sell_panel, label="000000", size=wx.Size(100, -1)) sizer1.Add(self.label_sell_code) sell_pannel_sizer.Add(sizer1) sizer1 = wx.BoxSizer(wx.VERTICAL) sizer1.Add(wx.StaticText(sell_panel, label="可用持仓:")) self.label_sell_avaiable_volume = wx.StaticText(sell_panel, label="0", size=wx.Size(70, -1)) sizer1.Add(self.label_sell_avaiable_volume) sell_pannel_sizer.Add(sizer1) sizer1 = wx.BoxSizer(wx.VERTICAL) sizer1.Add(wx.StaticText(sell_panel, label="卖出量:")) sizer_volume = wx.BoxSizer(wx.HORIZONTAL) self.edit_sell_volume = wx.TextCtrl(sell_panel, size=wx.Size(70, -1)) sizer_volume.Add(self.edit_sell_volume, 0, wx.RIGHT, 10) gui_util.GuiViewManager.create_sell_volume_percent(sizer_volume, sell_panel, lambda x: self.edit_sell_volume.SetValue(str(int( self.label_sell_avaiable_volume.GetLabel()) // x // 100 * 100))) sizer1.Add(sizer_volume) sell_pannel_sizer.Add(sizer1) sizer1 = wx.BoxSizer(wx.HORIZONTAL) sizer1.Add(wx.StaticText(sell_panel), 1) self.btn_cancel_sell = wx.Button(sell_panel, label="撤卖", size=wx.Size(50, 30)) sizer1.Add(self.btn_cancel_sell, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10) self.btn_sell = wx.Button(sell_panel, label="卖出", size=wx.Size(50, 30)) sizer1.Add(self.btn_sell, 0, wx.ALIGN_CENTER_VERTICAL, 0) sell_pannel_sizer.Add(sizer1, 1, wx.EXPAND) panel_sizer.Add(sell_panel, 0, wx.ALL | wx.EXPAND, 5) self.btn_request_blocks.Bind(wx.EVT_BUTTON, self.__refresh_blocks) self.btn_repaire_limit_up_task.Bind(wx.EVT_BUTTON, self.__repaire_limit_up_task) self.btn_sell.Bind(wx.EVT_BUTTON, self.__sell) on_item_selected = lambda event: self.__show_sell_data(event.GetIndex()) self.list_ctrl_position.Bind(wx.EVT_LIST_ITEM_SELECTED, on_item_selected) self.btn_cancel_sell.Bind(wx.EVT_BUTTON, lambda x: self.__cancel_order()) # 设置快捷键 entries = [ # wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('W'), 901), wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_F4, 901), wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_F5, 902) ] # Create an accelerator table accel_table = wx.AcceleratorTable(entries) self.SetAcceleratorTable(accel_table) self.Bind(wx.EVT_MENU, self.quick_sell, id=901) self.Bind(wx.EVT_MENU, lambda x: self.__cancel_order(), id=902) self.__start_task() def quick_sell(self, event): self.__sell(event) def __cancel_order(self): for symbol in self.delegates_dict: for d in self.delegates_dict[symbol]: local_api.trade_api.cancel_order(d[1], d[2], blocking=False) def __show_sell_data(self, index): if index < 0: return self.label_sell_code.SetLabel(self.positions[index][0]) available_volume = self.__compute_available_volume(self.positions[index]) self.label_sell_avaiable_volume.SetLabel(str(available_volume)) sell_percent = gui_util.GuiViewManager.get_sell_volume_percent() self.edit_sell_volume.SetValue(str(available_volume // sell_percent // 100 * 100)) def __refresh_blocks(self, event): def update_blocks(): local_api.update_blocks() wx.CallAfter(lambda: self.btn_request_blocks.SetLabel("刷新板块")) self.btn_request_blocks.SetLabel("刷新板块...") threading.Thread(target=update_blocks, daemon=True).start() def __repaire_limit_up_task(self, event): KPLLimitUpDataManager().repaire_task() wx.MessageBox("修复成功") def __sell(self, event): volume = self.edit_sell_volume.GetValue() if not volume.isdigit(): wx.MessageBox("量输入错误") return print("卖出量:", volume) symbol = self.label_sell_code.GetLabel() code = symbol.split(".")[1] tick = local_api.latest_tick_dict.get(code) # 收盘价,现价 if tick: price, pre_price = tick[2], tick[1] price = tool.get_buy_min_price(price) result = local_api.trade_api.sell(code, int(volume), price) print("卖出结果:", result) print("持仓:", local_api.trade_api.position_by_symbol(symbol)) else: wx.MessageBox("没有获取到tick数据") def __compute_available_volume(self, data): """ 计算可用量:总量-委托量 :param data: :return: """ available_volume = self.__compute_total_volume(data) # 委托量 dvolume = 0 if data[0] in self.delegates_dict: delegates_list = self.delegates_dict[data[0]] if delegates_list: dvolume = sum([x[3] for x in delegates_list]) available_volume -= dvolume return available_volume def __compute_total_volume(self, data): """ 计算总量 :param data: :return: """ total_volume = copy.deepcopy(data[2]) if data[0] in self.deal_dict: deal_list = self.deal_dict[data[0]] deal_volume = 0 if deal_list: for d in deal_list: if d[1] == 2 and tool.trade_time_sub(d[5], system_start_time) > 0: deal_volume += d[3] total_volume -= deal_volume return total_volume def __start_task(self): def __show_blocks(): while True: try: today_count, before_count = local_api.get_blocks_count_info() st = f"有板块代码数: 今日-{today_count} 昨日-{before_count}" wx.CallAfter(lambda: self.label_block_info.SetLabelText(st)) except: pass finally: time.sleep(1) def __show_limit_up_list_info(): while True: try: info = KPLLimitUpDataManager().get_current_limitup_info() if info is None: st = f"涨停列表:尚未更新" else: st = f"涨停列表:{info[0]}-{len(info[1])}个" wx.CallAfter(lambda: self.label_limit_up_info.SetLabelText(st)) except: pass finally: time.sleep(1) def __get_positions(): def __show_positions(datas): self.positions = datas # self.list_ctrl_position self.list_ctrl_position.DeleteAllItems() symbols_names_dict = get_symbols_names([x[0] for x in datas]) for data in datas: code = data[0].split(".")[1] total_volume = self.__compute_total_volume(data) available_volume = self.__compute_available_volume(data) index = self.list_ctrl_position.InsertItem(self.list_ctrl_position.GetItemCount(), data[0]) # 委托量 dvolume = 0 if data[0] in self.delegates_dict: delegates_list = self.delegates_dict[data[0]] if delegates_list: dvolume = sum([x[3] for x in delegates_list]) self.list_ctrl_position.SetItem(index, 8, f'{delegates_list[-1][4]}') self.list_ctrl_position.SetItem(index, 1, symbols_names_dict.get(data[0])) self.list_ctrl_position.SetItem(index, 2, str(round(data[1], 2))) self.list_ctrl_position.SetItem(index, 3, str(total_volume)) self.list_ctrl_position.SetItem(index, 4, str(available_volume)) self.list_ctrl_position.SetItem(index, 5, str(round(data[4], 2))) tick = local_api.latest_tick_dict.get(code) if tick: self.list_ctrl_position.SetItem(index, 6, str(tick[2])) else: self.list_ctrl_position.SetItem(index, 6, str(data[5])) self.list_ctrl_position.SetItem(index, 7, f'{dvolume}') while True: try: positions = local_api.trade_api.positions(blocking=True) print("持仓:", positions) wx.CallAfter(lambda: __show_positions( [(p["symbol"], p["amount"], p["volume"], p["available_now"], p["cost"], p["price"],) for p in positions])) # wx.CallAfter(lambda: self.label_limit_up_info.SetLabelText(st)) except: pass finally: time.sleep(3) def __get_delegates(): # 获取委托 while True: try: delegates = local_api.trade_api.get_unfinish_orders(blocking=True) delegates = [(x["symbol"], x["cl_ord_id"], x["account_id"], x["volume"], x["price"]) for x in delegates] delegates_dict = {} for x in delegates: if x[0] not in delegates_dict: delegates_dict[x[0]] = [] delegates_dict[x[0]].append(x) self.delegates_dict = delegates_dict # wx.CallAfter(lambda: self.label_limit_up_info.SetLabelText(st)) except: pass finally: time.sleep(2) def __get_deal_list(): # 获取委托 while True: try: deals = local_api.trade_api.get_execution_reports(blocking=True) deals = [(x["symbol"], x["side"], x["price"], x["volume"], x["amount"], x["created_at"].strftime('%H:%M:%S')) for x in deals] deal_dict = {} for x in deals: if x[0] not in deal_dict: deal_dict[x[0]] = [] deal_dict[x[0]].append(x) self.deal_dict = deal_dict # wx.CallAfter(lambda: self.label_limit_up_info.SetLabelText(st)) except: pass finally: time.sleep(2) """ 开始任务 :return: """ threading.Thread(target=__show_blocks, daemon=True).start() threading.Thread(target=__show_limit_up_list_info, daemon=True).start() threading.Thread(target=__get_positions, daemon=True).start() threading.Thread(target=__get_delegates, daemon=True).start() threading.Thread(target=__get_deal_list, daemon=True).start() def __init_data(self): self.delegates_dict = {} self.deal_dict = {} logs = log_export.load_system_logs() self.system_log_ctrl.Clear() for l in logs: self.system_log_ctrl.AppendText(f"{l[0]} - {l[1]}\n") logs = log_export.load_trade_logs() self.trade_log_ctrl.Clear() for l in logs: self.trade_log_ctrl.AppendText(f"{l[0]} - {l[1]}\n") class MainApp(wx.App): def __init_data(self): pass def OnInit(self): self.SetAppName("低吸") self.__init_data() self.frame = MainFrame() self.frame.Show() return True