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

news2024/11/16 11:24:43

目录

写在前面:

使用过程:

代码:

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

 K线图控件

放置标记数据表格控件

输入并设置标记数据控件

 主界面

运行代码


写在前面:

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

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

使用过程:

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

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

3 显示K线

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

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

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

3 选择点的形状

4 选择点的颜色

5 输入待标记的数据

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

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

在主界面中点击“执行”,待标记的点将在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<len(self.current_data):
                target_data = self.current_data[index]
                html_str = ''
                for i,item in enumerate(self.whole_header):
                    html_str += f"<br/>{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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/798133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django实现音乐网站 ⑴

使用Python Django框架制作一个音乐网站。 目录 网站功能模块 安装django 创建项目 创建应用 注册应用 配置数据库 设置数据库配置 设置pymysql库引用 创建数据库 创建数据表 生成表迁移文件 执行表迁移 后台管理 创建管理员账户 启动服务器 登录网站 配置时区…

神码ai火车头伪原创设置【php源码】

大家好&#xff0c;给大家分享一下python考什么内容&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 1、Python 计算机二级都考什么 Python要到什么程度 考试内容 一、Python语言的基本语法元素…

高算力AI模组前沿应用:基于ARM架构的SoC阵列式服务器

本期我们带来高算力AI模组前沿应用&#xff0c;基于ARM架构的SoC阵列式服务器相关内容。澎湃算力、创新架构、异构计算&#xff0c;有望成为未来信息化社会的智能算力底座。 ▌性能优势AI驱动&#xff0c;ARM架构服务器加速渗透 一直以来&#xff0c;基于ARM架构的各类处理器…

Tooltip文字提示(antd-design组件库)简单使用

1.Tooltip文字提示 简单的文字提示气泡框。 2.何时使用 鼠标移入则显示提示&#xff0c;移出消失&#xff0c;气泡浮层不承载复杂文本和操作。 可用来代替系统默认的 title 提示&#xff0c;提供一个 按钮/文字/操作 的文案解释。 组件代码来自&#xff1a; 文字提示 Tooltip -…

读写分离案例、Mysql主从复制 步骤

在开发大型应用程序时&#xff0c;数据库的性能通常是一个关键问题。读写分离是一种常见的数据库优化技术&#xff0c;可以显著提升数据库的读取操作性能。本文将介绍MySQL主从复制和一个读写分离案例。 1、MySQL主从复制 主从复制是MySQL数据库提供的一种数据复制机制&#…

免费商城搭建、免费小程序商城搭建、之java商城 电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

【黑马头条之内容安全第三方接口】

本笔记内容为黑马头条项目的文本-图片内容审核接口部分 目录 一、概述 二、准备工作 三、文本内容审核接口 四、图片审核接口 五、项目集成 一、概述 内容安全是识别服务&#xff0c;支持对图片、视频、文本、语音等对象进行多样化场景检测&#xff0c;有效降低内容违规风…

vue+ivew model框 select校验遇到的问题

iview model 点击关闭&#xff0c;校验没有通过也会关闭 解决办法&#xff1a; 第一步&#xff1a;自定义页脚内容 <div slot"footer"><Button type"primary" click"confirmCarryOver()">确认</Button><Button click&qu…

python绘制3D条形图

文章目录 数据导入三维条形图bar3d 数据导入 尽管在matplotlib支持在一个坐标系中绘制多组条形图&#xff0c;效果如下 其中&#xff0c;蓝色表示中国&#xff0c;橘色表示美国&#xff0c;绿色表示欧盟。从这个图就可以非常直观地看出&#xff0c;三者自2018到2022年的GDP变化…

智能制造:开启工业新纪元

随着科技的不断发展和人工智能的日益成熟&#xff0c;智能制造正成为当今工业界的热门话题。智能制造是一种以先进技术为支撑&#xff0c;通过数字化、网络化、智能化手段来提升生产效率、优化生产流程的现代化制造模式。 在智能制造中&#xff0c;物联网、大数据、云计算、人工…

OR-Tools工具安装(Python-Vs code)-自用

安装&#xff08;已安装python以及Vs code&#xff09; pip安装 python -m pip install --user ortools安装完成示意如下&#xff1a; 验证安装 python -c "import ortools; print(ortools.__version__)"输出结果为版本号

【Spring框架】@Resource注入以及与@Autowired的区别

目录 使用Resource设置name的方式来重命名注入的对象区别 使用Resource设置name的方式来重命名注入的对象 package com;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.spr…

Ansible自动化运维工具

Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可以实现。 Ansible能批量配置、部署、管理上千台主机。比如以前需要…

解读维达国际2023半年度财报:后续发力“高端、高利润、高质量”

随着国内直播电商市场的迅速发展&#xff0c;对于希望在国内市场取得成功的品牌来说&#xff0c;直播电商已经成为所有大众消费品牌的竞争关键。 以生活用纸品牌维达为例&#xff0c;截至2023年7月25日&#xff0c;据抖音平台直播动态显示&#xff0c;维达官方旗舰店今年上半年…

opencv-27 阈值处理 cv2.threshold()

怎么理解阈值处理? 阈值处理&#xff08;Thresholding&#xff09;是一种常用的图像处理技术&#xff0c;在机器学习和计算机视觉中经常被用于二值化图像或二分类任务。它基于设定一个阈值来将像素值进行分类&#xff0c;将像素值大于或小于阈值的部分分为两个不同的类别&…

geomesa-cassandra安装测试

环境&#xff1a;centos7、java8、cassandra3.0.29、geomesa-cassandra_2.12-3.5.2 配置Java环境&#xff1a; 安装配置cassandra: 下载cassandra&#xff1a; wget https://www.apache.org/dyn/closer.lua/cassandra/3.0.29/apache-cassandra-3.0.29-bin.tar.gz tar -xzf ap…

一文了解声音克隆软件的技术原理

声音克隆软件是一种可以对人声进行复制和模拟的软件。它的技术原理主要包括语音信号处理和合成声音的算法。 首先&#xff0c;声音克隆软件会通过麦克风或其他录音设备获取用户的原始语音信号。这个语音信号将被传输到计算机中&#xff0c;经过一系列的处理和分析。 在语音信号…

微信小程序自动化测试实战,支持录制回放、智能遍历

为了满足小程序性能、功能等方面的测试需求&#xff0c;微信团队上线 小程序云测服务&#xff0c;提供丰富的自动化测试能力。其中 智能化 Monkey 服务 凭借着零代码、低成本的优势吸引不少开发者使用。 在服务使用过程中&#xff0c;我们发现开发者有更多的进阶需求&#xff…

多个回路进行全电参量测量,实现基站内各回路用电能耗的集中管理-安科瑞黄安南

应用场景 可应用于基站的交直流配电箱及对基站内的动力设备进行数据采集和控制。 功能 1.对多个回路进行全电参量测量&#xff0c;实现基站内各回路用电能耗的集中管理&#xff1b; 2.丰富的DI/DO输入输出&#xff0c;NTC测温&#xff0c;温湿度测量等非电参量监测&#xff…

深入学习 redis - Stream、Geospatial、HyperLogLog、Bitmap、Bitfields 类型扩展

目录 前言 Stream geospatial HyperLogLog Bitmaps Bitfields 前言 redis 中最关键的五个数据类型 String、List、Hash、Set、Zset 应用最广泛&#xff0c;同时 redis 也推出了额外的 5 个数据类型&#xff0c;他们分别是针对特殊场景才进行的应用的. Ps&#xff1a;这几种…