python_PyQt5开发验证K线视觉想法工具V1.0

目录

写在前面:

使用过程:

代码:

导入的包、字符型横坐标、K线控件

 K线图控件

放置标记数据表格控件

输入并设置标记数据控件

 主界面

运行代码


写在前面:

开发这个工具的初衷,是基于在分析股票实践中想批量计算股票最近一次的上升振幅或下降振幅,视觉上,我们寻找波段低点和高点很容易,但如果用代码寻找波段低点与高点就颇为复杂,在实现代码过程中经常性快速验证代码得出的结果是否正确,这时如果能在K线上把计算出来的点直接标注出来就能一目了然。基于此,开发了这个工具辅助自己做视觉想法相关的代码设计,在我的理解,诸如波段的划分、股票是否在低位、股票是否在震荡这些都属于视觉感知的范畴,所以该工具就取名为“PyQt5开发验证K线视觉想法工具”。

V1.0版本,只做了单个验证里的点验证,即计算所得点在K线中进行标注

使用过程:

python_PyQt5开发验证K线视觉想法工具V1.0_第1张图片

 1 选择要验证的日数据文件(数据来自优矿)

2 选择与计算过程相同的时间区间

3 显示K线

4 输入并设置标记数据:点击该按钮后会弹出输入框,输入待标记的数据

python_PyQt5开发验证K线视觉想法工具V1.0_第2张图片

1 输入标题:这个标题的作用是便于使用者区分多个标记

2 选择规则:当前V1.0版本只有“点””,选择规则后,在下一行会提示要输入的数据格式,输入的数据格式要和规则对应,否则会出错

3 选择点的形状

4 选择点的颜色

5 输入待标记的数据

6 点确定,左侧设置的结果将插入右侧的表格

7 点击提交,设置的结果将传入主界面

python_PyQt5开发验证K线视觉想法工具V1.0_第3张图片

在主界面中点击“执行”,待标记的点将在K线图中标记出来,从上图可以看到,设置的两个点序列在K线图中标记出来了。

代码:

导入的包、字符型横坐标、K线控件

import os,sys,json,datetime
import pandas as pd
from threading import Thread
from typing import Dict,List,Any
from PyQt5 import QtCore,QtWidgets,QtGui
from PyQt5.QtCore import Qt
import pyqtgraph as pg
pg.setConfigOption('background','w')
pg.setConfigOption('foreground','k')

class RotateAxisItem(pg.AxisItem):
    def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):
        p.setRenderHint(p.Antialiasing,False)
        p.setRenderHint(p.TextAntialiasing,True)

        ## draw long line along axis
        pen,p1,p2 = axisSpec
        p.setPen(pen)
        p.drawLine(p1,p2)
        p.translate(0.5,0)  ## resolves some damn pixel ambiguity

        ## draw ticks
        for pen,p1,p2 in tickSpecs:
            p.setPen(pen)
            p.drawLine(p1,p2)

        ## draw all text
        # if self.tickFont is not None:
        #     p.setFont(self.tickFont)
        p.setPen(self.pen())
        for rect,flags,text in textSpecs:
            # this is the important part
            p.save()
            p.translate(rect.x(),rect.y())
            p.rotate(-30)
            p.drawText(int(-rect.width()),int(rect.height()),int(rect.width()),int(rect.height()),flags,text)
            # restoring the painter is *required*!!!
            p.restore()

class CandlestickItem(pg.GraphicsObject):
    def __init__(self, data):
        pg.GraphicsObject.__init__(self)
        self.data = data  ## data must have fields: time, open, close, min, max
        self.generatePicture()

    def generatePicture(self):
        ## pre-computing a QPicture object allows paint() to run much more quickly,
        ## rather than re-drawing the shapes every time.
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        p.setPen(pg.mkPen('d'))
        w = (self.data[1][0] - self.data[0][0]) / 3.
        for (t, open, close, min, max) in self.data:
            p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
            if open < close:
                p.setBrush(pg.mkBrush('r'))
            else:
                p.setBrush(pg.mkBrush('g'))
            p.drawRect(QtCore.QRectF(t-w, open, w * 2, close - open))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        ## boundingRect _must_ indicate the entire area that will be drawn on
        ## or else we will get artifacts and possibly crashing.
        ## (in this case, QPicture does all the work of computing the bouning rect for us)
        return QtCore.QRectF(self.picture.boundingRect())

