pyqt5股票实时数据统计软件

本博客介绍了一款使用PyQt5和ECharts开发的股票实时数据展示软件,该软件能够从网络获取大盘及个股数据,并实现实时更新。通过自定义线程处理数据,结合Model/View模式展示大盘数据,支持K线图查看。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大盘行情界面

实现方法:http://qt.gtimg.cn网站和tushare作为数据来源,pyqt5和echart作为软件界面展示
在这里插入图片描述
在这里插入图片描述

数据线程

#大盘页面数据类》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
class DaPanDataClass(QThread):
    sig = pyqtSignal(tuple)
    sig_tag = pyqtSignal(list)
    isRun = True
    def __init__(self):
        super(DaPanDataClass, self).__init__()
    def get_san_data(self,url_code):
        urlt = "http://qt.gtimg.cn/q=s_{}".format(','.join(url_code))
        response = requests.get(urlt)
        if response.text != "":
            # print(response.text)
            ss = response.text.split(';')
            for i in ss:
                if i.split("=")[-1] != "":
                    strings = i.split("=")[-1][1:-1]
                    tem_list = strings.split('~')
                    # print(tem_list)
                    if len(tem_list) > 1:
                        res = (tem_list[1],float(tem_list[3]),float(tem_list[4]),tem_list[5],tem_list[2])
                        self.sig.emit(res)

    def get_tag_data(self,url_code):
        data = []
        url = "http://qt.gtimg.cn/q=s_{}".format(','.join(url_code))
        response = requests.get(url)
        if response.text != "":
            # print(response.text)
            ss = response.text.split(';')
            for i in ss:
                if i.split("=")[-1] != "":
                    strings = i.split("=")[-1][1:-1]
                    tem_list = strings.split('~')
                    # print(tem_list)
                    if len(tem_list) > 1:
                        res = (tem_list[1],tem_list[2],float(tem_list[5]),float(tem_list[3]),float(tem_list[4]))
                        data.append(res)
            self.sig_tag.emit(data)
    def run(self):
        while True:
            if self.isRun == False:
                break
            self.get_san_data(['sh000001','s_sz399001','s_sz399006','s_sh000002'])
            self.get_tag_data(['sz399300','s_sz399333','s_sz399335','s_sz399337','s_sz399339','s_sz399352','s_sz399361','s_sz399363',
                  's_sz399367','s_sz399368','s_sz399386','s_sz399387','s_sz399388','s_sz399389','s_sz399394','s_sz399395',
                  's_sz399431', 's_sz399432', 's_sz399433', 's_sz399434', 's_sz399435', 's_sz399436','s_sz399437','s_sz399438',
                  's_sz399439', 's_sz399440', 's_sz399441','s_sz399396','s_sz399397','s_sz399414','s_sz399300','s_sz399330',
                  's_sh000002','s_sh000066','s_sh000004','s_sh000005','s_sh000006','s_sh000007','s_sh000008','s_sh000009',
                  's_sh000010','s_sh000011','s_sh000012','s_sh000016','s_sh000017','s_sh000018','s_sh000025','s_sh000027',
                  's_sh000032','s_sh000033','s_sh000034','s_sh000036','s_sh000037','s_sh000039','s_sh000001','s_sz399001',
                   's_sz399006','s_sh000002'])
            time.sleep(1)

#K线数据类》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
class KData(QThread):
    def __init__(self):
        super(KData,self).__init__()
        self.code = None
        self.name = None
    def getcode(self):
        with open('temcode','r',encoding='utf8')as f:
            tem = f.read().strip().split(',')
            self.code = tem[1]
            self.name = tem[0]
    def get_data(self,ky='D'):
        self.getcode()
        df = ts.get_hist_data(self.code,ktype=ky)
        if df is not None:
            a = [x for x in df.index]
            df.insert(0, 'date', a)
            df = df.reset_index(level=None, drop=True, col_level=0, col_fill='')
            ac = [df['date'].values, df['open'].values, df['close'].values, df['low'].values, df['high'].values,
                  df['volume'].values]
            data = list(map(list, zip(*ac)))
            data.reverse()
            return data
        else:
            print('数据刷新失败,请检查网络')
            return

model

headerData控制表头,data函数实现数据设置。
Qt.TextColorRole实现控制数据内容的字体颜色,Qt.TextAlignmentRole实现数据字体的显示格式update_model实现数据刷新,self.layoutAboutToBeChanged.emit() self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(self.rowCount(0), self.columnCount(0)))self.layoutChanged.emit()实现数据刷新不影响选中行

