PyQt5_股票技术图形查看工具

技术图形,诸如头肩顶、头肩底、W底、圆底等,代码逻辑实现后,要使用股票数据验证,这类主要依靠视觉判断的技术图形,获得的结果能及时在图表中展示出来,对代码的开发、校验、结果的准确度确认等能起到事半功倍的效果,本工具就是基于此需求所做的开发。

本文以“头肩底”为例进行讲解

目录

效果

计算技术图形策略代码

工具代码

工具使用

数据


效果

计算技术图形策略代码

前置说明:

1. 必须以“excute_strategy”为方法名

2. 一个参数,股票日数据文件路径

3. 策略代码写完后,命名,保存在“shape_recognition_strategy”文件夹中,‘shape_recognition_strategy’文件夹的创建位置在下文中会介绍

4. 将策略文件名写入主程序类StrategeMainWidget的self.strategyname_code_map对应的兼职对中

def excute_strategy(daily_file_path):
    '''
    名称:头肩底
    处理过程:结合图形说明,从最近的日期往前找
    1. (1)号位为起点位
    2. 从(1)号位开始找最近最小值设为(2)号位
    3. 找到(2)号位后,找最近最大值设为(3)号位
    4. 判断(3)号位是否小于(1)号位:
    5. (3)号位小于(1)号位,找最近最小值设为(4)号位
    6. (3)号位大于等于(1)号位,将(3)号位设为(1)号位,从第二步开始,直到找到(4)号位
    7. 找到(4)号位后,判断(4)号位是否小于(2)号位:
    8. (4)号位小于(2)号位,找最近最大值设为(5)号位
    9. (4)号位大于等于(2)号位,将(3)号位设为(1)号位,从第二步开始,直到找到(5)号位
    10. 找到(5)号位后,判断(5)号位是否和(3)号位在相近的水平位置:
    11. (5)号位和(3)号位在相近的水平位置,找最近最小值设为(6)号位
    12. 找到(6)号位后,判断(6)号位是否大于(4)号位:
    13. (6)号位大于(4)号位,找最近最大值设为(7)号位
    14. (6)号位小于等于(4)号位,将(5)号位设为(1)号位,从第二步开始,直到找到(7)号位
    15. 找到(7)号位后,判断(7)号位是否大于(5)号位:
    16. (7)号位大于(5)号位,找图完毕。
    17. (7)号位小于等于(5)号位,将(5)号位设为(1)号位,从第二步开始,直到完毕。

    前置条件:计算时间区间 2021-01-01 到 2022-01-01
    :param daily_file_path: 股票日数据文件路径
    :return:
    '''
    import pandas as pd
    import os

    start_date_str = '2021-01-01'
    end_date_str = '2022-01-01'
    df = pd.read_csv(daily_file_path,encoding='utf-8')
    # 删除停牌的数据
    df = df.loc[df['openPrice'] > 0].copy()
    df['o_date'] = df['tradeDate']
    df['o_date'] = pd.to_datetime(df['o_date'])
    df = df.loc[(df['o_date'] >= start_date_str) & (df['o_date']<=end_date_str)].copy()
    # 保存未复权收盘价数据
    df['close'] = df['closePrice']
    # 计算前复权数据
    df['openPrice'] = df['openPrice'] * df['accumAdjFactor']
    df['closePrice'] = df['closePrice'] * df['accumAdjFactor']
    df['highestPrice'] = df['highestPrice'] * df['accumAdjFactor']
    df['lowestPrice'] = df['lowestPrice'] * df['accumAdjFactor']

    df.reset_index(inplace=True)
    df['i_row'] = [i for i in range(len(df))]
    # 开始计算
    one_point = None
    one_val = None
    two_point = None
    two_val = None
    three_point = None
    three_val = None
    four_point = None
    four_val = None
    five_point = None
    five_val = None
    six_point = None
    six_val = None
    seven_point = None
    seven_val = None

    gap_pct = 0.005
    for i in range(len(df)-1,0,-1):
        if seven_point:
            if six_point-seven_point < 5 or seven_val < five_val:
                one_point = seven_point
                one_val = seven_val
                two_point = None
                two_val = None
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None
            else:
                break
        if six_point:
            if five_point - six_point < 3 or six_val < four_val:
                one_point = five_point
                one_val = five_val
                two_point = six_point
                two_val = six_val
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None
                pass
        if five_point:
            if four_point - five_point < 3 or five_val*(1+gap_pct)<=three_val or five_val*(1-gap_pct)>=three_val:
                one_point = five_point
                one_val = five_val
                two_point = None
                two_val = None
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None
                pass
        if four_point:
            if three_point - four_point < 3 or four_val > two_val:
                one_point = three_point
                one_val = three_val
                two_point = four_point
                two_val = four_val
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None
                pass
        if three_point:
            if two_point - three_point < 3 or three_val > one_val:
                one_point = three_point
                one_val = three_val
                two_point = None
                two_val = None
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None
            pass
        if two_point:
            if one_point - two_point < 5:
                one_point = None
                one_val = None
                two_point = None
                two_val = None
                three_point = None
                three_val = None
                four_point = None
                four_val = None
                five_point = None
                five_val = None
                six_point = None
                six_val = None
                seven_point = None
                seven_val = None

        if one_point is None:
            if one_val is None:
                one_val = df.iloc[i]['highestPrice']
            else:
                if one_val < df.iloc[i]['highestPrice']:
                    one_val = df.iloc[i]['highestPrice']
                else:
                    if one_val*(1-gap_pct) <= df.iloc[i]['highestPrice']:
                        pass
                    else:
                        one_point = i + 1
                        two_val = df.iloc[i]['lowestPrice']
        if one_point and two_point is None:
            if two_val is None:
                two_val = df.iloc[i]['lowestPrice']
            else:
                if two_val > df.iloc[i]['lowestPrice']:
                    two_val = df.iloc[i]['lowestPrice']
                else:
                    if two_val*(1+gap_pct) >= df.iloc[i]['lowestPrice']:
                        pass
                    else:
                        two_point = i+1
                        three_val = df.iloc[i]['highestPrice']
        if one_point and two_point and three_point is None:
            if three_val is None:
                three_val = df.iloc[i]['highestPrice']
            else:
                if three_val < df.iloc[i]['highestPrice']:
                    three_val = df.iloc[i]['highestPrice']
                else:
                    if three_val*(1-gap_pct) <= df.iloc[i]['highestPrice']:
                        pass
                    else:
                        three_point = i+1
                        four_val = df.iloc[i]['lowestPrice']
        if one_point and two_point and three_point and four_point is None:
            if four_val is None:
                four_val = df.iloc[i]['lowestPrice']
            else:
                if four_val > df.iloc[i]['lowestPrice']:
                    four_val = df.iloc[i]['lowestPrice']
                else:
                    if four_val*(1+gap_pct) >= df.iloc[i]['lowestPrice']:
                        pass
                    else:
                        four_point = i + 1
                        five_val = df.iloc[i]['highestPrice']
        if one_point and two_point and three_point and four_point and five_point is None:
            if five_val is None:
                five_val = df.iloc[i]['highestPrice']
            else:
                if five_val < df.iloc[i]['highestPrice']:
                    five_val = df.iloc[i]['highestPrice']
                else:
                    if five_val*(1-gap_pct) <= df.iloc[i]['highestPrice']:
                        pass
                    else:
                        five_point = i + 1
                        six_val = df.iloc[i]['lowestPrice']
        if one_point and two_point and three_point and four_point and five_point and six_point is None:
            if six_val is None:
                six_val = df.iloc[i]['lowestPrice']
            else:
                if six_val > df.iloc[i]['lowestPrice']:
                    six_val = df.iloc[i]['lowestPrice']
                else:
                    if six_val*(1+gap_pct) >= df.iloc[i]['lowestPrice']:
                        pass
                    else:
                        six_point = i+1
                        seven_val = df.iloc[i]['highestPrice']
        if one_point and two_point and three_point and four_point and five_point and six_point and seven_point is None:
            if seven_val is None:
                seven_val = df.iloc[i]['highestPrice']
            else:
                if seven_val < df.iloc[i]['highestPrice']:
                    seven_val = df.iloc[i]['highestPrice']
                else:
                    if seven_val*(1-gap_pct) <= df.iloc[i]['highestPrice']:
                        pass
                    else:
                        seven_point = i + 1
        pass


    res_duration = []
    res_line = []
    res_table = []
    if one_point and two_point and three_point and four_point and five_point and six_point and seven_point:
        res_duration.append([seven_point,one_point])
        res_line.append([(five_point,five_val),(three_point,three_val)])
        res_table = [
            ['1',df.iloc[one_point]['tradeDate'],one_val],
            ['2',df.iloc[two_point]['tradeDate'],two_val],
            ['3',df.iloc[three_point]['tradeDate'],three_val],
            ['4',df.iloc[four_point]['tradeDate'],four_val],
            ['5',df.iloc[five_point]['tradeDate'],five_val],
            ['6',df.iloc[six_point]['tradeDate'],six_val],
            ['7',df.iloc[seven_point]['tradeDate'],seven_val]
        ]
        pass

    file_name = os.path.basename(daily_file_path)
    title_str = file_name.split('.')[0]

    line_data = {
        'title_str':title_str,
        'whole_header':['日期','收','开','高','低'],
        'whole_df':df,
        'whole_pd_header':['tradeDate','closePrice','openPrice','highestPrice','lowestPrice'],
        'start_date_str':start_date_str,
        'end_date_str':end_date_str,
        'res_duration':res_duration,
        'res_line':res_line,
        'res_table':res_table,
        'temp':len(res_duration)
    }
    return line_data