class ExtendedComboBox(QtWidgets.QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.pFilterModel = QtCore.QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QtWidgets.QCompleter(self.pFilterModel, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QtWidgets.QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)

    # on selection of an item from the completer, select the corresponding item from combobox
    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)
            self.activated[str].emit(self.itemText(index))

    # on model change, update the models of the filter and completer as well
    def setModel(self, model):
        super(ExtendedComboBox, self).setModel(model)
        self.pFilterModel.setSourceModel(model)
        self.completer.setModel(self.pFilterModel)

    # on model column change, update the model column of the filter and completer as well
    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        super(ExtendedComboBox, self).setModelColumn(column)

 K线图控件

class Graph_Widget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()
        pass
    def init_data(self):
        self.whole_header = None
        self.whole_df = None
        self.whole_pd_header = None
        self.whole_xTick = None

        self.current_df = None
        self.current_data = None
        self.dur_len = 20

        self.add_items_list = []
        self.pointshape_map: Dict = {
            '圆': 'o',
            '三角形': 't',
            '星形': 'star',
            '正方形': 's',
            '菱形': 'd',
            '加号': '+',
            '向下箭头': 'arrow_down',
            '向左箭头': 'arrow_left',
            '向上箭头': 'arrow_up',
            '向右箭头': 'arrow_right'
        }
        pass
    def init_ui(self):
        self.duration_label = QtWidgets.QLabel('左边界~右边界')

        layout_top = QtWidgets.QHBoxLayout()
        layout_top.addWidget(self.duration_label)
        layout_top.addStretch(1)

        xax = RotateAxisItem(orientation='bottom')
        xax.setHeight(h=50)
        self.pw = pg.PlotWidget(axisItems={'bottom': xax})
        self.pw.setMouseEnabled(x=True, y=False)
        # self.pw.enableAutoRange(x=False,y=True)
        self.pw.setAutoVisible(x=False, y=True)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_top)
        layout.addWidget(self.pw)
        self.setLayout(layout)
        pass

    def first_setData(self,data:Dict):
        whole_header = data['whole_header']
        whole_df = data['whole_df']
        whole_pd_header = data['whole_pd_header']

        whole_xTick = whole_df['xTick'].values.tolist()

        self.whole_header = whole_header
        self.whole_df = whole_df
        self.whole_pd_header = whole_pd_header
        self.whole_xTick = whole_xTick

        self.current_df = self.whole_df.copy()
        self.caculate_and_show_data()
        pass

    def caculate_and_show_data(self):
        df = self.current_df.copy()
        df.reset_index(inplace=True)
        df['x'] = [i for i in range(len(df))]
        xTick = df['xTick'].values.tolist()
        xTick00 = []
        dur_num = int(len(xTick)/self.dur_len)
        if dur_num > 2:
            for i in range(0,len(xTick),dur_num):
                xTick00.append((i,xTick[i]))
            pass
        else:
            for i,item in enumerate(xTick):
                xTick00.append((i,item))
            pass
        candle_data = []
        for i,row in df.iterrows():
            candle_data.append((row['x'],row['open'],row['close'],row['lowest'],row['highest']))
        self.current_data = df.loc[:,self.whole_pd_header].values.tolist()
        y_min = df['lowest'].min()
        y_max = df['highest'].max()

        # 开始配置显示内容
        self.pw.clear()

        self.duration_label.setText(f"{xTick[0]}~{xTick[-1]}")

        xax = self.pw.getAxis('bottom')
        xax.setTicks([xTick00])

        self.vb = self.pw.getViewBox()
        self.vb.setLimits(yMin=y_min,yMax=y_max)

        candle_fixed_target = CandlestickItem(candle_data)
        self.pw.addItem(candle_fixed_target)

        self.vLine = pg.InfiniteLine(angle=90,movable=False)
        self.hLine = pg.InfiniteLine(angle=0,movable=False)
        self.label = pg.TextItem()

        self.pw.addItem(self.vLine,ignoreBounds=True)
        self.pw.addItem(self.hLine,ignoreBounds=True)
        self.pw.addItem(self.label,ignoreBounds=True)

        self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved,rateLimit=60,slot=self.mouseMoved)
        self.pw.enableAutoRange()
        self.pw.setAutoVisible()
        pass

    def mouseMoved(self,evt):
        pos = evt[0]
        if self.pw.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            index = int(mousePoint.x())
            if index>=0 and index{item}:{target_data[i]}"
                self.label.setHtml(html_str)
                self.label.setPos(mousePoint.x(),mousePoint.y())
                pass
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())
            pass
        pass

    def add_marks(self,data:List):
        # 点,曲线,区间
        # '标题','规则','形状','颜色','数据'
        self.del_marks()
        for row in data:
            try:
                rule_str = row[1]
                shape_str = row[2]
                color_str = row[3]
                data_str = row[4]
                data_json = json.loads(data_str)
                if rule_str == '点':
                    for node in data_json:
                        targetItem = pg.TargetItem(
                            pos=node,
                            size=20,
                            symbol=self.pointshape_map[shape_str],
                            pen=color_str,
                            brush=color_str,
                            movable=False
                        )
                        self.pw.addItem(targetItem)
                        self.add_items_list.append(targetItem)
                    pass
                if rule_str == '连线':
                    for node in data_json:
                        targetItem = pg.PlotCurveItem(
                            x=node[0],
                            y=node[1],
                            pen=color_str,
                            symbol=self.pointshape_map[shape_str]
                        )
                        self.pw.addItem(targetItem)
                        self.add_items_list.append(targetItem)
                        pass
                    pass
                if rule_str == '区间':
                    for node in data_json:
                        targetItem = pg.LinearRegionItem(
                            values=node,
                            pen=color_str,
                            movable=False
                        )
                        self.pw.addItem(targetItem)
                        self.add_items_list.append(targetItem)
                        pass
                    pass
            except:
                continue
            pass
        pass
    def del_marks(self):
        if self.add_items_list:
            for item in self.add_items_list:
                self.pw.removeItem(item)
            self.add_items_list.clear()
        pass
    pass

