| | |
| | | return t1 |
| | | |
| | | |
| | | class TickCompareFrame(wx.Frame): |
| | | mark_lines = {} |
| | | |
| | | def __init__(self): |
| | | '''构造函数''' |
| | | wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE, |
| | | size=(800, 1000)) |
| | | self.SetBackgroundColour(wx.Colour(0, 0, 0)) |
| | | |
| | | self.Center() |
| | | |
| | | # 拉取数据线程 |
| | | self.cost_price_threads = {} |
| | | |
| | | # 以下代码处理图标 |
| | | # if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe": |
| | | # exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None)) |
| | | # icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO) |
| | | # else: |
| | | # icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO) |
| | | # self.SetIcon(icon) |
| | | # 定义窗口关闭 |
| | | self.Bind(wx.EVT_CLOSE, self.OnExit) |
| | | self.Bind(wx.EVT_SIZE, self.OnResize) |
| | | self.panels = [] |
| | | self.scroll = None |
| | | self.col = 1 |
| | | self.ratio = 0.55 |
| | | self.__re_draw() |
| | | |
| | | self.timer = wx.Timer(self) # 创建定时器 |
| | | self.Bind(wx.EVT_TIMER, self.post_redraw, self.timer) # 绑定一个定时器事件 |
| | | self.last_size = (self.Size[0], self.Size[1]) |
| | | |
| | | # 初始化 |
| | | # self.scroll = wx.ScrolledWindow(self, -1, size=(800, 1000)) |
| | | self.boxsier = wx.BoxSizer(wx.VERTICAL) |
| | | boxSizer1 = wx.BoxSizer(wx.HORIZONTAL) |
| | | self.edit_code1 = wx.TextCtrl(self, size=(100, 30)) |
| | | self.edit_code2 = wx.TextCtrl(self, size=(100, 30)) |
| | | self.btn_load_data = wx.Button(self, label="加载数据", size=(100, 30)) |
| | | boxSizer1.Add(self.edit_code1) |
| | | boxSizer1.Add(self.edit_code2) |
| | | boxSizer1.Add(self.btn_load_data, 1, wx.LEFT|wx.TOP, 2) |
| | | |
| | | self.boxsier.Add(boxSizer1) |
| | | |
| | | # self.scroll.EnableScrolling(False, True) |
| | | |
| | | # self.boxsier.Add(wx.FlexGridSizer(rows, self.col, space, space)) |
| | | |
| | | # self.scroll.SetSizer(self.boxsier) |
| | | |
| | | # self.scroll.Layout() |
| | | # self.boxsier.Fit(self.scroll) |
| | | |
| | | # boxsier.Add(mainBoxsier, 1, wx.EXPAND | wx.ALL, 5) |
| | | # self.SetSizer(boxsier) |
| | | # mainBoxsier.Fit(self) |
| | | if setting.is_stay_on_top(): |
| | | self.WindowStyle = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.STAY_ON_TOP |
| | | |
| | | def __re_draw(self): |
| | | return |
| | | codes_name = juejin_core.GPCodeManager().get_codes_with_names() |
| | | rows = len(codes_name) |
| | | if rows % self.col == 0: |
| | | rows = rows / self.col |
| | | else: |
| | | rows = rows / self.col + 1 |
| | | space = 0 |
| | | if not self.scroll: |
| | | return |
| | | |
| | | if self.panels: |
| | | for p in self.panels: |
| | | p.Destroy() |
| | | self.boxsier.Clear() |
| | | |
| | | pannel_height = round((self.Size[0] - (self.col - 1) * space) / self.col * self.ratio) |
| | | |
| | | self.scroll.SetScrollbars(1, 1, 0, pannel_height * rows) |
| | | self.scroll.SetScrollRate(0, pannel_height) |
| | | global drawManager |
| | | axes_list = [] |
| | | self.panels = [] |
| | | for i in range(0, len(codes_name)): |
| | | # pos=(0, i * pannel_height) |
| | | pannel = wx.Panel(self.scroll, size=(-1, pannel_height)) |
| | | pannel.BackgroundColour = wx.Colour(0, 0, 0) |
| | | self.panels.append(pannel) |
| | | self.boxsier.Add(pannel) |
| | | code = codes_name[i][0] |
| | | axes = self.__create_canvas(pannel, code, "{}({})".format(codes_name[i][0], codes_name[i][1]), |
| | | codes_name[i][1], |
| | | codes_name[i][2]) |
| | | |
| | | if code not in self.cost_price_threads: |
| | | t1 = self.run_get_cost_price(codes_name[i][0]) |
| | | self.cost_price_threads[code] = t1 |
| | | axes_list.append(axes) |
| | | |
| | | self.scroll.Layout() |
| | | # self.boxsier.Fit(self.scroll) |
| | | # |
| | | # 初始化数据 |
| | | drawManager = DrawManager(axes_list, codes_name) |
| | | t1 = threading.Thread(target=lambda: drawManager.init_code_datas()) |
| | | # 后台运行 |
| | | t1.setDaemon(True) |
| | | t1.start() |
| | | |
| | | @classmethod |
| | | def set_mouse_data(cls, xdata, ydata, code, axes2): |
| | | try: |
| | | if code not in cls.mark_lines: |
| | | cls.mark_lines[code] = {} |
| | | if "mouse" not in cls.mark_lines[code]: |
| | | line_h = axes2.axhline(ydata, linestyle='-', color='white', lw=0.5, zorder=3) |
| | | line_v = axes2.axvline(xdata, linestyle='-', color='white', lw=0.5, zorder=3) |
| | | text_h = axes2.text(axes2.get_xlim()[1], ydata, r'', fontsize=10, color='white', |
| | | verticalalignment="center", bbox=dict(facecolor='white', alpha=0.9), zorder=3) |
| | | text_v = axes2.text(xdata, axes2.get_ylim()[0], r'', fontsize=10, color='red', |
| | | verticalalignment='top', horizontalalignment='center', |
| | | bbox=dict(facecolor='white', alpha=0.9), zorder=3) |
| | | |
| | | cls.mark_lines[code]["mouse"] = (line_h, line_v, text_h, text_v) |
| | | line = cls.mark_lines.get(code).get("mouse") |
| | | x = round(xdata) |
| | | y = round(ydata, 2) |
| | | |
| | | line[0].set_ydata(ydata) |
| | | line[1].set_xdata(xdata) |
| | | line[2].set_text(f"{y}%") |
| | | line[3].set_text(f"{tool.trade_time_add_second('09:30:00', x)}") |
| | | line[2].set_x(axes2.get_xlim()[1] * (1 + 0.005)) |
| | | line[2].set_y(y) |
| | | line[3].set_x(x) |
| | | line[3].set_y(axes2.get_ylim()[0] * (1 + 0.02)) |
| | | if y >= 0: |
| | | line[2].set_color('red') |
| | | else: |
| | | line[2].set_color('green') |
| | | axes2.figure.canvas.draw() |
| | | except Exception as e: |
| | | pass |
| | | |
| | | def __create_canvas(self, pannel, code, title, name, price, close_callback=None): |
| | | TickDataProcess.clear(code) |
| | | |
| | | def show_mouse_line(event): |
| | | # 删除之前的线 |
| | | self.set_mouse_data(event.xdata, event.ydata, code, axes) |
| | | |
| | | def clear_mouse_line(event): |
| | | print("clear_mouse_line") |
| | | if code in self.mark_lines: |
| | | if self.mark_lines.get(code): |
| | | line = self.mark_lines.get(code).get("mouse") |
| | | if line is not None: |
| | | for l in line: |
| | | l.remove() |
| | | self.mark_lines.get(code).pop("mouse") |
| | | axes.figure.canvas.draw() |
| | | |
| | | def close_canvas(event): |
| | | print("关闭", title) |
| | | close_callback(title) |
| | | |
| | | dpi = 100 |
| | | width_dpi = self.Size[0] / (dpi * self.col) |
| | | figure_score = Figure(figsize=(width_dpi, round(width_dpi * (self.ratio), 2)), dpi=dpi) |
| | | # 设置外边距 |
| | | right_padding_px = 85 |
| | | right = round((self.Size[0] - right_padding_px) / self.Size[0], 4) |
| | | figure_score.subplots_adjust(left=0.01, bottom=0.15, top=0.92, |
| | | right=right) |
| | | # 设置字体颜色 |
| | | plt.rcParams["text.color"] = "red" |
| | | plt.rcParams["axes.labelcolor"] = "red" |
| | | # 设置坐标轴数字颜色 |
| | | plt.rcParams["xtick.color"] = "white" |
| | | plt.rcParams["ytick.color"] = "white" |
| | | # 设置坐标轴颜色 |
| | | plt.rcParams["axes.edgecolor"] = "firebrick" |
| | | |
| | | # 解决中文乱码问题 |
| | | plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置字体 |
| | | plt.rcParams["font.serif"] = ["SimHei"] |
| | | plt.rcParams["axes.unicode_minus"] = False # 该语句解决图像中的“-”负号的乱码问题 |
| | | |
| | | # 测试 |
| | | buttonaxe = plt.axes([0.94, 0.5, 0.1, 0.1]) |
| | | button1 = Button(buttonaxe, '关闭', color='white', hovercolor='yellow') |
| | | |
| | | axes = figure_score.add_subplot(1, 1, 1) |
| | | axes.autoscale(True) |
| | | |
| | | # axes_score.plot(t_score, s_score, 'ro', t_score, s_score, 'k') |
| | | axes.set_title(title) |
| | | axes.grid(False) |
| | | axes.set_xlabel(f'时间({name})') |
| | | axes.dist = 0 |
| | | |
| | | # axes.set_ylabel(u'价格') |
| | | # 获取平开价 |
| | | extra = 0 # (tool.get_limit_up_price(price)-decimal.Decimal(price))*decimal.Decimal(0.02) |
| | | |
| | | axes.patch.set_facecolor('black') |
| | | figure_score.patch.set_facecolor('black') |
| | | |
| | | # 设置横坐标9:25-15:00 |
| | | xs_str = ["09:25", "09:30", "10:30", "11:30", "14:00", "15:00"] |
| | | xs_int = [DrawManager.get_x_time_as_seconds(f"0000-00-00 {x}:00") for x in xs_str] |
| | | axes.set_xticks(xs_int[1:]) |
| | | axes.set_xticklabels(xs_str[1:]) |
| | | axes.set_xlim([xs_int[0], xs_int[-1]]) |
| | | |
| | | axes2 = axes.twinx() |
| | | # axes2.grid(color='firebrick', ls='-', lw=0.5) |
| | | axes2.grid(color='firebrick', ls='-', lw=0.5) |
| | | # 鼠标在画布移动 |
| | | # axes2.figure.canvas.mpl_connect('motion_notify_event', show_mouse_line) |
| | | # # 鼠标离开画布 |
| | | # axes2.figure.canvas.mpl_connect('axes_leave_event', clear_mouse_line) |
| | | |
| | | # 设置纵坐标轴 |
| | | limit_up_price = float(tool.get_limit_up_price(price)) |
| | | max_rate = round((limit_up_price - price) / price, 4) * 100 |
| | | print("涨停最大比例", max_rate) |
| | | # 设置纵坐标信息 |
| | | # max_rate = 2 |
| | | DrawManager.set_y_info(code, max_rate, axes, axes2, price) |
| | | |
| | | line = axes2.plot([], [], color='white', linewidth=1) |
| | | average_line = axes2.plot([], [], color='yellow', linewidth=1, linestyle='-') |
| | | average_line_1m = axes2.plot([], [], color='yellow', linewidth=1, linestyle='-') |
| | | # axes2.legend(loc='upper left') |
| | | cannvas = FigureCanvas(pannel, -1, figure_score) |
| | | axes2.text(1, 11.5, r'', fontsize=15, color='red') |
| | | axes2.text(-1, -11.5, r'', fontsize=15, color='red') |
| | | |
| | | axes2.spines['top'].set_visible(False) |
| | | axes.spines['top'].set_visible(False) |
| | | axes2.spines['bottom'].set_visible(True) |
| | | axes.spines['bottom'].set_visible(False) |
| | | |
| | | # 中轴线加粗 |
| | | hline = axes2.axhline(0, linestyle='-', color='firebrick', lw=2, zorder=1) |
| | | |
| | | # 设置坐标轴标记点为黑色 |
| | | axes.tick_params(axis='x', colors='firebrick') |
| | | axes.tick_params(axis='y', colors='black') |
| | | axes2.tick_params(axis='x', colors='firebrick') |
| | | axes2.tick_params(axis='y', colors='black') |
| | | |
| | | def update_data(i): |
| | | print("更新数据:", i) |
| | | |
| | | return axes2, line, average_line_1m, average_line, axes |
| | | |
| | | def __show_top(self, event): |
| | | if event.Selection: |
| | | setting.set_stay_on_top(1) |
| | | self.WindowStyle = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.STAY_ON_TOP |
| | | else: |
| | | setting.set_stay_on_top(0) |
| | | self.WindowStyle = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN |
| | | |
| | | def OnExit(self, e): |
| | | try: |
| | | setting.set_tick_window_info((self.Position[0], self.Position[1], self.Size[0], self.Size[1])) |
| | | except Exception as e: |
| | | print("") |
| | | self.Hide() |
| | | |
| | | def post_redraw(self, evt): |
| | | |
| | | if abs(self.last_size[0] - self.Size[0]) > 20: |
| | | print("--------post_redraw--------") |
| | | self.last_size = (self.Size[0], self.Size[1]) |
| | | self.__re_draw() |
| | | |
| | | def OnResize(self, e): |
| | | print("变化后的尺寸", e.Size) |
| | | # 留出滚动条,留出上边距 |
| | | if self.scroll: |
| | | self.scroll.Size = (e.Size[0] - 15, e.Size[1] - 60) |
| | | for p in self.panels: |
| | | p_height = round(e.Size[0] * (450 / 800)) |
| | | p.Size = (e.Size[0], p_height) |
| | | self.timer.Stop() |
| | | self.timer.StartOnce(1000) |
| | | |
| | | # 降低重绘频率 |
| | | # self.__re_draw() |
| | | |
| | | def set_codes_success(self): |
| | | print("设置代码成功回调") |
| | | p2.send("resub") |
| | | self.__re_draw() |
| | | self.timer.Stop() |
| | | self.timer.StartOnce(1000) |
| | | self.Size = wx.Size(self.Size[0], self.Size[1] + 10) |
| | | time.sleep(0.1) |
| | | self.Size = wx.Size(self.Size[0], self.Size[1] - 10) |
| | | |
| | | def run_get_cost_price(self, code): |
| | | def request(code): |
| | | while True: |
| | | try: |
| | | price = SocketApiUtil.get_cost_price(code) |
| | | pre_price = juejin_core.GPCodeManager().get_pre_prices(code) |
| | | rate = round((price - pre_price) * 100 / pre_price, 2) |
| | | DrawManager.set_cost_rate(code, rate) |
| | | # wx.CallAfter(lambda :) |
| | | except Exception as e: |
| | | DrawManager.set_cost_rate(code, None) |
| | | # wx.CallAfter(lambda: str(e)) |
| | | except: |
| | | pass |
| | | finally: |
| | | time.sleep(3) |
| | | |
| | | t1 = threading.Thread(target=lambda: request(code), daemon=True) |
| | | t1.start() |
| | | return t1 |
| | | |
| | | |
| | | # 绘图管理器 |
| | | class DrawManager: |
| | | X_RANGE_MINIUTES = 335 |
| | |
| | | def OnInit(self): |
| | | self.SetAppName(APP_TITLE) |
| | | self.__init_data() |
| | | self.frame = TickFrame() |
| | | self.frame = TickCompareFrame() |
| | | # self.floatFrame = FloatFrame() |
| | | global_datas["tickFrame"] = self.frame |
| | | # global_datas["floatFrame"] = self.floatFrame |