from PyQt5.QtCore import QAbstractTableModel,Qt,QVariant,QTimer
from PyQt5.QtGui import QFont,QColor,QBrush

class ModelDapan(QAbstractTableModel):
    def __init__(self):
        super(ModelDapan, self).__init__()
        self.data_list = []
    def columnCount(self, parent) -> int:
        return 5
    def rowCount(self, parent) -> int:
        return len(self.data_list)
    def headerData(self, section, orientation, role):
        if role==Qt.DisplayRole and orientation==Qt.Horizontal:
            headers = ["名称","代码","涨跌%","当前价格","涨跌"]
            for n in range(5):
                if section==n:
                    return headers[n]
        else:
            return QVariant()
    def data(self, index, role):
        col = index.column()
        row = index.row()
        if not index.isValid():
            return QVariant()
        if role==Qt.TextAlignmentRole:
            return Qt.AlignCenter
        if role==Qt.TextColorRole:
            if col==2:
                if self.data_list[row][2]<0:
                    return QBrush(QColor(Qt.green))
                if self.data_list[row][2]>0:
                    return QBrush(QColor(Qt.red))
            if col==4:
                if self.data_list[row][4]<0:
                    return QBrush(QColor(Qt.green))
                if self.data_list[row][4]>0:
                    return QBrush(QColor(Qt.red))
        if role==Qt.DisplayRole:
            for i in range(5):
                if col==i:
                    return self.data_list[row][i]
        else:
            return QVariant()
    def update_model(self,data):
        self.data_list = data
        self.layoutAboutToBeChanged.emit()
        self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(self.rowCount(0), self.columnCount(0)))
        self.layoutChanged.emit()

view

通过QSortFilterProxyModel实现表格排序,dapan数据线程类绑定model的update_model函数,实现tableview的数据实时刷新

#tableview显示功能实现+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def model_fun(self):
        self.model = ModelDapan()
        self.proxymodel = QSortFilterProxyModel(self)
        self.proxymodel.setSourceModel(self.model)
        self.tableView.setModel(self.proxymodel)                            #表格按列排序
        self.tableView.setSortingEnabled(True)                              #开启表头按列排序
        self.tableView.verticalHeader().setHidden(True)                     #隐藏序号列
        self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)  #设置选中行
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.clicked.connect(self.selectRow)                      #绑定单击选中行响应函数

        self.dapadataThread.sig_tag.connect(self.model.update_model)        #数据绑定model实时刷新数据

大盘widget类

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QPushButton,QAbstractItemView
from PyQt5.QtCore import Qt,QSortFilterProxyModel,QEvent,QUrl,pyqtSignal
from PyQt5.QtWebEngineWidgets import QWebEngineView,QWebEngineSettings
from gui.dapan_gui import Ui_Form
from data.data_class import DaPanDataClass,KData
from model.model_dapan import ModelDapan
from echartsdir.Kline_widget import MainWindow