放置标记数据表格控件

class MarkTableWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()
        pass
    def init_data(self):
        self.header = ['标题','规则','形状','颜色','数据']
        pass
    def init_ui(self):
        self.table = QtWidgets.QTableWidget()
        self.table.setColumnCount(len(self.header))
        self.table.setHorizontalHeaderLabels(self.header)
        self.table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.table.setColumnHidden(len(self.header)-1,True)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.table)
        self.setLayout(layout)
        pass
    def set_data(self,data:List):
        # '标题','规则','形状','颜色','数据’
        self.table.clearContents()
        self.table.setRowCount(len(data))
        for r,row in enumerate(data):
            self.table.setItem(r,0,QtWidgets.QTableWidgetItem(row[0]))
            self.table.setItem(r,1,QtWidgets.QTableWidgetItem(row[1]))
            self.table.setItem(r,2,QtWidgets.QTableWidgetItem(row[2]))
            one_item = QtWidgets.QTableWidgetItem(row[3])
            one_item.setForeground(QtGui.QColor(row[3]))
            self.table.setItem(r, 3, one_item)
            self.table.setItem(r, 4, QtWidgets.QTableWidgetItem(row[4]))
            pass
        pass
    def insert_one_row(self,data:List):
        self.table.insertRow(0)
        self.table.setItem(0,0,QtWidgets.QTableWidgetItem(data[0]))
        self.table.setItem(0,1,QtWidgets.QTableWidgetItem(data[1]))
        self.table.setItem(0,2,QtWidgets.QTableWidgetItem(data[2]))
        color_item = QtWidgets.QTableWidgetItem(data[3])
        color_item.setForeground(QtGui.QColor(data[3]))
        self.table.setItem(0,3,color_item)
        self.table.setItem(0,4,QtWidgets.QTableWidgetItem(data[4]))
        pass
    def clear_table_contents(self):
        # 清空表内容
        self.table.clearContents()
        self.table.setRowCount(0)
        pass
    def del_selected_rows(self):
        # 删除选中项
        selected_items = self.table.selectedItems()
        if len(selected_items)<=0:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择要删除的行',
                QtWidgets.QMessageBox.Yes
            )
            return
        col_len = self.table.columnCount()
        row_index_list = []
        for i in range(0,len(selected_items)-1,col_len):
            row_index_list.append(selected_items[i].row())
        for i in row_index_list:
            self.table.removeRow(i)
        pass
    def res_name_list(self)->List[str]:
        # 返回标题列表
        row_count = self.table.rowCount()
        if row_count<=0:
            return []
        else:
            res_list = []
            for i in range(row_count):
                item = self.table.item(i,0)
                res_list.append(item.text())
            return res_list
        pass
    def res_data_content(self)->List:
        row_count = self.table.rowCount()
        if row_count<=0:
            return None
        res_data = []
        col_count = self.table.columnCount()
        for i in range(row_count):
            node = []
            for j in range(col_count):
                item_txt = self.table.item(i,j).text()
                node.append(item_txt)
                pass
            res_data.append(node)
            pass
        return res_data