工具代码

导入需要的包

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

pygtgraph 日期横坐标控件、蜡烛图控件、分页表格控件,请查看该博文

 K线与结果显示控件

class PyQtGraphKWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()
    def init_data(self):
        # https://www.sioe.cn/yingyong/yanse-rgb-16/
        # self.color_line = (30, 144, 255)
        self.color_line = (255, 255, 0)
        # 0 幽灵的白色; 1 纯黄; 2 紫红色; 3 纯绿; 4 道奇蓝
        self.color_list = [(248, 248, 255), (255, 255, 0), (255, 0, 255), (0, 128, 0), (30, 144, 255)]
        self.main_fixed_target_list = []  # 主体固定曲线,不能被删除
        self.whole_df = None
        self.whole_header = None
        self.whole_pd_header = None
        self.current_whole_data = None
        self.current_whole_df = None
        self.res_duration = None
        self.res_line = None
        self.res_table = None
        pass
    def init_ui(self):
        self.whole_duration_label = QtWidgets.QLabel('左边界~右边界')

        self.title_label = QtWidgets.QLabel('执行过程查看')
        self.title_label.setAlignment(Qt.AlignCenter)
        self.title_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')

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

        layout_right = QtWidgets.QVBoxLayout()
        layout_right.addWidget(self.title_label)
        layout_right.addWidget(self.whole_duration_label)
        layout_right.addWidget(self.pw)
        self.setLayout(layout_right)
        pass

    def set_data(self, data: Dict[str, Any]):
        title_str = data['title_str']
        whole_header = data['whole_header']
        whole_df = data['whole_df']
        whole_pd_header = data['whole_pd_header']
        res_duration = data['res_duration']
        res_line = data['res_line']
        res_table = data['res_table']

        self.whole_header = whole_header
        self.whole_df = whole_df
        self.whole_pd_header = whole_pd_header
        self.res_duration = res_duration
        self.res_line = res_line
        self.res_table = res_table

        self.title_label.setText(title_str)
        self.whole_duration_label.setText(f"{self.whole_df.iloc[0]['tradeDate']}~{self.whole_df.iloc[-1]['tradeDate']}")

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

    def caculate_and_show_data(self):
        df = self.current_whole_df.copy()
        df.reset_index(inplace=True)
        df['i_count'] = [i for i in range(len(df))]
        tradeDate_list = df['tradeDate'].values.tolist()
        x = range(len(df))
        xTick_show = []
        x_dur = math.ceil(len(df) / 20)
        for i in range(0, len(df), x_dur):
            xTick_show.append((i, tradeDate_list[i]))
        if len(df) % 20 != 0:
            xTick_show.append((len(df) - 1, tradeDate_list[-1]))
        candle_data = []
        for i, row in df.iterrows():
            candle_data.append(
                (row['i_count'], row['openPrice'], row['closePrice'], row['lowestPrice'], row['highestPrice']))

        self.current_whole_data = df.loc[:, self.whole_pd_header].values.tolist()
        # 开始配置显示的内容
        self.pw.clear()

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

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

        # 标记技术图形 start
        if len(self.res_duration)>0:
            for item in self.res_duration:
                signal_fiexed_target = pg.LinearRegionItem([item[0], item[1]],
                                                           movable=False, brush=(
                        self.color_line[0], self.color_line[1], self.color_line[2], 50))
                self.pw.addItem(signal_fiexed_target)
            pass
        if len(self.res_line)>0:
            for item in self.res_line:
                angle = math.atan2((item[1][1] - item[0][1]),
                                   (item[1][0] - item[0][0]))
                theta = angle * (180 / math.pi)
                signal_fiexed_target = pg.InfiniteLine(pos=item[0], movable=False, angle=theta,
                                                       pen=pg.mkPen({'color': self.color_line, 'width': 1}))
                self.pw.addItem(signal_fiexed_target)
            pass
        # 标记技术图形 end


        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.vb = self.pw.getViewBox()
        self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.pw.enableAutoRange()
        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_whole_data):
                target_data = self.current_whole_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())
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())
        pass

    def mouseClicked(self, evt):
        pass

    def updateViews(self):
        pass
    pass