class DaPanWidget(QWidget,Ui_Form):
    sig_code = pyqtSignal(str)
    def __init__(self):
        super(DaPanWidget,self).__init__()
        self.setupUi(self)

        self.dapadataThread = DaPanDataClass()
        self.dapadataThread.start()
        self.dapadataThread.sig.connect(self.push_update)
        self.model_fun()

        self.widget = MainWindow()
        self.gridLayout_3.addWidget(self.widget)
        self.pushButton_zh.clicked.connect(self.solt_zh)
        self.pushButton_sz.clicked.connect(self.solt_sz)
        self.pushButton_cy.clicked.connect(self.solt_cy)
    #上证指数按钮+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def solt_zh(self):
        on = self.pushButton_zh.text().split('\n')
        s = on[0]+','+'sh'+on[1]
        with open('temcode','w',encoding='utf8')as f:
            f.write(s)
        self.widget.update_data_day()
    #深圳指数按钮+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def solt_sz(self):
        on = self.pushButton_sz.text().split('\n')
        s = on[0] + ',' + 'sz'+on[1]
        with open('temcode', 'w', encoding='utf8')as f:
            f.write(s)
        self.widget.update_data_day()
    #创业板指数按钮+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def solt_cy(self):
        on = self.pushButton_cy.text().split('\n')
        s = on[0] + ',' + on[1]
        with open('temcode', 'w', encoding='utf8')as f:
            f.write(s)
        self.widget.update_data_day()
    #三个指标数据实时刷新槽函数+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def push_update(self,one):
        if one[0]=='上证指数':
            self.pushButton_zh.setText("{}\n{}\n{}\n{}  {}%".format(one[0],one[4],one[1],one[2],one[3]))
            self.btn_three(self.pushButton_zh,one)
        if one[0]=='深证成指':
            self.pushButton_sz.setText("{}\n{}\n{}\n{}  {}%".format(one[0],one[4],one[1],one[2],one[3]))
            self.btn_three(self.pushButton_sz, one)
        if one[0]=='创业板指':
            self.pushButton_cy.setText("{}\n{}\n{}\n{}  {}%".format(one[0],one[4],one[1],one[2],one[3]))
            self.btn_three(self.pushButton_cy, one)
    #三个大按钮判断大小改变颜色+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def btn_three(self,btn,one):
        if one[2]<0:
            btn.setStyleSheet("QPushButton { background-color: rgb(69, 83, 100);border-radius: 3px; color: rgb(1, 247, 2);}"
                                        "QPushButton:hover { background-color: rgb(96, 121, 139)}")
                                        # "QPushButton:checked { background-color: rgb(208, 227, 253);}")
        if one[2]>0:
            btn.setStyleSheet("QPushButton { background-color: rgb(69, 83, 100);border-radius: 3px; color: red;}"
                              "QPushButton:hover { background-color: rgb(96, 121, 139)}")
                              # "QPushButton:checked { background-color: rgb(208, 227, 253);}")
    #tableview显示功能实现+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def model_fun(self):
        self.model = ModelDapan()
        self.proxymodel = QSortFilterProxyModel(self)
        self.proxymodel.setSourceModel(self.model)
        self.tableView.setModel(self.proxymodel)                            #表格按列排序
        self.tableView.setSortingEnabled(True)                              #开启表头按列排序
        self.tableView.verticalHeader().setHidden(True)                     #隐藏序号列
        self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)  #设置选中行
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.clicked.connect(self.selectRow)                      #绑定单击选中行响应函数
        self.dapadataThread.sig_tag.connect(self.model.update_model)        #数据绑定model实时刷新数据
    #单击响应行函数++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def selectRow(self, index):
        #输出第一个字段
        model = self.tableView.model()
        j = model.index(index.row(),0)
        i = model.index(index.row(),1)
        code = model.data(i)
        if code.startswith('6'):
            code = 'sh'+code
        else:
            code = 'sz'+code
        s = model.data(j) +','+ code
        print(s)
        with open('temcode','w',encoding='utf8')as f:
            f.write(s)
        #5分钟按钮响应
        if self.widget.pushButton_2.isChecked():
            self.widget.update_data_5_min()
        #15分钟按钮响应
        if self.widget.pushButton_3.isChecked():
            self.widget.update_data_15_min()
        #60分钟按钮响应
        if self.widget.pushButton_4.isChecked():
            self.widget.update_data_60_min()
        #日线按钮响应
        if self.widget.pushButton_5.isChecked():
            self.widget.update_data_day()
        #周线按钮响应
        if self.widget.pushButton_6.isChecked():
            self.widget.update_data_wend()
        #月线按钮响应
        if self.widget.pushButton_7.isChecked():
            self.widget.update_data_mon()

自选股界面

实现输入联想提示

    def line_edit_show(self):
        with open('codelist','r',encoding='utf-8')as f:
            temlist = f.readlines()
        temlist = QCompleter(temlist)
        temlist.setCaseSensitivity(Qt.CaseInsensitive)
        temlist.setFilterMode(Qt.MatchContains)
        self.lineEdit.setCompleter((temlist))

实现加自选股

    def solt_add_stock(self):
        input = self.lineEdit.text()
        if input != "":
            temdata = input.split('\t')
            if temdata[0].startswith('6'):
                code = 'sh' + temdata[0]
            else:
                code = 'sz' + temdata[0]
            name = temdata[1]

            mydb = MyDataDB()
            mydb.input_data(code,name)
            mydb.close()

实现减自选股

    def solt_sub_stock(self):
        self.model.removeRow(self.select_row)
        with open('temcode', 'r', encoding='utf8')as f:
            tem = f.readline()
            if tem != "":
                code = tem.split(',')[1]
                if code.startswith("6"):
                    code='sh'+code
                else:
                    code='sz'+code
        mydb = MyDataDB()
        mydb.delete_data(code)
        mydb.close()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值