输入并设置标记数据控件

class SettingMarksWidget(QtWidgets.QWidget):
    signal_excute = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()
        pass
    def init_data(self):
        self.please_select_str: str = '-- 请选择 --'
        self.rule_map: Dict = {
            '点':'数据格式提示:[[x,y],[x,y],...]',
            '连线':'数据格式提示:[[x_list,y_list],...]',
            '区间':'数据格式提示:[[x0,x1],[x0,x1],...]'
        }
        self.pointshape_map: Dict = {
            '圆':'o',
            '三角形':'t',
            '星形':'star',
            '正方形':'s',
            '菱形':'d',
            '加号':'+',
            '向下箭头':'arrow_down',
            '向左箭头':'arrow_left',
            '向上箭头':'arrow_up',
            '向右箭头':'arrow_right'
        }
        pass
    def init_ui(self):
        self.setWindowTitle('输入并设置标记数据')
        self.setMinimumWidth(800)
        self.setMinimumHeight(600)

        submit_btn = QtWidgets.QPushButton('提交')
        submit_btn.clicked.connect(self.submit_btn_clicked)

        layout_top = QtWidgets.QHBoxLayout()
        layout_top.addStretch(1)
        layout_top.addWidget(submit_btn)

        h_line = QtWidgets.QFrame()
        h_line.setFrameShape(QtWidgets.QFrame.HLine)
        h_line.setFrameShadow(QtWidgets.QFrame.Sunken)

        layout_hline = QtWidgets.QVBoxLayout()
        layout_hline.addWidget(h_line)
        layout_hline.addSpacing(20)

        tip_label = QtWidgets.QLabel('标题')
        self.name_lineedit = QtWidgets.QLineEdit()
        tip_label2 = QtWidgets.QLabel('规则')
        self.rule_combox = QtWidgets.QComboBox()
        self.rule_combox.addItem(self.please_select_str)
        self.rule_combox.addItems(list(self.rule_map.keys()))
        self.rule_combox.currentTextChanged.connect(self.rule_combox_currentTextChanged)
        self.rule_label = QtWidgets.QLabel('数据格式提示')
        self.rule_label.setWordWrap(True)
        tip_label3 = QtWidgets.QLabel('点形状')
        self.pointshape_combox = QtWidgets.QComboBox()
        self.pointshape_combox.addItem(self.please_select_str)
        self.pointshape_combox.addItems(list(self.pointshape_map.keys()))
        color_btn = QtWidgets.QPushButton('颜色')
        color_btn.clicked.connect(self.color_btn_clicked)
        self.color_label = QtWidgets.QLabel()
        tip_label4 = QtWidgets.QLabel('数据')
        self.data_textedit = QtWidgets.QTextEdit()

        check_btn = QtWidgets.QPushButton('确定')
        check_btn.clicked.connect(self.check_btn_clicked)

        layout_left = QtWidgets.QFormLayout()
        layout_left.addRow(tip_label,self.name_lineedit)
        layout_left.addRow(tip_label2,self.rule_combox)
        layout_left.addRow(self.rule_label)
        layout_left.addRow(tip_label3,self.pointshape_combox)
        layout_left.addRow(color_btn,self.color_label)
        layout_left.addRow(tip_label4,self.data_textedit)
        layout_left.addRow(check_btn)

        self.results_table = MarkTableWidget()
        clear_table_btn = QtWidgets.QPushButton('清空')
        clear_table_btn.clicked.connect(self.clear_table_btn_clicked)
        del_table_btn = QtWidgets.QPushButton('删除选中项')
        del_table_btn.clicked.connect(self.del_table_btn_clicked)

        layout_table_btn = QtWidgets.QHBoxLayout()
        layout_table_btn.addWidget(clear_table_btn)
        layout_table_btn.addWidget(del_table_btn)

        layout_right = QtWidgets.QVBoxLayout()
        layout_right.addWidget(self.results_table)
        layout_right.addLayout(layout_table_btn)

        layout_bottom = QtWidgets.QHBoxLayout()
        layout_bottom.addLayout(layout_left)
        layout_bottom.addLayout(layout_right)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_top)
        layout.addLayout(layout_hline)
        layout.addLayout(layout_bottom)

        self.setLayout(layout)
        pass
    def rule_combox_currentTextChanged(self,txt:str):
        cur_txt = self.rule_combox.currentText()
        if not cur_txt or cur_txt == self.please_select_str:
            self.rule_label.setText('')
            return
        self.rule_label.setText(self.rule_map[cur_txt])
        if cur_txt == '区间':
            self.pointshape_combox.setCurrentText(self.please_select_str)
            self.pointshape_combox.setDisabled(True)
        else:
            self.pointshape_combox.setDisabled(False)
        pass
    def color_btn_clicked(self):
        res = QtWidgets.QColorDialog.getColor()
        self.color_label.setText(res.name())
        style_str = 'QLabel{font-weight:bold;color:'+res.name()+';}'
        self.color_label.setStyleSheet(style_str)
        pass
    def check_btn_clicked(self):
        cur_name = self.name_lineedit.text()
        now_name_list = self.results_table.res_name_list()
        if now_name_list:
            if cur_name in now_name_list:
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    '该标题已经设置过',
                    QtWidgets.QMessageBox.Yes
                )
                return
        rule_str = self.rule_combox.currentText()
        if not rule_str or rule_str==self.please_select_str:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择规则',
                QtWidgets.QMessageBox.Yes
            )
            return
        pointshape_str = ''
        if rule_str!='区间':
            pointshape_str = self.pointshape_combox.currentText()
            if not pointshape_str or pointshape_str==self.please_select_str:
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    '请选择点形状',
                    QtWidgets.QMessageBox.Yes
                )
                return
            pass
        color_str = self.color_label.text()
        if not color_str:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择颜色',
                QtWidgets.QMessageBox.Yes
            )
            return
        data_str = self.data_textedit.toPlainText()
        if not data_str:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请输入数据',
                QtWidgets.QMessageBox.Yes
            )
            return
        # ['标题','规则','形状','颜色','数据']
        res_data = [cur_name,rule_str,pointshape_str,color_str,data_str]
        self.results_table.insert_one_row(res_data)
        pass
    def clear_table_btn_clicked(self):
        self.results_table.clear_table_contents()
    def del_table_btn_clicked(self):
        self.results_table.del_selected_rows()
    def submit_btn_clicked(self):
        res_data = self.results_table.res_data_content()
        if not res_data:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '没有设置相关项,提交的内容为空',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.signal_excute.emit(res_data)
        self.close()
        pass

 主界面