主程序控件

class StrategeMainWidget(QtWidgets.QWidget):
    signal_runcode = QtCore.pyqtSignal(object)
    signal_time = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()
        self.thread_run: Thread = None
        self.thread_time: Thread = None

        self.init_data()
        self.init_ui()
        self.register_event()
        pass
    def init_data(self):
        self.pre_output_dir = './'
        self.results_output_dir = './k_recognition_output/'
        self.please_select_str: str = '--请选择--'
        self.k_strategy_path: str = '../shape_recognition_strategy/'
        self.stratege_run_start_time = None
        self.stratege_start = False
        self.current_stratege_py_str: str = ''
        self.dailydata_path:str = ''
        self.k_strategy_map: Dict[str,Any] = {
            '转势技术图形':['头肩顶','头肩底','复合头肩模式','圆底(蝶形底)','圆顶(蝶形顶)','双底(W底)','双顶(M顶)','三重顶和三重底','潜伏底','V形反转(V形底)','倒置V形反转(尖顶)','缺口','底部岛形反转','顶部岛形反转'],
            '整理技术图形':['上升三角形','下降三角形','底部三角形','扩散三角形(喇叭形)','收敛三角形','菱形(钻石形)','上升旗形(下飘旗形)','下降旗形(上飘旗形)','上升楔形','下降楔形','矩形(箱体)']
        }
        self.strategyname_code_map:Dict[str,str] = {
            '头肩顶': '',
            '头肩底': '',
            '复合头肩模式': '000',
            '圆底(蝶形底)': '',
            '圆顶(蝶形顶)': '',
            '双底(W底)': '',
            '双顶(M顶)': '',
            '三重顶和三重底': '',
            '潜伏底': '',
            'V形反转(V形底)': '',
            '倒置V形反转(尖顶)': '',
            '缺口': '',
            '底部岛形反转': '',
            '顶部岛形反转': '',
            '上升三角形': '',
            '下降三角形': '',
            '底部三角形': '',
            '扩散三角形(喇叭形)': '',
            '收敛三角形': '',
            '菱形(钻石形)': '',
            '上升旗形(下飘旗形)': '',
            '下降旗形(上飘旗形)': '',
            '上升楔形': '',
            '下降楔形': '',
            '矩形(箱体)': ''
        }
        self.table_header: List = ['点位','日期','值']
        pass
    def init_ui(self):
        self.setWindowTitle('股票技术图形识别工具')
        tip_0 = QtWidgets.QLabel('股票日数据文件:')
        self.dailydata_filepath_lineedit = QtWidgets.QLineEdit()
        self.dailydata_filepath_lineedit.setReadOnly(True)
        dailydata_choice_btn = QtWidgets.QPushButton('选择文件')
        dailydata_choice_btn.clicked.connect(self.dailydata_choice_btn_clicked)

        layout_top = QtWidgets.QHBoxLayout()
        layout_top.addWidget(tip_0)
        layout_top.addWidget(self.dailydata_filepath_lineedit)
        layout_top.addWidget(dailydata_choice_btn)
        layout_top.addStretch(1)

        tip_1 = QtWidgets.QLabel('类别:')
        self.type_combox = QtWidgets.QComboBox()
        self.type_combox.addItem(self.please_select_str)
        self.type_combox.addItems(list(self.k_strategy_map.keys()))
        self.type_combox.currentIndexChanged.connect(self.type_combox_currentIndexChanged)

        tip_2 = QtWidgets.QLabel('技术图形:')
        self.shape_combox = QtWidgets.QComboBox()
        self.shape_combox.addItem(self.please_select_str)
        self.shape_combox.currentIndexChanged.connect(self.shape_combox_currentIndexChanged)

        self.run_btn = QtWidgets.QPushButton('运行')
        self.run_btn.clicked.connect(self.run_btn_clicked)

        self.time_label = QtWidgets.QLabel('')

        layout_combox = QtWidgets.QFormLayout()
        layout_combox.addRow(tip_1,self.type_combox)
        layout_combox.addRow(tip_2,self.shape_combox)
        layout_combox.addRow(self.run_btn,self.time_label)

        self.code_textedit = QtWidgets.QTextEdit()
        self.code_textedit.setReadOnly(True)

        self.results_table = PageTableWidget()
        self.results_table.set_table_init_data({'headers':self.table_header})

        layout_left = QtWidgets.QVBoxLayout()
        layout_left.addLayout(layout_combox)
        layout_left.addWidget(self.code_textedit)
        layout_left.addWidget(self.results_table)

        self.line_widget = PyQtGraphKWidget()

        layout_down = QtWidgets.QHBoxLayout()
        layout_down.addLayout(layout_left,1)
        layout_down.addWidget(self.line_widget,2)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_top)
        layout.addLayout(layout_down)
        self.setLayout(layout)
        pass
    def register_event(self):
        self.signal_runcode.connect(self.thread_run_excuted)
        self.signal_time.connect(self.thread_time_excuted)
        pass
    def dailydata_choice_btn_clicked(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            '打开股票日数据所在文件',
            self.pre_output_dir
        )
        if not path:
            return
        self.dailydata_filepath_lineedit.setText(path)
        pass
    def type_combox_currentIndexChanged(self,cur_i:int):
        cur_txt = self.type_combox.currentText()
        if not cur_txt or cur_txt == self.please_select_str:
            return
        shape_name_list = self.k_strategy_map[cur_txt]
        self.shape_combox.clear()
        self.shape_combox.addItem(self.please_select_str)
        self.shape_combox.addItems(shape_name_list)
        pass
    def shape_combox_currentIndexChanged(self,cur_i:int):
        cur_txt = self.shape_combox.currentText()
        if not cur_txt or cur_txt == self.please_select_str:
            return
        cur_strategy_name = self.strategyname_code_map[cur_txt]
        if cur_strategy_name == '000':
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '代码实现太复杂,还是靠肉眼吧。。。',
                QtWidgets.QMessageBox.Yes
            )
            return


        if len(cur_strategy_name)<=0:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '该K线形态的策略还没上线',
                QtWidgets.QMessageBox.Yes
            )
            return
        strategy_file_path = self.k_strategy_path + cur_strategy_name
        with open(strategy_file_path,'r',encoding='utf-8') as fr:
            py_str = fr.read()
        if len(py_str)<=20:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '策略文件代码为空',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.code_textedit.setPlainText(py_str)
        pass
    def run_btn_clicked(self):
        '''运行按钮'''
        # 检查股票日数据文件夹
        dailydata_filepath = self.dailydata_filepath_lineedit.text()
        dailydata_filepath = dailydata_filepath.strip()
        if len(dailydata_filepath)<=0:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择股票日数据文件',
                QtWidgets.QMessageBox.Yes
            )
            return

        py_str = self.code_textedit.toPlainText()
        if len(py_str)<20:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择要执行的策略',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.current_stratege_py_str = py_str

        self.run_btn.setDisabled(True)
        self.shape_combox.setDisabled(True)
        self.stratege_run_start_time = datetime.now()
        self.stratege_start = True

        if self.thread_run:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '有策略正在运行',
                QtWidgets.QMessageBox.Yes
            )
            return
        pre_data = {
            'py_str':py_str,
            'dailydata_filepath':dailydata_filepath
        }
        self.thread_run = Thread(
            target=self.running_run_thread,
            args=(pre_data,)
        )
        self.thread_run.start()
        self.thread_time = Thread(
            target=self.running_time_thread
        )
        self.thread_time.start()
        pass
    def running_run_thread(self,data:Dict[str,Any]):
        '''执行代码线程'''
        py_str = data['py_str']
        dailydata_filepath = data['dailydata_filepath']

        namespace = {}
        fun_stragegy = compile(py_str,'<string>','exec')
        exec(fun_stragegy,namespace)
        ret = namespace['excute_strategy'](dailydata_filepath)
        self.signal_runcode.emit(ret)
        pass
    def thread_run_excuted(self,data:Dict):
        '''策略代码执行返回结果'''
        self.run_btn.setDisabled(False)
        self.shape_combox.setDisabled(False)

        # 保存结果文件
        self.results_table.set_table_full_data(data['res_table'])

        self.line_widget.set_data(data)

        self.thread_run = None
        self.thread_time = None
        self.stratege_start = False

        QtWidgets.QMessageBox.information(
            self,
            '提示',
            '当前策略运行完毕',
            QtWidgets.QMessageBox.Yes
        )
        pass
    def running_time_thread(self):
        '''计时线程'''
        while self.stratege_start:
            now = datetime.now()
            interval_time = (now-self.stratege_run_start_time).seconds
            res_map = {'res':interval_time}
            self.signal_time.emit(res_map)
            time.sleep(1)
        pass
    def thread_time_excuted(self,data:Dict):
        '''计时返回结果'''
        res = data['res']
        self.time_label.setText(f"{res}s")
        pass

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        if self.thread_time:
            self.thread_time = None
        if self.thread_run:
            self.thread_run = None
        self.close()

工具使用

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

1. 在入口代码对应的py文件的上一级目录下创建 shape_recognition_strategy 文件夹,后续K线技术图形判别的策略代码都保存在这个文件夹下

 

数据

链接:https://pan.baidu.com/s/1acghH4GQyu_OaOUmEjPdHw 
提取码:6toe

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyQt5中,_del_是一个特殊的方法,用于对象的删除和垃圾回收。当一个对象的引用计数降为零时,_del_方法会被调用。然而,存在一些情况下,当应用程序使用_pyqt5.pyd时,调用_del_方法时可能会导致闪退。闪退的原因可能有以下几点: 1. 对象的引用计数错误:如果对象的引用计数不正确地被管理或跟踪,可能会导致调用_del_方法时出现内存访问错误,从而导致闪退。 2. PySide2内存管理问题:在使用PySide2时,由于其与Qt的集成方式不同,可能存在内存管理方面的问题,可能导致闪退。 3. PyQt5版本不兼容:如果使用的PyQt5版本与其他依赖库或Python版本不兼容,可能会导致调用_del_方法时出现闪退。 为了解决这个问题,可以尝试以下几点: 1. 检查代码逻辑:确保正确管理对象的引用计数,尽可能避免在_del_方法中进行复杂的操作,以减少闪退的可能性。 2. 更新到最新版本的PyQt5:确保使用的PyQt5版本与其他依赖库和Python版本兼容,并从官方网站或PyPi上下载最新版本的PyQt5。 3. 使用其他版本的Qt绑定库:考虑尝试使用其他的Qt绑定库,如PySide2,看是否可以解决闪退的问题。 总结而言,PyQt5 _del_方法闪退的原因可能是对象引用计数错误、PySide2内存管理问题或PyQt5版本不兼容等。为了解决这个问题,可以考虑检查代码逻辑,更新到最新版本的PyQt5,或尝试使用其他的Qt绑定库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值