class EyeCheckMainWidget(QtWidgets.QWidget):
    signal_excute = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()

        self.thread_caculate: Thread = None

        self.init_data()
        self.init_ui()
        self.register_event()
        self.progress_init()
        pass
    def init_data(self):
        self.single_settingMark_widget: QtWidgets.QWidget = None
        self.target_column_list: List[str] = ['xTick', 'open', 'close', 'highest', 'lowest']
        pass
    def init_ui(self):
        self.setWindowTitle('验证K线视觉想法工具')

        self.caculate_progress = QtWidgets.QProgressBar()
        self.caculate_status_label = QtWidgets.QLabel()

        layout_progress = QtWidgets.QHBoxLayout()
        layout_progress.addWidget(self.caculate_progress)
        layout_progress.addWidget(self.caculate_status_label)

        groupbox_one = QtWidgets.QGroupBox('选择',self)

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
        groupbox_one.setSizePolicy(sizePolicy)

        self.radio_group = QtWidgets.QButtonGroup()
        single_radio_btn = QtWidgets.QRadioButton('单个验证')
        single_radio_btn.setChecked(True)
        batch_radio_btn = QtWidgets.QRadioButton('批量验证')
        self.radio_group.addButton(single_radio_btn,1)
        self.radio_group.addButton(batch_radio_btn,2)
        self.radio_group.buttonClicked.connect(self.radio_group_buttonClicked)

        layout_one = QtWidgets.QVBoxLayout()
        layout_one.addWidget(single_radio_btn)
        layout_one.addWidget(batch_radio_btn)
        layout_one.addStretch(1)

        groupbox_one.setLayout(layout_one)

        self.stack_one = QtWidgets.QWidget()
        self.stack_two = QtWidgets.QWidget()

        self.fill_stack_widget_one()
        self.fill_stack_widget_two()

        self.stack_widget = QtWidgets.QStackedWidget()
        self.stack_widget.setSizePolicy(sizePolicy)
        self.stack_widget.addWidget(self.stack_one)
        self.stack_widget.addWidget(self.stack_two)

        layout_two = QtWidgets.QHBoxLayout()
        layout_two.addWidget(groupbox_one,1)
        layout_two.addWidget(self.stack_widget,4)

        groupbox_two = QtWidgets.QGroupBox('选择与待验证数据相同区间', self)
        tip_label = QtWidgets.QLabel('区间')
        self.left_point = QtWidgets.QDateEdit()
        self.left_point.setDisplayFormat('yyyy-MM-dd')
        self.left_point.setCalendarPopup(True)
        self.right_point = QtWidgets.QDateEdit()
        self.right_point.setDisplayFormat('yyyy-MM-dd')
        self.right_point.setCalendarPopup(True)
        self.right_point.setDate(QtCore.QDate.currentDate())
        tip_label2 = QtWidgets.QLabel('请先设置好对应区间')
        tip_label2.setStyleSheet('QLabel{color:red;}')

        layout_three = QtWidgets.QHBoxLayout()
        layout_three.addWidget(tip_label)
        layout_three.addWidget(self.left_point)
        layout_three.addWidget(self.right_point)
        layout_three.addWidget(tip_label2)
        layout_three.addStretch(1)

        groupbox_two.setLayout(layout_three)

        self.graph_title_label = QtWidgets.QLabel('图标题')
        self.graph_title_label.setAlignment(Qt.AlignCenter)
        self.graph_title_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold;}')
        self.graph_widget = Graph_Widget()

        layout_four = QtWidgets.QVBoxLayout()
        layout_four.addWidget(self.graph_title_label)
        layout_four.addWidget(self.graph_widget)

        tip_label3 = QtWidgets.QLabel('标记详情列表')
        self.mark_table = MarkTableWidget()

        layout_five = QtWidgets.QVBoxLayout()
        layout_five.addWidget(tip_label3)
        layout_five.addWidget(self.mark_table)

        layout_six = QtWidgets.QHBoxLayout()
        layout_six.addLayout(layout_four,4)
        layout_six.addLayout(layout_five,1)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_progress)
        layout.addLayout(layout_two)
        layout.addWidget(groupbox_two)
        layout.addLayout(layout_six)
        self.setLayout(layout)
        pass
    def register_event(self):
        self.signal_excute.connect(self.process_excute_event)
        pass
    def process_excute_event(self,data:Dict):
        pass
    def fill_stack_widget_one(self):
        single_choice_one_daily_file_path = QtWidgets.QPushButton('选择股票日数据文件')
        single_choice_one_daily_file_path.clicked.connect(self.single_choice_one_daily_file_path_clicked)
        self.single_choice_one_daily_file_lineedit = QtWidgets.QLineEdit()
        single_show_k_btn = QtWidgets.QPushButton('显示K线')
        single_show_k_btn.clicked.connect(self.single_show_k_btn_clicked)
        single_input_marks_btn = QtWidgets.QPushButton('输入并设置标记数据')
        single_input_marks_btn.clicked.connect(self.single_input_marks_btn_clicked)
        mark_excute_btn = QtWidgets.QPushButton('执行')
        mark_excute_btn.clicked.connect(self.mark_excute_btn_clicked)

        single_layout_one = QtWidgets.QHBoxLayout()
        single_layout_one.addWidget(single_choice_one_daily_file_path)
        single_layout_one.addWidget(self.single_choice_one_daily_file_lineedit)
        single_layout_one.addWidget(single_show_k_btn)

        single_layout_two = QtWidgets.QHBoxLayout()
        single_layout_two.addWidget(single_input_marks_btn)
        single_layout_two.addWidget(mark_excute_btn)

        single_layout = QtWidgets.QVBoxLayout()
        single_layout.addLayout(single_layout_one)
        single_layout.addLayout(single_layout_two)
        single_layout.addStretch(1)
        self.stack_one.setLayout(single_layout)
        pass
    def fill_stack_widget_two(self):
        batch_layout = QtWidgets.QVBoxLayout()
        self.stack_two.setLayout(batch_layout)
        pass
    def radio_group_buttonClicked(self,obj):
        radio_id = self.radio_group.checkedId()
        self.stack_widget.setCurrentIndex(radio_id - 1)
        pass
    def single_choice_one_daily_file_path_clicked(self):
        path,_ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            '选择股票日数据文件',
            '.',
            'CSV(*.csv)'
        )
        if not path:
            return
        self.single_choice_one_daily_file_lineedit.setText(path)
        pass
    def single_show_k_btn_clicked(self):
        daily_file = self.single_choice_one_daily_file_lineedit.text()
        if not daily_file or not os.path.exists(daily_file):
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择要验证的日数据',
                QtWidgets.QMessageBox.Yes
            )
            return
        file_name = os.path.basename(daily_file)
        left_point = self.left_point.date().toString('yyyy-MM-dd')
        right_point = self.right_point.date().toString('yyyy-MM-dd')
        left_datetime = datetime.datetime.strptime(left_point,'%Y-%m-%d')
        right_datetime = datetime.datetime.strptime(right_point,'%Y-%m-%d')
        if left_datetime >= right_datetime:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择时间区间',
                QtWidgets.QMessageBox.Yes
            )
            return
        df = pd.read_csv(daily_file,encoding='utf-8')
        df = df.loc[df['openPrice']>0].copy()
        df['o_date'] = pd.to_datetime(df['tradeDate'])
        df = df.loc[(df['o_date']>=left_point) & (df['o_date']<=right_point)].copy()
        df['open'] = df['openPrice']*df['accumAdjFactor']
        df['close'] = df['closePrice']*df['accumAdjFactor']
        df['highest'] = df['highestPrice']*df['accumAdjFactor']
        df['lowest'] = df['lowestPrice']*df['accumAdjFactor']
        df['xTick'] = df['tradeDate']

        k_data = {
            'whole_df':df,
            'whole_header':['日期','开盘','收盘','最高','最低'],
            'whole_pd_header': self.target_column_list
        }
        self.graph_widget.first_setData(k_data)
        self.graph_title_label.setText(file_name)
        pass
    def single_input_marks_btn_clicked(self):
        if not self.single_settingMark_widget:
            self.single_settingMark_widget = SettingMarksWidget()
            self.single_settingMark_widget.signal_excute.connect(self.single_settingMark_widget_signal_emit)
        self.single_settingMark_widget.show()
        pass
    def single_settingMark_widget_signal_emit(self,data:List):
        if not data:
            return
        self.mark_table.set_data(data)
        pass
    def mark_excute_btn_clicked(self):
        mark_data = self.mark_table.res_data_content()
        if mark_data:
            self.graph_widget.add_marks(mark_data)
        pass
    def start_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        if self.thread_caculate:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '线程正在执行任务,请稍后。。。',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.thread_caculate = Thread(
            target=self.running_caculate_thread,
            args=(
                mark_str, data,
            )
        )
        self.thread_caculate.start()
        self.progress_busy()
        pass
    def running_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        pass
    def progress_init(self) -> None:
        self.caculate_progress.setValue(0)
        self.caculate_status_label.setText('无任务')
    def progress_busy(self) -> None:
        self.caculate_progress.setRange(0, 0)
        self.caculate_status_label.setText('正在执行')
    def progress_finished(self) -> None:
        self.caculate_progress.setRange(0, 100)
        self.caculate_progress.setValue(100)
        self.caculate_status_label.setText('执行完毕')
        pass
    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        if self.single_settingMark_widget:
            self.single_settingMark_widget.close()
        self.close()
        pass

运行代码

if __name__ == '__main__':
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    app = QtWidgets.QApplication(sys.argv)
    main_window = EyeCheckMainWidget()
    main_window.showMaximized()
    app.exec()
    pass

你可能感兴趣的:(python杂项,python)