├── README.md ├── baoStock.pyproject ├── baseInformation.py ├── config.ini ├── drawCandle.py ├── drawTimeShare.py ├── figureCanvas.py ├── form.ui ├── getDate.py ├── getEastData.py ├── globalVariable.py ├── key.wav ├── list ├── abbreviation_index_list.csv ├── abbreviation_list.csv ├── concept_industry_board.csv ├── index.csv ├── index_list.csv ├── my_stock.csv ├── rising_speed.csv ├── rising_speed.txt └── stock_list.csv ├── logo.ico ├── mainwindow.py ├── modelAnalysisTable.py ├── modelTableStock.py ├── modelTimeShare.py ├── placeOrder.py ├── stockBaseInformation.py ├── stockInformation.py ├── tableStock.py ├── threadDealTimeShare.py ├── threadGetCandle.py ├── threadIndex.py ├── threadNewsReport.py ├── threadRealTime.py ├── threadTable.py ├── ui_form.py └── worldIndex.py /README.md: -------------------------------------------------------------------------------- 1 | -# stock-quotes 有问题联系QQ:109206895 2 | 3 | 股票行情软件 4 | 5 | 因为一般看盘软件都无法在linux下使用,所以自己干脆写了一个跨平台的。 6 | 7 | python+pyqt。 8 | 9 | 查看全球主要指数,实盘美股和港股。 10 | 11 | A股板块、指数、个股k线图均线资料查看、搜索,输入拼音查询。 12 | 13 | F10资料,主要指标,经营分析,3大报表,板块资金流。 14 | 15 | 实时语音播报当前新闻 16 | 17 | 后续功能再慢慢加。。。。。。 18 | 19 | 需要解决的问题: 20 | 21 | 一、可以实时浏览所有股票(A股,美股,港股) 22 | 23 | ['代码','名称','最新价','涨跌幅','换手率','成交额','市盈率','成交量','总市值','流通市值','今年涨幅','60日涨幅','涨速','最高','最低','今开','昨收'] 24 | 表格数据用QTableView组件,使用model/view模型控制显示的颜色,格式。 25 | 26 | A股,美股,港股全部都使用同样的数据结构,这样可以很方便界面的切换。一个model模式就可以了。在做其它(比如资金流分析)时,再建一个model模式。 27 | 28 | 看盘的主界面上分了4大块区域(个人习惯),一个显示所有股票的实时数据,一个只显示涨速,一个自选股,最右边显示个股的详细信息,包括分时图,买卖一到五及其分笔成交细节。 29 | 30 | 点击表格任何一列实现顺序、倒序排列。比如按涨幅,成交额排序 31 | 32 | ![Snipaste_2022-11-06_19-20-46](https://user-images.githubusercontent.com/29307274/200167923-75be3496-439d-48f6-8e2b-42c7edffc02f.jpg) 33 | 34 | 二、实现鼠标和键盘操作 35 | 36 | 重载鼠标的单击和双击,单击显示个股详细信息,双击显示个股的k线图。鼠标滚轮,右键功能 37 | 38 | 重载键盘事件,回车也可显示个股的k线图。输入个股、指数、板块的代码,拼音都可查询。ESC键,翻页键。F10查看个股报表资讯 39 | 40 | 三、需要多线程,刷新数据的同时界面不能卡顿。 41 | 42 | 可能是数据原因或者python的原因,为了保证实时,同时开了6个线程 43 | 44 | 一个用于刷新全球实时指数 45 | 46 | 一个刷新所有股票的实时数据 47 | 48 | 一个刷新买卖一到五的数据 49 | 50 | 一个刷新分笔成交数据 51 | 52 | 一个实时语音播报 53 | 54 | 一个用于获取k线图数据,这个觉得有些多余,但是在开盘阶段如果想看k线图,偶尔会出现卡顿的情况,所以单独开了一个线程。 55 | 56 | 四、目前所遇到问题: 57 | 58 | 在盘后操作基本还是很流畅的,反应速度也很快。主要在开盘阶段,因为每5秒刷新一次界面,如果正好在刷新的时刻单击或者双击某一行股票,就会出现卡顿现象。我感觉可能是ui刷新速度不够快,同一时刻子线程均发信号要求刷新界面导致。又或者是我代码有问题,或者python的速度问题。 59 | 由于以前没有学过python,临时从c++转过来,基本是按照c++的编程思路来的。也不知道合适不,欢迎大家多提建议。 60 | 61 | ![Snipaste_2022-11-06_19-21-27](https://user-images.githubusercontent.com/29307274/200167939-b4401eac-f204-4335-bc96-82d1f71e4251.jpg) 62 | ![Snipaste_2022-11-06_19-22-01](https://user-images.githubusercontent.com/29307274/200167941-64237622-e2e6-46e1-a52c-1fd7183637cf.jpg) 63 | ![Snipaste_2022-11-06_19-22-36](https://user-images.githubusercontent.com/29307274/200167942-01991042-fa3d-43b6-8f2a-eec6aca27c92.jpg) 64 | ![Snipaste_2022-11-06_19-24-37](https://user-images.githubusercontent.com/29307274/200167943-a318c9cd-16b0-47c1-b1d6-02b601d595a0.jpg) 65 | ![Snipaste_2022-11-06_19-25-25](https://user-images.githubusercontent.com/29307274/200167945-a9750d43-b587-4a5e-81db-6fa194930a1f.jpg) 66 | ![Snipaste_2022-11-06_19-25-57](https://user-images.githubusercontent.com/29307274/200167946-8cfeccf3-7a48-4cde-98b8-2baf4644a9e2.jpg) 67 | -------------------------------------------------------------------------------- /baoStock.pyproject: -------------------------------------------------------------------------------- 1 | { 2 | "files": ["baseInformation.py","threadGetCandle.py","threadNewsReport.py","modelTimeShare.py","stockInformation.py","getDate.py","form.ui","globalVariable.py","threadIndex.py","threadTable.py","modelTableStock.py","placeOrder.py","tableStock.py","drawCandle.py","threadDealTimeShare.py","mainwindow.py","threadRealTime.py","modelAnalysisTable.py","drawTimeShare.py","worldIndex.py","getEastData.py"] 3 | } 4 | -------------------------------------------------------------------------------- /baseInformation.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6.QtWidgets import QWidget,QGridLayout,QLabel,QFrame,QTextEdit,QPushButton 6 | from PySide6.QtCore import Qt 7 | from PySide6.QtGui import QColor,QTextCharFormat,QTextCursor,QFont 8 | import globalVariable 9 | 10 | class BaseInformation(): 11 | def __init__(self,parent): 12 | self.parent=parent 13 | super().__init__() 14 | self.isKC=False 15 | self.base_information(self.parent.stock_code,self.parent.name) 16 | self.buy_sell_information() 17 | self.initLabel(self.parent.ui.statusbar) 18 | self.text_count=14 19 | 20 | def base_information(self,code,name): 21 | #基本信息显示初始化 22 | self.base_information_widget=QWidget() 23 | #self.base_information_widget.setMaximumHeight(150) 24 | base_information_layout=QGridLayout() 25 | base_information_layout.setSpacing(2) 26 | base_information_layout.setContentsMargins(10,0,0,0) 27 | self.base_information_widget.setLayout(base_information_layout) 28 | self.code_label=QLabel(code) 29 | self.name_label=QLabel(name) 30 | self.code_label.setStyleSheet("QLabel{font:bold;color:blue}") 31 | self.name_label.setStyleSheet("QLabel{font:bold 26px;font-family:微软雅黑;color:red}") 32 | base_information_layout.addWidget(self.code_label,0,0,2,1) 33 | base_information_layout.addWidget(self.name_label,0,1,2,3) 34 | 35 | self.base_info=locals() 36 | base_info_name=['现价','涨幅','换手','成交额','总股本','总市值','PE(静)','A股上涨', 37 | '今开','最高','最低','成交量(手)','流通股','','PE(动)','A股下跌'] 38 | base_info_var=['self.now_price','self.pctChg','self.turn','self.amount','self.Issued_Capital',\ 39 | 'self.total_captial','self.pe_static','rise','self.open','self.high','self.low',\ 40 | 'self.volume','self.Negotiable_Capital','self.earnings','self.pe','self.fall'] 41 | base_info_data_var=['self.now_price_data','self.pctChg_data','self.turn_data','self.amount_data',\ 42 | 'self.Issued_Capital_data','self.total_captial_data','self.pe_static_data',\ 43 | 'self.rise_data','self.open_data','self.high_data','self.low_data','self.volume_data',\ 44 | 'self.Negotiable_Capital_data','self.earnings_data','self.pe_data','self.fall_data'] 45 | for i in range(16): 46 | self.base_info[base_info_var[i]]=QLabel(base_info_name[i]) 47 | #self.base_info[base_info_var[i]].setMaximumHeight(20) 48 | self.base_info[base_info_var[i]].setStyleSheet("QLabel{font:bold;font-family:微软雅黑}") 49 | self.base_info[base_info_data_var[i]]=QLabel() 50 | #self.base_info[base_info_data_var[i]].setMaximumHeight(20) 51 | 52 | if (i>=2 and i<=6) or (i>=11 and i<=14): 53 | self.base_info[base_info_data_var[i]].setStyleSheet("QLabel{font:bold 14px;color:blue}") 54 | elif i==7: 55 | self.base_info[base_info_data_var[i]].setStyleSheet("QLabel{font:bold 14px;color:red}") 56 | elif i==15: 57 | self.base_info[base_info_data_var[i]].setStyleSheet("QLabel{font:bold 14px;color:green}") 58 | else: 59 | self.base_info[base_info_data_var[i]].setStyleSheet("QLabel{font:bold 14px}") 60 | if i<8: 61 | base_information_layout.addWidget(self.base_info[base_info_var[i]],i+2,0) 62 | base_information_layout.addWidget(self.base_info[base_info_data_var[i]],i+2,1) 63 | else: 64 | base_information_layout.addWidget(self.base_info[base_info_var[i]],i-6,2) 65 | base_information_layout.addWidget(self.base_info[base_info_data_var[i]],i-6,3) 66 | 67 | def flash_base_information_click(self,cur_item,data,name): 68 | #now_close=data.iat[cur_item,2] 69 | pre_close=data.iat[cur_item,16] 70 | self.code_label.setText(str(data.iat[cur_item,0])) 71 | self.name_label.setText(name) 72 | if (globalVariable.getValue()==1 and not globalVariable.isZhMarketDay()) or globalVariable.getValue()==2 or globalVariable.getValue()==5: 73 | if data.iat[cur_item,3]<0: 74 | self.base_info['self.now_price_data'].setPalette(globalVariable.pegreen) 75 | self.base_info['self.pctChg_data'].setPalette(globalVariable.pegreen) 76 | else: 77 | self.base_info['self.now_price_data'].setPalette(globalVariable.pered) 78 | self.base_info['self.pctChg_data'].setPalette(globalVariable.pered) 79 | self.base_info['self.now_price_data'].setText(str(data.iat[cur_item,2])) 80 | self.base_info['self.pctChg_data'].setText(f"{data.iat[cur_item,3]}%") 81 | if data.iat[cur_item,13]pre_close: 195 | fmt.setForeground(QColor("red")) 196 | else: 197 | fmt.setForeground(QColor("black")) 198 | cursor.setPosition(line_len[i]+12,QTextCursor.MoveAnchor); 199 | cursor.setPosition(line_len[i]+12+price_len[i],QTextCursor.KeepAnchor); 200 | cursor.mergeCharFormat(fmt) 201 | if flag_direction[i]==1: 202 | fmt.setForeground(QColor(0,191,0)) 203 | elif flag_direction[i]==2: 204 | fmt.setForeground(QColor("red")) 205 | if flag_pos[i+1]==0: 206 | continue 207 | cursor.setPosition(flag_pos[i+1],QTextCursor.MoveAnchor); 208 | cursor.setPosition(flag_pos[i+1]-1,QTextCursor.KeepAnchor); 209 | cursor.mergeCharFormat(fmt) 210 | 211 | def setIndex(self,sender,isAsia,worldIndexData): 212 | self.base_info['self.Issued_Capital_data'].setText('') 213 | self.base_info['self.Negotiable_Capital_data'].setText('') 214 | self.base_info['self.total_captial_data'].setText('') 215 | self.base_info['self.pe_data'].setText('') 216 | self.base_info['self.pe_static_data'].setText('') 217 | self.base_info['self.earnings_data'].setText('') 218 | for i in range(0,10,2): 219 | self.buy_sell_Var[f'self.sell_price{5-i//2}'].setText('') 220 | self.buy_sell_Var[f'self.sell_num{5-i//2}'].setText('') 221 | self.buy_sell_Var[f'self.buy_price{5-i//2}'].setText('') 222 | self.buy_sell_Var[f'self.buy_num{5-i//2}'].setText('') 223 | if isAsia: 224 | for i in range(3): 225 | if sender==self.createVar[f'self.index{i}']: 226 | if i==2: 227 | if self.createVar['self.index2'].text()==worldIndexData.loc[i,'f14']: 228 | stock_code=worldIndexData.loc[i,'f12'] 229 | name=worldIndexData.loc[i,'f14'] 230 | else: 231 | stock_code=worldIndexData.loc[16,'f12'] 232 | name=worldIndexData.loc[16,'f14'] 233 | else: 234 | stock_code=worldIndexData.loc[i,'f12'] 235 | name=worldIndexData.loc[i,'f14'] 236 | return stock_code,name 237 | 238 | for i in range(3,8): 239 | if sender==self.createVar[f'self.index{i}']: 240 | stock_code=worldIndexData.loc[i,'f12'] 241 | name=worldIndexData.loc[i,'f14'] 242 | break 243 | else: 244 | for i in range(8): 245 | if sender==self.createVar[f'self.index{i}']: 246 | stock_code=worldIndexData.loc[i+8,'f12'] 247 | name=worldIndexData.loc[i+8,'f14'] 248 | break 249 | if sender==self.createVar[f'self.index{8}']: 250 | if self.createVar[f'self.index{8}'].text()=='小型道指': 251 | stock_code='103.YM00Y' 252 | name='小型道指当月连续' 253 | elif self.createVar[f'self.index{8}'].text()=='A50期指': 254 | stock_code='104.CN00Y' 255 | name='A50期指当月连续' 256 | self.time_share_tick.clear() 257 | self.code_label.setText(stock_code) 258 | self.name_label.setText(name) 259 | return stock_code,name 260 | 261 | def initLabel(self,statusbar): 262 | self.createVar=locals() 263 | self.circle=QLabel() 264 | if globalVariable.isZhMarketDay(): 265 | self.circle.setStyleSheet(globalVariable.circle_green_SheetStyle) 266 | else: 267 | self.circle.setStyleSheet(globalVariable.circle_red_SheetStyle) 268 | statusbar.addWidget(self.circle) 269 | 270 | for i in range(9): 271 | self.createVar[f'self.index{i}']=QPushButton() 272 | self.createVar[f'self.index{i}'].setStyleSheet("QPushButton{font:bold;font-family:微软雅黑;}") 273 | self.createVar[f'self.indexData{i}']=QLabel() 274 | self.createVar[f'self.indexData{i}'].setStyleSheet("QLabel{font:bold;font-size:14px;}") 275 | statusbar.addWidget(self.createVar[f'self.index{i}']) 276 | statusbar.addWidget(self.createVar[f'self.indexData{i}']) 277 | 278 | def flashLabel(self,offset,worldIndexData): 279 | for i in range(8): 280 | if (globalVariable.marketNum==1 or globalVariable.marketNum==3) and i==2 and self.isKC: 281 | self.createVar[f'self.index{i}'].setText(worldIndexData.loc[16,'f14']) 282 | if worldIndexData.loc[16,'f3']=='-' or worldIndexData.loc[16,'f3']>=0: 283 | self.createVar[f'self.indexData{i}'].setPalette(globalVariable.pered) 284 | else: 285 | self.createVar[f'self.indexData{i}'].setPalette(globalVariable.pegreen) 286 | self.createVar[f'self.indexData{i}'].setText(f"{worldIndexData.loc[16,'f2']} {worldIndexData.loc[16,'f3']}%") 287 | self.isKC=False 288 | else: 289 | self.createVar[f'self.index{i}'].setText(worldIndexData.loc[i+offset,'f14']) 290 | if worldIndexData.loc[i+offset,'f3']=='-' or worldIndexData.loc[i+offset,'f3']>=0: 291 | self.createVar[f'self.indexData{i}'].setPalette(globalVariable.pered) 292 | else: 293 | self.createVar[f'self.indexData{i}'].setPalette(globalVariable.pegreen) 294 | self.createVar[f'self.indexData{i}'].setText(f"{worldIndexData.loc[i+offset,'f2']} {worldIndexData.loc[i+offset,'f3']}%") 295 | if i==2: 296 | self.isKC=True 297 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [%General] 2 | curTime=2023-03-15 3 | newsReport=True 4 | jinShiNewsReportCurTime=2023-03-15 11:18:39 5 | eastNewsReportCurTime=3151052 6 | Vacation_HK="[123,124,125,405,407,1004,1226,1227]" 7 | Vacation_ZH="[102,123,124,125,126,127,405,501,502,503,622,623,929,1002,1003,1004,1005,1006]" 8 | Vacation_US="[117,220,407,1124,1226]" 9 | northText=说明:\n一、可以双击查询板块成分股或者个股k线资讯\n二、营业部排行的1、2、3、5、10表示上榜后多少天\n三、昨日强势股票可以选择你想要查看的日期\n 10 | -------------------------------------------------------------------------------- /drawCandle.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | import pyqtgraph as pg 4 | from PySide6.QtWidgets import QWidget,QLabel 5 | from PySide6.QtGui import QColor,QPicture,QPainter 6 | from PySide6.QtCore import Signal,QPointF,QRectF 7 | import pandas as pd 8 | import datetime 9 | 10 | class DrawChart(QWidget): 11 | _signal=Signal() 12 | def __init__(self, data): 13 | super(DrawChart, self).__init__() 14 | self.baseheight=745 15 | self.baseWidth=1465 16 | self.data=data 17 | self.idx_range=150 18 | self.idx_start=len(data) 19 | self.x_max=self.idx_start 20 | self.y_len=4 21 | if self.idx_start=pre_range: 103 | pre_range=self.idx_range 104 | if self.idx_start=120: 157 | d=20 158 | elif self.candle_item.max_i==self.idx_range-1 and self.idx_range>=120: 159 | d=35 160 | self.max_label.setText(str(self.candle_item.max_high)) 161 | a=self.baseWidth/self.idx_range 162 | if self.idx_range<120 and self.idx_start<120: 163 | a=12.25 164 | self.max_label.move(self.candle_item.max_i*a-d,5) 165 | self.min_label.setText(str(self.candle_item.min_low)) 166 | d=0 167 | if self.candle_item.min_i==self.idx_range-2 and self.idx_start>2: 168 | d=20 169 | elif self.candle_item.min_i==self.idx_range-1 and self.idx_start>1: 170 | d=35 171 | self.min_label.move(self.candle_item.min_i*a-d,self.baseheight-32) 172 | 173 | def deal_with_data(self,data): 174 | self.data=data 175 | self.data['MA5'] = self.data['close'].rolling(window=5).mean() 176 | self.data['MA10'] = self.data['close'].rolling(window=10).mean() 177 | self.data['MA20'] = self.data['close'].rolling(window=20).mean() 178 | self.data['MA60'] = self.data['close'].rolling(window=60).mean() 179 | 180 | self.data['VMA5'] = self.data['volume'].rolling(window=5).mean()/500 181 | self.data['VMA10'] = self.data['volume'].rolling(window=10).mean()/500 182 | 183 | def mouseMoved(self,ev): 184 | pos = ev[0] 185 | if pos.x()>=self.baseWidth-7 or pos.x()<=0 or pos.y()>=self.baseheight-1 or pos.y()<=0: 186 | self.ylabel.hide() 187 | self.xlabel.hide() 188 | return 189 | if self.candle_plot.sceneBoundingRect().contains(pos): 190 | mousePoint = self.candle_plot.plotItem.vb.mapSceneToView(pos)#转换坐标系 191 | 192 | self.index = int(mousePoint.x() + 0.5) # 鼠标所处的x轴坐标 193 | if self.index=0: 194 | self._signal.emit() 195 | if self.idx_start-self.idx_range-1 < self.index < self.idx_start: 196 | trade_date = datetime.datetime.strptime(self.data['date'][self.index],'%Y-%m-%d').strftime("%m/%d/%Y") 197 | 198 | # 显示x, y坐标跟随鼠标移动 199 | if not self.ylabel is None: 200 | self.ylabel.setText(str(round(mousePoint.y(), 2))) 201 | self.ylabel.move(0,pos.y()-self.ylabel.geometry().height()/2) 202 | if self.ylabel.isHidden(): 203 | self.ylabel.show() 204 | if not self.xlabel is None: 205 | self.xlabel.setText(trade_date) 206 | self.xlabel.move(pos.x() - self.xlabel.geometry().width()/2,self.xlabel.geometry().y()) 207 | if self.xlabel.isHidden(): 208 | self.xlabel.show() 209 | 210 | def leaveEvent(self, a0): 211 | if not self.ylabel is None: 212 | self.ylabel.hide() 213 | if not self.xlabel is None: 214 | self.xlabel.hide() 215 | 216 | class CandleItem(pg.GraphicsObject): 217 | def __init__(self,data,idx_range,idx_start): 218 | pg.GraphicsObject.__init__(self) 219 | self.generatePicture(data,idx_range,idx_start) 220 | 221 | def generatePicture(self,data,idx_range,idx_start): 222 | self.picture = QPicture() 223 | p = QPainter(self.picture) 224 | pg.setConfigOptions(leftButtonPan=False, antialias=True) 225 | w = 0.25 226 | self.max_high=0 227 | self.min_low=100000 228 | self.max_i=0 229 | self.min_i=0 230 | for i in range((idx_start-idx_range),idx_start): 231 | open, close, high, low = data['open'][i], data['close'][i], data['high'][i], data['low'][i] 232 | if self.max_highlow: 236 | self.min_low=low 237 | self.min_i=i-(idx_start-idx_range) 238 | if i-1>=0: 239 | if not pd.isna(data['MA5'][i-1]): 240 | p.setPen(pg.mkPen(QColor(255, 255, 255))) 241 | p.drawLine(QPointF(i-1, data['MA5'][i-1]), QPointF(i, data['MA5'][i])) 242 | if not pd.isna(data['MA10'][i-1]): 243 | p.setPen(pg.mkPen(QColor(255, 255, 0))) 244 | p.drawLine(QPointF(i-1, data['MA10'][i-1]), QPointF(i, data['MA10'][i])) 245 | if not pd.isna(data['MA20'][i-1]): 246 | p.setPen(pg.mkPen(QColor(0, 255, 0))) 247 | p.drawLine(QPointF(i-1, data['MA20'][i-1]), QPointF(i, data['MA20'][i])) 248 | if not pd.isna(data['MA60'][i-1]): 249 | p.setPen(pg.mkPen(QColor(205,0,0))) 250 | p.drawLine(QPointF(i-1, data['MA60'][i-1]), QPointF(i, data['MA60'][i])) 251 | if open > close: 252 | p.setPen(pg.mkPen(QColor(2,148,255))) 253 | p.setBrush(pg.mkBrush(QColor(2,148,255))) 254 | else: 255 | p.setPen(pg.mkPen('w')) 256 | p.setBrush(pg.mkBrush('w')) 257 | if high!=low: 258 | p.drawLine(QPointF(i, low), QPointF(i, high)) 259 | p.drawRect(QRectF(i - w, open, w * 2, close - open)) 260 | p.end() 261 | 262 | def paint(self, p, *args): 263 | p.drawPicture(0, 0, self.picture) 264 | 265 | def boundingRect(self): 266 | return QRectF(self.picture.boundingRect()) 267 | 268 | class VolItem(pg.GraphicsObject): 269 | def __init__(self, data,idx_range,idx_start): 270 | pg.GraphicsObject.__init__(self) 271 | self.generatePicture(data,idx_range,idx_start) 272 | 273 | def generatePicture(self,data,idx_range,idx_start): 274 | self.picture = QPicture() 275 | p = QPainter(self.picture) 276 | pg.setConfigOptions(leftButtonPan=False, antialias=False) 277 | w=0.25 278 | for i in range((idx_start-idx_range),idx_start): 279 | open, close, vol = data['open'][i], data['close'][i], data['volume'][i]/500 280 | if i-1>=0: 281 | if not pd.isna(data['VMA5'][i-1]): 282 | p.setPen(pg.mkPen(QColor(255, 255, 0))) 283 | p.drawLine(QPointF(i-1, data['VMA5'][i-1]), QPointF(i, data['VMA5'][i])) 284 | if not pd.isna(data['VMA10'][i-1]): 285 | p.setPen(pg.mkPen(QColor(0, 255, 0))) 286 | p.drawLine(QPointF(i-1, data['VMA10'][i-1]), QPointF(i, data['VMA10'][i])) 287 | if open > close: 288 | p.setPen(pg.mkPen(QColor(2,148,255))) 289 | p.setBrush(pg.mkBrush(QColor(2,148,255))) 290 | else: 291 | p.setPen(pg.mkPen('w')) 292 | p.setBrush(pg.mkBrush('w')) 293 | p.drawRect(QRectF(i - w, 0, w * 2, vol)) 294 | p.end() 295 | 296 | def paint(self, p, *args): 297 | p.drawPicture(0, 0, self.picture) 298 | 299 | def boundingRect(self): 300 | return QRectF(self.picture.boundingRect()) 301 | -------------------------------------------------------------------------------- /drawTimeShare.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | import pyqtgraph as pg 4 | from PySide6.QtWidgets import QWidget,QVBoxLayout 5 | from PySide6.QtGui import QColor,QPainter,QPicture 6 | from PySide6.QtCore import Signal,QPointF,QRectF 7 | 8 | class DrawChart(QWidget): 9 | _signal=Signal() 10 | def __init__(self,high_low_point, data): 11 | super(DrawChart, self).__init__() 12 | self.pre_len=len(data) 13 | self.deal_with_data(high_low_point,data) 14 | self.baseheight=300 15 | self.baseWidth=420 16 | self.time_share_widget=QWidget() 17 | self.time_share_widget.setMaximumHeight(self.baseheight) 18 | self.time_share_widget.setMinimumWidth(self.baseWidth) 19 | self.time_share_layout=QVBoxLayout() 20 | self.time_share_layout.setContentsMargins(0,2,0,0) 21 | self.time_share_layout.setSpacing(1) 22 | self.time_share_widget.setLayout(self.time_share_layout) 23 | self.time_share_plot = pg.PlotWidget() 24 | #self.time_share_plot.setMinimumHeight(200) 25 | 26 | xdict = {0:'09:30',60:'10:30',120:'13:00',180:'14:00',240:'15:00'} 27 | stringaxis = pg.AxisItem(orientation='bottom') 28 | stringaxis.setTicks([xdict.items()]) 29 | #self.time_share_plot.setGeometry(0,0,self.baseWidth,self.baseheight) 30 | self.volume_plot= pg.PlotWidget(axisItems={'bottom':stringaxis},enableMenu=False) 31 | self.volume_plot.setMaximumHeight(60) 32 | 33 | #self.volume_plot.setGeometry(0,self.baseheight,self.baseWidth,100) 34 | self.time_share_layout.addWidget(self.time_share_plot) 35 | self.time_share_layout.addWidget(self.volume_plot) 36 | 37 | #self.candle_plot = pg.PlotWidget(axisItems={'bottom': self.stringaxis},background=QColor(219,241,255),enableMenu=False) 38 | self.time_share_plot.showAxis('bottom', False) 39 | self.time_share_plot.showAxis('left', False) 40 | #self.volume_plot= pg.PlotWidget(axisItems={'bottom': self.stringaxis2},background=QColor(219,241,255),enableMenu=False) 41 | #self.volume_plot.showAxis('bottom', False) 42 | self.volume_plot.showAxis('left', False) 43 | 44 | self.time_share_plot.showGrid(x=False, y=True) 45 | self.volume_plot.showGrid(x=False, y=True) 46 | self.time_share_plot.setMouseEnabled(x=False, y=False) 47 | self.volume_plot.setMouseEnabled(x=False, y=False) 48 | #self.time_share_plot.setMouseMode(False) 49 | self.time_share_plot.hideButtons()#隐藏左下角按钮 50 | self.volume_plot.hideButtons() 51 | self.time_share_plot.setXRange(-1, 241, padding=0) 52 | 53 | self.time_share_plot.setYRange(self.low_point, self.high_point, padding=0) 54 | self.volume_plot.setXRange(-1, 241, padding=0) 55 | self.volume_plot.setYRange(0, self.high_vol, padding=0) 56 | 57 | self.time_share_item = TimeShareItem(data,self.low_point ,self.high_point,self.high_stop,self.low_stop) 58 | self.vol_item=VolItem(data,self.high_vol) 59 | self.time_share_plot.addItem(self.time_share_item) 60 | self.volume_plot.addItem(self.vol_item) 61 | 62 | def init(self,high_low_point,data): 63 | self.time_share_plot.removeItem(self.time_share_item) 64 | self.volume_plot.removeItem(self.vol_item) 65 | self.deal_with_data(high_low_point,data) 66 | l=len(data) 67 | 68 | d=60 69 | if l<240: 70 | l=240 71 | elif l>1000: 72 | d=180 73 | elif l>500: 74 | d=120 75 | # if self.pre_len!=len(data): 76 | # self.pre_len=len(data) 77 | # xdict={} 78 | x=[] 79 | strs=[] 80 | for i in range(0,len(data),d): 81 | x.append(i) 82 | strs.append(data['Time'][i][11:16]) 83 | # xdict[i]= data['Time'][i][11:16] 84 | # stringaxis = pg.AxisItem(orientation='bottom') 85 | # stringaxis.setTicks([xdict.items()]) 86 | #self.volume_plot.setAxisItems(axisItems={'bottom':stringaxis}) 87 | xAxis = self.volume_plot.getAxis('bottom') 88 | ticks = [(i, j) for i, j in zip(x,strs)] 89 | xAxis.setTicks([ticks]) 90 | 91 | self.time_share_plot.setXRange(0, l, padding=0) 92 | self.volume_plot.setXRange(0, l, padding=0) 93 | self.time_share_plot.setYRange(self.low_point, self.high_point, padding=0) 94 | self.volume_plot.setYRange(0, self.high_vol, padding=0) 95 | self.time_share_plot.removeItem(self.time_share_item) 96 | self.volume_plot.removeItem(self.vol_item) 97 | 98 | self.time_share_item = TimeShareItem(data,self.high_point,self.low_point,self.high_stop,self.low_stop) 99 | self.vol_item=VolItem(data,self.high_vol) 100 | self.time_share_plot.addItem(self.time_share_item) 101 | self.volume_plot.addItem(self.vol_item) 102 | 103 | def deal_with_data(self,high_low_point,data): 104 | 105 | self.high_vol=high_low_point[2] 106 | self.high_point=high_low_point[0]+0.5 107 | self.low_point=high_low_point[1]-0.5 108 | self.high_stop=high_low_point[3] 109 | self.low_stop=high_low_point[4] 110 | 111 | class TimeShareItem(pg.GraphicsObject): 112 | def __init__(self,data,low_point,high_ponit,high_stop,low_stop): 113 | pg.GraphicsObject.__init__(self) 114 | self.generatePicture(data,low_point,high_ponit,high_stop,low_stop) 115 | 116 | def generatePicture(self,data,high_point,low_point,high_stop,low_stop): 117 | self.picture = QPicture() 118 | p = QPainter(self.picture) 119 | pg.setConfigOptions(leftButtonPan=False, antialias=True) 120 | p.setPen(pg.mkPen('blue')) 121 | l=len(data) 122 | d=30 123 | if l<240: 124 | l=240 125 | elif l>1000: 126 | d=180 127 | elif l>600: 128 | d=120 129 | elif l>400: 130 | d=60 131 | p.drawLine(QPointF(0, 0), QPointF(l, 0)) 132 | 133 | p.setPen(pg.mkPen('gray')) 134 | for i in range(1,l//d): 135 | p.drawLine(QPointF(i*d,high_point), QPointF(i*d, low_point)) 136 | 137 | p.drawLine(QPointF(0, 2.5), QPointF(l, 2.5)) 138 | p.drawLine(QPointF(0, 7.5), QPointF(l, 7.5)) 139 | p.drawLine(QPointF(0, 15), QPointF(l, 15)) 140 | p.drawLine(QPointF(0, 20), QPointF(l, 20)) 141 | p.drawLine(QPointF(0, -2.5), QPointF(l, -2.5)) 142 | p.drawLine(QPointF(0, -7.5), QPointF(l, -7.5)) 143 | p.drawLine(QPointF(0, -15), QPointF(l, -15)) 144 | p.drawLine(QPointF(0, -20), QPointF(l, -20)) 145 | if high_point-0.5>=5: 146 | p.setPen(pg.mkPen('r')) 147 | p.drawLine(QPointF(0, 5), QPointF(l, 5)) 148 | if high_point-0.5>=high_stop: 149 | p.setPen(pg.mkPen(QColor(255, 0, 255))) 150 | p.drawLine(QPointF(0, high_stop), QPointF(l, high_stop)) 151 | if low_point+0.5<=-5: 152 | p.setPen(pg.mkPen(QColor(60,179,113))) 153 | p.drawLine(QPointF(0, -5), QPointF(l, -5)) 154 | if low_point+0.5<=low_stop: 155 | p.setPen(pg.mkPen(QColor(0, 255, 0))) 156 | p.drawLine(QPointF(0, low_stop), QPointF(l, low_stop)) 157 | 158 | for i in range(len(data)): 159 | if i-1>=0: 160 | price1 ,price2= data['price'][i-1],data['price'][i] 161 | ave_price1,ave_price2=data['ave_price'][i-1],data['ave_price'][i] 162 | p.setPen(pg.mkPen('yellow')) 163 | p.drawLine(QPointF((i-1), price1), QPointF(i, price2)) 164 | p.setPen(pg.mkPen('white')) 165 | p.drawLine(QPointF((i-1), ave_price1), QPointF(i, ave_price2)) 166 | p.end() 167 | 168 | def paint(self, p, *args): 169 | p.drawPicture(0, 0, self.picture) 170 | 171 | def boundingRect(self): 172 | return QRectF(self.picture.boundingRect()) 173 | 174 | class VolItem(pg.GraphicsObject): 175 | def __init__(self, data,high_vol): 176 | pg.GraphicsObject.__init__(self) 177 | self.generatePicture(data,high_vol) 178 | 179 | def generatePicture(self,data,high_vol): 180 | self.picture = QPicture() 181 | p = QPainter(self.picture) 182 | pg.setConfigOptions(leftButtonPan=False, antialias=False) 183 | p.setPen(pg.mkPen('gray')) 184 | l=len(data) 185 | d=30 186 | if l<240: 187 | l=240 188 | elif l>1000: 189 | d=180 190 | elif l>600: 191 | d=120 192 | elif l>400: 193 | d=60 194 | for i in range(1,l//d): 195 | if high_vol>=1000000000: 196 | break 197 | p.drawLine(QPointF(i*d,0), QPointF(i*d,high_vol)) 198 | 199 | for i in range(len(data)): 200 | vol,direct= data['vol'][i], data['direct'][i] 201 | if vol>=1000000000: 202 | break 203 | if direct==2: 204 | p.setPen(pg.mkPen('r')) 205 | elif direct==1: 206 | p.setPen(pg.mkPen(QColor(0, 255, 0))) 207 | else: 208 | p.setPen(pg.mkPen('w')) 209 | p.drawLine(QPointF(i, 0), QPointF(i, vol)) 210 | p.end() 211 | 212 | def paint(self, p, *args): 213 | p.drawPicture(0, 0, self.picture) 214 | 215 | def boundingRect(self): 216 | return QRectF(self.picture.boundingRect()) 217 | -------------------------------------------------------------------------------- /figureCanvas.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | #matplotlib.use('QtAgg') #指定渲染后端。QtAgg后端指用Agg二维图形库在Qt控件上绘图。 6 | from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas 7 | #使用matplotlib中的FigureCanvas(继承自QtWidgets.QWidget)绘制图形可以嵌入QT GUI 8 | import mplfinance as mpf 9 | import pandas as pd 10 | import time 11 | 12 | title_font = {'fontname': 'SimHei', 13 | 'size': '16', 14 | 'color': 'black', 15 | 'weight': 'bold', 16 | 'va': 'bottom', 17 | 'ha': 'center'} 18 | large_red_font = {'fontname': 'Arial', 19 | 'size': '24', 20 | 'color': 'red', 21 | 'weight': 'bold', 22 | 'va': 'bottom'} 23 | # 绿色数字格式(显示开盘收盘价)粗体绿色24号字 24 | large_green_font = {'fontname': 'Arial', 25 | 'size': '24', 26 | 'color': 'green', 27 | 'weight': 'bold', 28 | 'va': 'bottom'} 29 | # 小数字格式(显示其他价格信息)粗体红色12号字 30 | small_red_font = {'fontname': 'Arial', 31 | 'size': '12', 32 | 'color': 'red', 33 | 'weight': 'bold', 34 | 'va': 'bottom'} 35 | # 小数字格式(显示其他价格信息)粗体绿色12号字 36 | small_green_font = {'fontname': 'Arial', 37 | 'size': '12', 38 | 'color': 'green', 39 | 'weight': 'bold', 40 | 'va': 'bottom'} 41 | # 标签格式,可以显示中文,普通黑色12号字 42 | normal_label_font = {'fontname': 'SimHei', 43 | 'size': '12', 44 | 'color': 'black', 45 | 'va': 'bottom', 46 | 'ha': 'right'} 47 | # 普通文本格式,普通黑色12号字 48 | normal_font = {'fontname': 'Arial', 49 | 'size': '12', 50 | 'color': 'black', 51 | 'va': 'bottom', 52 | 'ha': 'left'} 53 | 54 | class Figure_Canvas(FigureCanvas): 55 | def __init__(self,code,freq,data,name,industry,parent=None,width=17,height=9.7,dpi=100): 56 | my_color=mpf.make_marketcolors(up='r', 57 | down='g', 58 | edge='inherit', 59 | wick='inherit', 60 | volume='inherit' 61 | ) 62 | my_style=mpf.make_mpf_style(base_mpf_style='blueskies', 63 | #marketcolors=my_color, 64 | figcolor='(0.82, 0.83, 0.85)', 65 | gridcolor='(0.82, 0.83, 0.85)') 66 | self.style=my_style 67 | self.fig=mpf.figure(style=my_style,figsize=(width,height),facecolor=(0.82, 0.83, 0.85)) 68 | fig=self.fig 69 | 70 | #显示鼠标位置信息 71 | 72 | # 添加三个图表,四个数字分别代表图表左下角在figure中的坐标,以及图表的宽(0.88)、高(0.60) 73 | self.ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60]) 74 | #添加第二、三张图表时,使用sharex关键字指明与ax1在x轴上对齐,且共用x轴 75 | self.ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=self.ax1) 76 | self.ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=self.ax1) 77 | # 设置三张图表的Y轴标签 78 | #self.ax1.set_ylabel('Price') 79 | #self.ax2.set_ylabel('Volume') 80 | 81 | FigureCanvas.__init__(self,fig) 82 | self.setParent(parent) 83 | self.Title=self.fig.text(0.50, 0.94, code,title_font) 84 | 85 | self.init(code,freq,data,name,industry) 86 | self.detailed_data() 87 | fig.text(0.12, 0.90, '开/收: ', normal_label_font) 88 | fig.text(0.40, 0.90, '涨幅: ', normal_label_font) 89 | fig.text(0.40, 0.86, '换手: ', normal_label_font) 90 | fig.text(0.55, 0.90, '高: ', normal_label_font) 91 | fig.text(0.55, 0.86, '低:', normal_label_font) 92 | fig.text(0.70, 0.90, '量(万股): ', normal_label_font) 93 | fig.text(0.70, 0.86, '额(千万元): ', normal_label_font) 94 | fig.text(0.85, 0.90, 'PE(滚): ', normal_label_font) 95 | fig.text(0.85, 0.86, '前收: ', normal_label_font) 96 | self.Title.set_text(self.stock_code+' '+self.name+'('+self.interval+')'+self.industry) 97 | 98 | #fig.canvas.mpl_connect('button_press_event',self.on_press) 99 | #fig.canvas.mpl_connect('button_release_event',self.on_release) 100 | fig.canvas.mpl_connect('motion_notify_event',self.on_motion) 101 | #fig.canvas.mpl_connect('scroll_event',self.on_scroll) 102 | fig.canvas.mpl_connect('key_press_event', self.on_key_press) 103 | 104 | def init(self,code,freq,data,name,industry): 105 | self.freq=freq 106 | self.stock_code=code 107 | 108 | self.data=data 109 | self.deal_with_data_candle() 110 | self.name=name 111 | self.industry=industry 112 | self.idx_start=len(self.data_candle) 113 | self.curInformation=len(self.data_candle)-1 114 | self.idx_range=120 115 | if self.idx_start=0: 158 | self.tGain=self.fig.text(0.40,0.90,'%s%%'%(a[8]),small_red_font) 159 | else: 160 | self.tGain=self.fig.text(0.40,0.90,'%s%%'%(a[8]),small_green_font) 161 | self.tHigh=self.fig.text(0.55,0.90,a[3],small_red_font) 162 | self.tLow=self.fig.text(0.55,0.86,a[4],small_green_font) 163 | self.tVolume=self.fig.text(0.70,0.90,a[5]/10000,normal_font) 164 | self.tPreclose=self.fig.text(0.85,0.86,(a[2]/(1+a[8]/100)).round(2),normal_font) 165 | self.tAmount=self.fig.text(0.70,0.86,(a[6]/10000000).round(4),normal_font) 166 | 167 | self.tTurn=self.fig.text(0.40,0.86,'%s%%'%(a[10]),normal_font) 168 | 169 | def refrash_detailed_data(self,curInformation): 170 | a=self.data.loc[curInformation] 171 | a=a.apply(pd.to_numeric,errors='ignore') 172 | 173 | if self.freq in ['5','15','30','60']: 174 | a['date'] = pd.to_datetime(a['date']) 175 | self.Title.set_text(self.stock_code+' '+self.name+'('+self.interval+')'+self.industry) 176 | self.tOpen.set_text(f'{a[1]}/{a[2]}') 177 | if a[1]<=a[2]: 178 | self.tOpen.set_color('r') 179 | else: 180 | self.tOpen.set_color('g') 181 | self.tGain.set_text('%s%%'%(a[8])) 182 | if a[8]>=0: 183 | self.tGain.set_color('r') 184 | else: 185 | self.tGain.set_color('g') 186 | 187 | self.tTime.set_text(a[0]) 188 | self.tHigh.set_text(a[3].round(2)) 189 | self.tLow.set_text(a[4].round(2)) 190 | self.tVolume.set_text(a[5]/10000) 191 | self.tAmount.set_text((a[6]/10000000).round(4)) 192 | self.tPreclose.set_text((a[2]/(1+a[8]/100)).round(2)) 193 | self.tTurn.set_text('%s%%'%(a[10])) 194 | 195 | def on_key_press(self,event): 196 | scale_factor=1.0 197 | if event.key == 'up': 198 | scale_factor=0.8 199 | if event.key=='down': 200 | scale_factor=1.2 201 | if event.key=='left': 202 | new_start=self.idx_start-self.idx_range//4 203 | if new_start <= self.idx_range: 204 | new_start = self.idx_range 205 | self.idx_start=new_start 206 | if event.key=='right': 207 | new_start=self.idx_start+self.idx_range//4 208 | if new_start >= len(self.data_candle): 209 | new_start = len(self.data_candle) 210 | self.idx_start=new_start 211 | self.idx_range=int(self.idx_range*scale_factor) 212 | if self.idx_range>=self.idx_start: 213 | self.idx_range=self.idx_start 214 | if self.idx_range<=100: 215 | self.idx_range=100 216 | self.ax1.clear() 217 | self.ax2.clear() 218 | self.ax3.clear() 219 | self.refrash_plot() 220 | self.fig.canvas.draw() 221 | 222 | def on_scroll(self,event): 223 | if event.inaxes!=self.ax1: 224 | return 225 | 226 | def on_press(self,event): 227 | if not event.inaxes==self.ax1: 228 | return 229 | if event.button!=1: 230 | return 231 | self.pressed=True 232 | self.xpress=event.xdata 233 | 234 | def on_release(self,event): 235 | self.pressed=False 236 | #dx=int(event.xdata-self.xpress) 237 | #self.idx_start-=dx 238 | if self.idx_start <= self.idx_range: 239 | self.idx_start = self.idx_range 240 | if self.idx_start >= len(self.data_candle): 241 | self.idx_start = len(self.data_candle) 242 | 243 | def on_motion(self,event): 244 | if event.inaxes!=self.ax1: 245 | #if(event.inaxes!=self.ax2): 246 | #if(event.inaxes!=self.ax3): 247 | return 248 | if not self.pressed: 249 | x=event.xdata 250 | time.sleep(0.2) 251 | if event.xdata==x: 252 | self.curInformation=self.idx_start-(self.idx_range-int(event.xdata+0.5)) 253 | self.refrash_detailed_data(self.curInformation) 254 | self.fig.canvas.draw_idle() 255 | return 256 | 257 | def refrash_plot(self): 258 | all_data=self.data_candle 259 | all_data['MA5'] = all_data['close'].rolling(window=5).mean() 260 | all_data['MA10'] = all_data['close'].rolling(window=10).mean() 261 | all_data['MA20'] = all_data['close'].rolling(window=20).mean() 262 | all_data['MA60'] = all_data['close'].rolling(window=60).mean() 263 | 264 | plot_data=all_data.iloc[self.idx_start-self.idx_range:self.idx_start] 265 | #计算移动平均线 266 | #talib计算macd 267 | #import talib 268 | #plot_data['MACD'],plot_data['MACDsignal'],plot_data['MACDhist'] = talib.MACD(plot_data.Close, fastperiod=12, slowperiod=26, signalperiod=9) 269 | #计算macd的方式 270 | exp12 = plot_data['close'].ewm(span=12, adjust=False).mean() 271 | exp26 = plot_data['close'].ewm(span=26, adjust=False).mean() 272 | macd = exp12 - exp26 273 | signal = macd.ewm(span=9, adjust=False).mean() 274 | histogram = macd - signal 275 | histogram[histogram < 0] = None 276 | histogram_positive = histogram 277 | histogram = macd - signal 278 | histogram[histogram >= 0] = None 279 | histogram_negative = histogram 280 | 281 | # 添加子图 282 | add_plot = [ 283 | mpf.make_addplot(plot_data[['MA5','MA10','MA20','MA60']], ax=self.ax1), 284 | 285 | mpf.make_addplot(histogram_positive, type='bar', color='red',ax=self.ax3), 286 | mpf.make_addplot(histogram_negative, type='bar', color='green',ax=self.ax3), 287 | mpf.make_addplot(macd, ax=self.ax3), 288 | mpf.make_addplot(signal, ax=self.ax3) 289 | ] 290 | self.ax3.set_ylabel('Macd') 291 | mpf.plot(plot_data, 292 | ax=self.ax1, 293 | type='candle', 294 | addplot=add_plot, 295 | ylabel='Price', ylabel_lower='Volume', 296 | volume=self.ax2, 297 | style=self.style, 298 | datetime_format='%Y-%m-%d', 299 | tight_layout=True, 300 | #mav=(5,10,20,60) 301 | ) 302 | -------------------------------------------------------------------------------- /form.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | true 7 | 8 | 9 | 10 | 0 11 | 0 12 | 1920 13 | 1080 14 | 15 | 16 | 17 | 18 | 0 19 | 0 20 | 21 | 22 | 23 | 24 | false 25 | 26 | 27 | 28 | MainWindow 29 | 30 | 31 | 32 | logo.icologo.ico 33 | 34 | 35 | 36 | 37 | 38 | -1 39 | 0 40 | 1920 41 | 1030 42 | 43 | 44 | 45 | 46 | Arial 47 | false 48 | 49 | 50 | 51 | QFrame::StyledPanel 52 | 53 | 54 | QFrame::Raised 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0 62 | 0 63 | 1920 64 | 25 65 | 66 | 67 | 68 | 69 | 开始 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 其它市场 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 分析 88 | 89 | 90 | 91 | 92 | 93 | 94 | 帮助 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | Arial 108 | false 109 | 110 | 111 | 112 | 113 | 114 | false 115 | 116 | 117 | 下载k线数据 118 | 119 | 120 | 121 | 122 | 退出 123 | 124 | 125 | 126 | 127 | 下载股票信息 128 | 129 | 130 | 131 | 132 | true 133 | 134 | 135 | false 136 | 137 | 138 | true 139 | 140 | 141 | 美股 142 | 143 | 144 | 145 | 146 | false 147 | 148 | 149 | 资金流 150 | 151 | 152 | 153 | 154 | true 155 | 156 | 157 | true 158 | 159 | 160 | A股 161 | 162 | 163 | 164 | 165 | true 166 | 167 | 168 | 港股 169 | 170 | 171 | 172 | 173 | F10---财务分析 经营分析 174 | 175 | 176 | 177 | 178 | F3---热度关键词 179 | 180 | 181 | 182 | 183 | true 184 | 185 | 186 | false 187 | 188 | 189 | 关闭语音播报 190 | 191 | 192 | 193 | 194 | 公式选股 195 | 196 | 197 | 198 | 199 | true 200 | 201 | 202 | 美中概股 203 | 204 | 205 | 206 | 207 | 208 | 209 | exit 210 | triggered() 211 | MainWindow 212 | close() 213 | 214 | 215 | -1 216 | -1 217 | 218 | 219 | 948 220 | 547 221 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /getDate.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | 6 | import pandas as pd 7 | import datetime 8 | import requests 9 | from pandas.core.frame import DataFrame 10 | 11 | class GetData(): 12 | def __init__(self,code,freq,adjustflag): 13 | 14 | self.data=pd.DataFrame(columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn']) 15 | self.issave=True 16 | self.data_time_share='' 17 | self.headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 18 | self.end_date=(datetime.date.today()+datetime.timedelta(days=1)).strftime("%Y%m%d") 19 | self.login_init(code,freq,adjustflag) 20 | 21 | def login_init(self,code,freq,adjustflag): 22 | #print(code,freq) 23 | # area='' 24 | # if str(code)[0] in ['6','s']: 25 | # area = 'sh' 26 | # elif str(code)[0] in ['4','8']: 27 | # area = 'bj' 28 | # elif str(code)[0] in ['0','3']: 29 | # area = 'sz' 30 | # data1=pd.DataFrame(columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn']) 31 | # self.start_date=(datetime.date.today()+datetime.timedelta(days=-365)).strftime("%Y%m%d") 32 | # if freq=='weekly': 33 | # self.start_date=(datetime.date.today()+datetime.timedelta(days=-1260)).strftime("%Y%m%d") 34 | # elif freq=='monthly': 35 | # self.start_date=(datetime.date.today()+datetime.timedelta(days=-5400)).strftime("%Y%m%d") 36 | 37 | if code[0]=='3' or code[0]=='0' or code[0]=='8' or code[0]=='4': 38 | num=0 39 | else: 40 | num=1 41 | if (code[0]=='s' and code[2]=='.' and code[3].isdigit()) or code[0:3]=='399': 42 | if code[0]=='s' and code[2]=='.' and code[3].isdigit(): 43 | code=code[3:9] 44 | # if os.path.exists('data/index/%s/%s/%s_%s.csv' 45 | # %(area,freq,code, freq)): 46 | # data1=pd.read_csv('data/index/%s/%s/%s_%s.csv' 47 | # %(area,freq,code, freq),encoding="gbk") 48 | # data1.drop(data1.columns[[0]],axis=1,inplace=True) 49 | # self.start_date='20221001' 50 | # self.data=ak.index_zh_a_hist(symbol=code, 51 | # start_date=self.start_date, 52 | # end_date=self.end_date, 53 | # period=freq) 54 | # if len(self.data)!=0: 55 | # self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 56 | # self.data=pd.concat([data1,self.data],ignore_index=True) 57 | 58 | adjust='0' 59 | self.get_zh_data_from_east(num,code,freq,adjust) 60 | self.deal_with_data(self.data) 61 | else: 62 | if code[0]=='S' and code[2].isdigit(): 63 | code=code[2:8] 64 | # if os.path.exists('data/%s/%s/%s_%s.csv' 65 | # %(area,freq,code, freq)) and adjustflag=='' and freq=='daily': 66 | # data1=pd.read_csv('data/%s/%s/%s_%s.csv' 67 | # %(area,freq,code, freq),encoding="gbk") 68 | # data1.drop(data1.columns[[0]],axis=1,inplace=True) 69 | # self.start_date='20221001' 70 | if code[0]=='3' or code[0]=='0' or code[0]=='8' or code[0]=='4': 71 | num=0 72 | else: 73 | num=1 74 | 75 | self.get_zh_data_from_east(num,code,freq,adjustflag) 76 | self.deal_with_data(self.data) 77 | 78 | def get_zh_data_from_east(self,num,code,freq,adjustflag): 79 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-1080)).strftime("%Y%m%d") 80 | if freq=='102': 81 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-5400)).strftime("%Y%m%d") 82 | elif freq=='103': 83 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-20000)).strftime("%Y%m%d") 84 | url='http://push2his.eastmoney.com/api/qt/stock/kline/get?fields1=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13&fields2=f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61&beg={}&end=20500101&ut=fa5fd1943c7b386f172d6893dbfba10b&rtntype=6&secid={}.{}&klt={}&fqt={}'.format(self.start_date,num,code,freq,adjustflag) 85 | data_list=requests.get(url,headers=self.headers).json()['data']['klines'] 86 | df=pd.DataFrame(data_list) 87 | self.data=df[0].str.split(',',expand = True) 88 | self.data.iloc[:,1:]=self.data.iloc[:,1:].astype(float) 89 | self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 90 | self.deal_with_data(self.data) 91 | 92 | def get_us_data_from_east(self,code,freq,adjustflag): 93 | day=1080 94 | url='http://push2his.eastmoney.com/api/qt/stock/kline/get?secid={}&ut=fa5fd1943c7b386f172d6893dbfba10b&fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5%2Cf6&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61&klt={}&fqt={}&end=20500101&lmt={}&_=1667035995818'.format(code,freq,adjustflag,day) 95 | data_list=requests.get(url,headers=self.headers).json()['data']['klines'] 96 | df=pd.DataFrame(data_list) 97 | self.data=df[0].str.split(',',expand = True) 98 | self.data.iloc[:,1:]=self.data.iloc[:,1:].astype(float) 99 | self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 100 | self.deal_with_data(self.data) 101 | 102 | def get_hk_data_from_east(self,code,freq,adjustflag): 103 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-1080)).strftime("%Y%m%d") 104 | if freq=='102': 105 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-5400)).strftime("%Y%m%d") 106 | elif freq=='103': 107 | self.start_date=(datetime.date.today()+datetime.timedelta(days=-20000)).strftime("%Y%m%d") 108 | url='http://push2his.eastmoney.com/api/qt/stock/kline/get?secid=116.{}&ut=fa5fd1943c7b386f172d6893dbfba10b&fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5%2Cf6&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61&klt={}&fqt={}&beg={}&end=20500101&smplmt=860.818&lmt=1000000&_=1667037417533'.format(code,freq,adjustflag,self.start_date) 109 | data_list=requests.get(url,headers=self.headers).json()['data']['klines'] 110 | df=pd.DataFrame(data_list) 111 | self.data=df[0].str.split(',',expand = True) 112 | self.data.iloc[:,1:]=self.data.iloc[:,1:].astype(float) 113 | self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 114 | self.deal_with_data(self.data) 115 | 116 | def deal_with_data(self,data): 117 | data['MA5'] = data['close'].rolling(window=5).mean() 118 | data['MA10'] = data['close'].rolling(window=10).mean() 119 | data['MA20'] = data['close'].rolling(window=20).mean() 120 | data['MA60'] = data['close'].rolling(window=60).mean() 121 | 122 | data['VMA5'] = data['volume'].rolling(window=5).mean()/500 123 | data['VMA10'] = data['volume'].rolling(window=10).mean()/500 124 | 125 | def get_other_index(self,code,freq): 126 | days=1365 127 | url='http://push2his.eastmoney.com/api/qt/stock/kline/get?secid={}&fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58%2Cf59%2Cf60%2Cf61&lmt={}&klt={}&fqt=1&end=30000101&ut=4f1862fc3b5e77c150a2b985b12db0fd&cb_1665195942532_53072773=cb_1665195942532_53072773'.format(code,days,freq) 128 | json_data=requests.get(url,headers=self.headers).json()['data']['klines'] 129 | for i in range(len(json_data)): 130 | json_data[i]=json_data[i].split(',',11) 131 | self.data=pd.DataFrame(json_data) 132 | self.data.columns=['date','open','close','high','low','volume','amount','turn','pctChg','pctVal','amplitude'] 133 | self.data.iloc[:,1:]=self.data.iloc[:,1:].astype(float) 134 | self.deal_with_data(self.data) 135 | 136 | def get_main_indicator_data(self,code): 137 | if code[0] == '6': 138 | stock_code = 'SH'+code 139 | elif code[0] in ['4','8']: 140 | stock_code = 'BJ'+code 141 | elif code[0] in ['0','3']: 142 | stock_code = 'SZ'+code 143 | url='https://emweb.securities.eastmoney.com/PC_HSF10/NewFinanceAnalysis/ZYZBAjaxNew?type=0&code={}'.format(stock_code) 144 | df=requests.get(url,headers=self.headers) 145 | data=DataFrame(df.json()['data']) 146 | data=data.T 147 | return data 148 | 149 | # def download_akshare_all_stock(self): 150 | # if globalVariable.getIsNet()==1 or self.issave==False: 151 | # print('网络未连接') 152 | # return 153 | # if globalVariable.isZhMarketDay(): 154 | # print('请休市后下载') 155 | # return 156 | # if not os.path.exists('data/index/sh/daily'): 157 | # os.makedirs('data/index/sh/daily') 158 | # if not os.path.exists('data/index/sz/daily'): 159 | # os.makedirs('data/index/sz/daily') 160 | 161 | # if not os.path.exists('data/sh/daily'): 162 | # os.makedirs('data/sh/daily') 163 | # if not os.path.exists('data/sz/daily'): 164 | # os.makedirs('data/sz/daily') 165 | # if not os.path.exists('data/bj/daily'): 166 | # os.makedirs('data/bj/daily') 167 | 168 | # stock=pd.read_csv('list/index_list.csv',encoding="gbk",dtype={'index_code':str}) 169 | # stock.drop(stock.columns[[0]],axis=1,inplace=True) 170 | # for row in range(0,len(stock)): 171 | # for freq in ['daily']: 172 | # code=stock.loc[row,'index_code'] 173 | # if(str(code)[0] == '3'): 174 | # area = 'sz' 175 | # else: 176 | # area = 'sh' 177 | # if os.path.exists('data/index/%s/%s/%s_%s.csv' 178 | # %(area,freq,code, freq)): 179 | # continue 180 | # else: 181 | # self.start_date='19901219' 182 | # self.end_date='20220930' 183 | 184 | # print('{:.2%}'.format(row/len(stock))) 185 | # print(code+' '+freq) 186 | # self.data=ak.index_zh_a_hist(symbol=code, 187 | # start_date=self.start_date, 188 | # end_date=self.end_date, 189 | # period=freq) 190 | # self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 191 | # self.data.to_csv('data/index/%s/%s/%s_%s.csv' 192 | # %(area,freq,code, freq),encoding="gbk") 193 | # print('指数下载完毕') 194 | 195 | # stock=pd.read_csv('list/stock_list.csv',encoding="gbk",dtype={'symbol':str}) 196 | # for row in range(0,len(stock)): 197 | # for freq in ['daily']: 198 | # code=stock.loc[row,'symbol'] 199 | # if code=='430685': 200 | # continue 201 | # if(str(code)[0] == '6'): 202 | # area = 'sh' 203 | # elif(str(code)[0] in ['4','8']): 204 | # area = 'bj' 205 | # elif(str(code)[0] in ['0','3']): 206 | # area = 'sz' 207 | # if os.path.exists('data/%s/%s/%s_%s.csv' 208 | # %(area,freq,code, freq)): 209 | # continue 210 | # else: 211 | # self.start_date='19901219' 212 | # self.end_date='20220930' 213 | # #print(code,self.start_date,self.end_date) 214 | 215 | # print('{:.2%}'.format(row/len(stock))) 216 | # self.data=ak.stock_zh_a_hist(symbol=code, 217 | # start_date=self.start_date, 218 | # end_date=self.end_date, 219 | # period='daily', 220 | # adjust='0') 221 | # self.data.columns=['date','open','close','high','low','volume','amount','amplitude','pctChg','pctVal','turn'] 222 | # self.data.to_csv('data/%s/%s/%s_%s.csv' 223 | # %(area,freq,code, freq),encoding="gbk") 224 | # print(code+' '+freq) 225 | # print('个股下载完毕') 226 | -------------------------------------------------------------------------------- /getEastData.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | import requests 6 | import pandas as pd 7 | import py_mini_racer 8 | from importlib import resources 9 | from bs4 import BeautifulSoup 10 | from tqdm import tqdm 11 | 12 | headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 13 | def getStockHot(): 14 | url = "https://emappdata.eastmoney.com/stockrank/getAllCurrentList" 15 | payload = { 16 | "appId": "appId01", 17 | "globalId": "786e4c21-70dc-435a-93bb-38", 18 | "marketType": "", 19 | "pageNo": 1, 20 | "pageSize": 100, 21 | } 22 | r = requests.post(url, json=payload,headers=headers) 23 | data_json = r.json() 24 | temp_rank_df = pd.DataFrame(data_json["data"]) 25 | 26 | temp_rank_df["mark"] = [ 27 | "0" + "." + item[2:] if "SZ" in item else "1" + "." + item[2:] 28 | for item in temp_rank_df["sc"] 29 | ] 30 | ",".join(temp_rank_df["mark"]) + "?v=08926209912590994" 31 | params = { 32 | "ut": "f057cbcbce2a86e2866ab8877db1d059", 33 | "fltt": "2", 34 | "invt": "2", 35 | "fields": "f14,f3,f12,f2", 36 | "secids": ",".join(temp_rank_df["mark"]) + ",?v=08926209912590994", 37 | } 38 | url = "https://push2.eastmoney.com/api/qt/ulist.np/get" 39 | r = requests.get(url, params=params) 40 | data_json = r.json() 41 | temp_df = pd.DataFrame(data_json["data"]["diff"]) 42 | temp_df.columns = ["最新价", "涨跌幅", "代码", "股票名称"] 43 | temp_df["当前排名"] = temp_rank_df["rk"] 44 | temp_df["代码"] = temp_rank_df["sc"] 45 | temp_df = temp_df[ 46 | [ 47 | "当前排名", 48 | "代码", 49 | "股票名称", 50 | "最新价", 51 | "涨跌幅", 52 | ] 53 | ] 54 | temp_df['最新价'] = pd.to_numeric(temp_df['最新价'], errors="coerce") 55 | temp_df['涨跌幅'] = pd.to_numeric(temp_df['涨跌幅'], errors="coerce") 56 | return temp_df 57 | 58 | def stock_hot_tgb(): 59 | """ 60 | 淘股吧-热门股票 61 | https://www.taoguba.com.cn/stock/moreHotStock 62 | """ 63 | url = "https://www.taoguba.com.cn/stock/moreHotStock" 64 | r = requests.get(url) 65 | temp_df = pd.concat([pd.read_html(r.text, header=0)[0], pd.read_html(r.text, header=0)[1]]) 66 | temp_df = temp_df[[ 67 | "个股代码", 68 | "个股名称", 69 | ]] 70 | temp_df.reset_index(inplace=True, drop=True) 71 | return temp_df 72 | 73 | def get_stock_pool_strong(date): 74 | """ 75 | 东方财富网-行情中心-涨停板行情-强势股池 76 | http://quote.eastmoney.com/ztb/detail#type=qsgc 77 | """ 78 | url = "http://push2ex.eastmoney.com/getTopicQSPool" 79 | params = { 80 | "ut": "7eea3edcaed734bea9cbfc24409ed989", 81 | "dpt": "wz.ztzt", 82 | "Pageindex": "0", 83 | "pagesize": "170", 84 | "sort": "zdp:desc", 85 | "date": date, 86 | "_": "1621590489736", 87 | } 88 | r = requests.get(url, params=params) 89 | data_json = r.json() 90 | if data_json["data"] is None: 91 | return pd.DataFrame() 92 | temp_df = pd.DataFrame(data_json["data"]["pool"]) 93 | temp_df.reset_index(inplace=True) 94 | temp_df["index"] = range(1, len(temp_df) + 1) 95 | temp_df.columns = [ 96 | "序号", 97 | "代码", 98 | "_", 99 | "名称", 100 | "最新价", 101 | "涨停价", 102 | "_", 103 | "涨跌幅", 104 | "成交额", 105 | "流通市值", 106 | "总市值", 107 | "换手率", 108 | "是否新高", 109 | "入选理由", 110 | "量比", 111 | "涨速", 112 | "涨停统计", 113 | "所属行业", 114 | ] 115 | temp_df["涨停统计"] = ( 116 | temp_df["涨停统计"].apply(lambda x: dict(x)["days"]).astype(str) 117 | + "/" 118 | + temp_df["涨停统计"].apply(lambda x: dict(x)["ct"]).astype(str) 119 | ) 120 | temp_df = temp_df[ 121 | [ 122 | "序号", 123 | "代码", 124 | "名称", 125 | "涨跌幅", 126 | "最新价", 127 | "涨停价", 128 | "成交额", 129 | "流通市值", 130 | "总市值", 131 | "换手率", 132 | "涨速", 133 | "是否新高", 134 | "量比", 135 | "涨停统计", 136 | "入选理由", 137 | "所属行业", 138 | ] 139 | ] 140 | temp_df["最新价"] = temp_df["最新价"] / 1000 141 | temp_df["涨停价"] = temp_df["涨停价"] / 1000 142 | return temp_df 143 | 144 | def get_stock_hot_keyword(symbol): 145 | """ 146 | 东方财富-个股人气榜-关键词 147 | http://guba.eastmoney.com/rank/stock?code=000665 148 | """ 149 | url = "https://emappdata.eastmoney.com/stockrank/getHotStockRankList" 150 | payload = { 151 | "appId": "appId01", 152 | "globalId": "786e4c21-70dc-435a-93bb-38", 153 | "srcSecurityCode": symbol, 154 | } 155 | r = requests.post(url, json=payload) 156 | data_json = r.json() 157 | temp_df = pd.DataFrame(data_json['data']) 158 | del temp_df['flag'] 159 | temp_df.columns = ['时间', '股票代码', '概念名称', '概念代码', '热度'] 160 | return temp_df 161 | 162 | def get_ths_js(file: str = "ths.js"): 163 | """Get path to data "ths.js" text file. 164 | 165 | Returns 166 | ------- 167 | pathlib.PosixPath 168 | Path to file. 169 | 170 | References 171 | ---------- 172 | .. [1] E.A.Abbott, ”Flatland”, Seeley & Co., 1884. 173 | """ 174 | with resources.path("akshare.data", file) as f: 175 | data_file_path = f 176 | return data_file_path 177 | 178 | def _get_file_content_ths(file: str = "ths.js") -> str: 179 | """ 180 | 获取 JS 文件的内容 181 | :param file: JS 文件名 182 | :type file: str 183 | :return: 文件内容 184 | :rtype: str 185 | """ 186 | setting_file_path = get_ths_js(file) 187 | with open(setting_file_path) as f: 188 | file_data = f.read() 189 | return file_data 190 | 191 | def stock_fund_flow_concept(symbol): 192 | """ 193 | 同花顺-数据中心-资金流向-概念资金流 194 | http://data.10jqka.com.cn/funds/gnzjl/#refCountId=data_55f13c2c_254 195 | """ 196 | js_code = py_mini_racer.MiniRacer() 197 | js_content = _get_file_content_ths("ths.js") 198 | js_code.eval(js_content) 199 | v_code = js_code.call("v") 200 | headers = { 201 | "Accept": "text/html, */*; q=0.01", 202 | "Accept-Encoding": "gzip, deflate", 203 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 204 | "Cache-Control": "no-cache", 205 | "Connection": "keep-alive", 206 | "hexin-v": v_code, 207 | "Host": "data.10jqka.com.cn", 208 | "Pragma": "no-cache", 209 | "Referer": "http://data.10jqka.com.cn/funds/gnzjl/", 210 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36", 211 | "X-Requested-With": "XMLHttpRequest", 212 | } 213 | url = ( 214 | "http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/ajax/1/free/1/" 215 | ) 216 | r = requests.get(url, headers=headers) 217 | soup = BeautifulSoup(r.text, "lxml") 218 | raw_page = soup.find("span", attrs={"class": "page_info"}).text 219 | page_num = raw_page.split("/")[1] 220 | if symbol == "3日排行": 221 | url = "http://data.10jqka.com.cn/funds/gnzjl/board/3/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 222 | elif symbol == "5日排行": 223 | url = "http://data.10jqka.com.cn/funds/gnzjl/board/5/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 224 | elif symbol == "10日排行": 225 | url = "http://data.10jqka.com.cn/funds/gnzjl/board/10/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 226 | elif symbol == "20日排行": 227 | url = "http://data.10jqka.com.cn/funds/gnzjl/board/20/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 228 | else: 229 | url = "http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 230 | big_df = pd.DataFrame() 231 | for page in tqdm(range(1, int(page_num) + 1)): 232 | js_code = py_mini_racer.MiniRacer() 233 | js_content = _get_file_content_ths("ths.js") 234 | js_code.eval(js_content) 235 | v_code = js_code.call("v") 236 | headers = { 237 | "Accept": "text/html, */*; q=0.01", 238 | "Accept-Encoding": "gzip, deflate", 239 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 240 | "Cache-Control": "no-cache", 241 | "Connection": "keep-alive", 242 | "hexin-v": v_code, 243 | "Host": "data.10jqka.com.cn", 244 | "Pragma": "no-cache", 245 | "Referer": "http://data.10jqka.com.cn/funds/gnzjl/", 246 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36", 247 | "X-Requested-With": "XMLHttpRequest", 248 | } 249 | r = requests.get(url.format(page), headers=headers) 250 | temp_df = pd.read_html(r.text)[0] 251 | big_df = pd.concat([big_df, temp_df], ignore_index=True) 252 | 253 | del big_df["序号"] 254 | big_df.reset_index(inplace=True) 255 | big_df["index"] = range(1, len(big_df) + 1) 256 | if symbol == "即时": 257 | big_df.columns = [ 258 | "序号", 259 | "行业", 260 | "行业指数", 261 | "行业-涨跌幅", 262 | "流入资金", 263 | "流出资金", 264 | "净额", 265 | "公司家数", 266 | "领涨股", 267 | "领涨股-涨跌幅", 268 | "当前价", 269 | ] 270 | big_df["行业-涨跌幅"] = big_df["行业-涨跌幅"].str.strip("%") 271 | big_df["领涨股-涨跌幅"] = big_df["领涨股-涨跌幅"].str.strip("%") 272 | big_df["行业-涨跌幅"] = pd.to_numeric(big_df["行业-涨跌幅"], errors="coerce") 273 | big_df["领涨股-涨跌幅"] = pd.to_numeric(big_df["领涨股-涨跌幅"], errors="coerce") 274 | else: 275 | big_df.columns = [ 276 | "序号", 277 | "行业", 278 | "公司家数", 279 | "行业指数", 280 | "阶段涨跌幅", 281 | "流入资金", 282 | "流出资金", 283 | "净额", 284 | ] 285 | return big_df 286 | 287 | def stock_fund_flow_industry(symbol): 288 | """ 289 | 同花顺-数据中心-资金流向-行业资金流 290 | http://data.10jqka.com.cn/funds/hyzjl/#refCountId=data_55f13c2c_254 291 | :param symbol: choice of {“即时”, "3日排行", "5日排行", "10日排行", "20日排行"} 292 | """ 293 | js_code = py_mini_racer.MiniRacer() 294 | js_content = _get_file_content_ths("ths.js") 295 | js_code.eval(js_content) 296 | v_code = js_code.call("v") 297 | headers = { 298 | "Accept": "text/html, */*; q=0.01", 299 | "Accept-Encoding": "gzip, deflate", 300 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 301 | "Cache-Control": "no-cache", 302 | "Connection": "keep-alive", 303 | "hexin-v": v_code, 304 | "Host": "data.10jqka.com.cn", 305 | "Pragma": "no-cache", 306 | "Referer": "http://data.10jqka.com.cn/funds/hyzjl/", 307 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36", 308 | "X-Requested-With": "XMLHttpRequest", 309 | } 310 | url = ( 311 | "http://data.10jqka.com.cn/funds/hyzjl/field/tradezdf/order/desc/ajax/1/free/1/" 312 | ) 313 | r = requests.get(url, headers=headers) 314 | soup = BeautifulSoup(r.text, "lxml") 315 | raw_page = soup.find("span", attrs={"class": "page_info"}).text 316 | page_num = raw_page.split("/")[1] 317 | if symbol == "3日排行": 318 | url = "http://data.10jqka.com.cn/funds/hyzjl/board/3/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 319 | elif symbol == "5日排行": 320 | url = "http://data.10jqka.com.cn/funds/hyzjl/board/5/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 321 | elif symbol == "10日排行": 322 | url = "http://data.10jqka.com.cn/funds/hyzjl/board/10/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 323 | elif symbol == "20日排行": 324 | url = "http://data.10jqka.com.cn/funds/hyzjl/board/20/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 325 | else: 326 | url = "http://data.10jqka.com.cn/funds/hyzjl/field/tradezdf/order/desc/page/{}/ajax/1/free/1/" 327 | big_df = pd.DataFrame() 328 | for page in tqdm(range(1, int(page_num) + 1)): 329 | js_code = py_mini_racer.MiniRacer() 330 | js_content = _get_file_content_ths("ths.js") 331 | js_code.eval(js_content) 332 | v_code = js_code.call("v") 333 | headers = { 334 | "Accept": "text/html, */*; q=0.01", 335 | "Accept-Encoding": "gzip, deflate", 336 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 337 | "Cache-Control": "no-cache", 338 | "Connection": "keep-alive", 339 | "hexin-v": v_code, 340 | "Host": "data.10jqka.com.cn", 341 | "Pragma": "no-cache", 342 | "Referer": "http://data.10jqka.com.cn/funds/hyzjl/", 343 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36", 344 | "X-Requested-With": "XMLHttpRequest", 345 | } 346 | r = requests.get(url.format(page), headers=headers) 347 | temp_df = pd.read_html(r.text)[0] 348 | big_df = pd.concat([big_df, temp_df], ignore_index=True) 349 | 350 | del big_df["序号"] 351 | big_df.reset_index(inplace=True) 352 | big_df["index"] = range(1, len(big_df) + 1) 353 | if symbol == "即时": 354 | big_df.columns = [ 355 | "序号", 356 | "行业", 357 | "行业指数", 358 | "行业-涨跌幅", 359 | "流入资金", 360 | "流出资金", 361 | "净额", 362 | "公司家数", 363 | "领涨股", 364 | "领涨股-涨跌幅", 365 | "当前价", 366 | ] 367 | big_df["行业-涨跌幅"] = big_df["行业-涨跌幅"].str.strip("%") 368 | big_df["领涨股-涨跌幅"] = big_df["领涨股-涨跌幅"].str.strip("%") 369 | big_df["行业-涨跌幅"] = pd.to_numeric(big_df["行业-涨跌幅"], errors="coerce") 370 | big_df["领涨股-涨跌幅"] = pd.to_numeric(big_df["领涨股-涨跌幅"], errors="coerce") 371 | else: 372 | big_df.columns = [ 373 | "序号", 374 | "行业", 375 | "公司家数", 376 | "行业指数", 377 | "阶段涨跌幅", 378 | "流入资金", 379 | "流出资金", 380 | "净额", 381 | ] 382 | return big_df 383 | 384 | def stock_zygc_ym(symbol): 385 | """ 386 | 益盟-F10-主营构成 387 | http://f10.emoney.cn/f10/zbyz/1000001 388 | """ 389 | url = f"http://f10.emoney.cn/f10/zygc/{symbol}" 390 | r = requests.get(url) 391 | soup = BeautifulSoup(r.text, "lxml") 392 | year_list = [ 393 | item.text.strip() 394 | for item in soup.find(attrs={"class": "swlab_t"}).find_all("li") 395 | ] 396 | 397 | big_df = pd.DataFrame() 398 | for i, item in enumerate(year_list, 2): 399 | temp_df = pd.read_html(r.text, header=0)[i] 400 | temp_df.columns = [ 401 | "分类方向", 402 | "分类", 403 | "营业收入", 404 | "营业收入-同比增长", 405 | "营业收入-占主营收入比", 406 | "营业成本", 407 | "营业成本-同比增长", 408 | "营业成本-占主营成本比", 409 | "毛利率", 410 | "毛利率-同比增长", 411 | ] 412 | temp_df["报告期"] = item 413 | big_df = pd.concat([big_df, temp_df], ignore_index=True) 414 | 415 | big_df = big_df[ 416 | [ 417 | "报告期", 418 | "分类方向", 419 | "分类", 420 | "营业收入", 421 | "营业收入-同比增长", 422 | "营业收入-占主营收入比", 423 | "营业成本", 424 | "营业成本-同比增长", 425 | "营业成本-占主营成本比", 426 | "毛利率", 427 | "毛利率-同比增长", 428 | ] 429 | ] 430 | return big_df 431 | -------------------------------------------------------------------------------- /globalVariable.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | import os, pytz 6 | import datetime 7 | from PySide6.QtGui import QPalette, QColor 8 | from PySide6.QtCore import Qt, QSettings, QDateTime 9 | 10 | settings = QSettings("config.ini", QSettings.IniFormat) 11 | 12 | def _init(): 13 | global whatInterface 14 | whatInterface = 1 15 | global marketNum 16 | marketNum = 1 17 | global PreInterface 18 | PreInterface = 0 19 | global subCount 20 | subCount = 1 21 | global isBoardWidth 22 | isBoardWidth = False 23 | init_style() 24 | 25 | def init_style(): 26 | global pered 27 | pered = QPalette() 28 | global pegreen 29 | pegreen = QPalette() 30 | global peblack 31 | peblack = QPalette() 32 | global peblue 33 | peblue = QPalette() 34 | global redBackGround 35 | redBackGround = QPalette() 36 | global greenBackGround 37 | greenBackGround = QPalette() 38 | pered.setColor(QPalette.WindowText, Qt.red) 39 | pegreen.setColor(QPalette.WindowText, QColor(0, 191, 0)) 40 | peblack.setColor(QPalette.WindowText, Qt.black) 41 | peblue.setColor(QPalette.WindowText, Qt.blue) 42 | global circle_green_SheetStyle 43 | circle_green_SheetStyle = "min-width: 16px; min-height: 16px;max-width:16px; max-height: 16px;border-radius: 8px; border:1px solid black;background:green" 44 | global circle_red_SheetStyle 45 | circle_red_SheetStyle = "min-width: 16px; min-height: 16px;max-width:16px; max-height: 16px;border-radius: 8px; border:1px solid black;background:red" 46 | 47 | def getValue(): 48 | return whatInterface 49 | 50 | def setValue(value): 51 | global whatInterface 52 | whatInterface = value 53 | 54 | def getIsNet(): 55 | IsNet = os.system('ping 110.242.68.66 -n 1') 56 | return IsNet 57 | 58 | # 是否交易日 59 | def isWeekend(): 60 | tz = pytz.timezone('Asia/shanghai') 61 | date_zh = datetime.datetime.now(tz) 62 | localweek = int(date_zh.strftime('%w')) 63 | if localweek in [1, 2, 3, 4, 5]: 64 | return False 65 | else: 66 | return True 67 | 68 | def isHKMarketDay(): 69 | tz = pytz.timezone('Asia/Hong_Kong') 70 | date_zh = datetime.datetime.now(tz) 71 | Vacation = eval(settings.value("General/Vacation_HK")) 72 | localdate = int(date_zh.strftime('%m%d')) 73 | localweek = int(date_zh.strftime('%w')) 74 | localtime = int(date_zh.strftime("%H%M%S")) 75 | if localdate not in Vacation and localweek in [1, 2, 3, 4, 5] and ( 76 | (90000 <= localtime <= 121505) or (130000 <= localtime <= 161505)): 77 | return True 78 | else: 79 | return False 80 | 81 | def isZhMarketDay(): 82 | tz = pytz.timezone('Asia/shanghai') 83 | date_zh = datetime.datetime.now(tz) 84 | Vacation = eval(settings.value("General/Vacation_ZH")) 85 | localdate = int(date_zh.strftime('%m%d')) 86 | localweek = int(date_zh.strftime('%w')) 87 | localtime = int(date_zh.strftime("%H%M%S")) 88 | if localdate not in Vacation and localweek in [1, 2, 3, 4, 5] and ( 89 | (91500 <= localtime <= 113010) or (130000 <= localtime <= 150010)): 90 | return True 91 | else: 92 | return False 93 | 94 | def isUSMarketDay(): 95 | tz = pytz.timezone('America/New_York') 96 | date_us = datetime.datetime.now(tz) 97 | Vacation = eval(settings.value("General/Vacation_US")) 98 | localdate = int(date_us.strftime('%m%d')) 99 | localweek = int(date_us.strftime('%w')) 100 | localtime = int(date_us.strftime("%H%M%S")) 101 | if localdate not in Vacation and localweek in [1, 2, 3, 4, 5] and (localtime >= 93000 and localtime <= 160005): 102 | return True 103 | else: 104 | return False 105 | 106 | def curRecentMarketDay(): 107 | date = datetime.datetime.now() 108 | for i in range(15): 109 | time = date + datetime.timedelta(days=-i) 110 | if isMarketDay(time): 111 | return time 112 | return 0 113 | 114 | def time_to_QDateTime(time): 115 | str = time.strftime("%Y%m%d %H:%M:%S") 116 | date = QDateTime.fromString(str, "yyyyMMdd hh:mm:ss").date() 117 | return date 118 | 119 | def isMarketDay(date_zh): 120 | Vacation = eval(settings.value("General/Vacation_ZH")) 121 | local = datetime.datetime.now() 122 | localdate = int(date_zh.strftime('%m%d')) 123 | localweek = int(date_zh.strftime('%w')) 124 | localtime = int(local.strftime("%H%M%S")) 125 | if localdate not in Vacation and localweek in [1, 2, 3, 4, 5]: 126 | if local == date_zh and localtime < 150000: 127 | return False 128 | return True 129 | return False 130 | 131 | def format_conversion(grid): 132 | if isinstance(grid, float): 133 | if float(grid) >= 100000000: 134 | return str(round(float(grid) / 100000000, 4)) + '亿' 135 | elif float(grid) >= 10000: 136 | return str(round(float(grid) / 10000, 4)) + '万' 137 | elif float(grid) <= -100000000: 138 | return str(round(float(grid) / 100000000, 4)) + '亿' 139 | elif float(grid) <= -10000: 140 | return str(round(float(grid) / 10000, 4)) + '万' 141 | return str(round(float(grid), 2)) 142 | elif isinstance(grid, int): 143 | if int(grid) >= 100000000: 144 | return str(round(int(grid) / 100000000, 4)) + '亿' 145 | elif int(grid) >= 10000: 146 | return str(round(int(grid) / 10000, 4)) + '万' 147 | elif int(grid) <= -100000000: 148 | return str(round(int(grid) / 100000000, 4)) + '亿' 149 | elif int(grid) <= -10000: 150 | return str(round(int(grid) / 10000, 4)) + '万' 151 | elif str(grid).isdigit(): 152 | if int(grid) >= 100000000: 153 | return str(round(int(grid) / 100000000, 4)) + '亿' 154 | elif int(grid) >= 10000: 155 | return str(round(int(grid) / 10000, 4)) + '万' 156 | elif int(grid) <= -100000000: 157 | return str(round(int(grid) / 100000000, 4)) + '亿' 158 | elif int(grid) <= -10000: 159 | return str(round(int(grid) / 10000, 4)) + '万' 160 | return str(grid) 161 | 162 | def single_get_first(unicode1): 163 | str1 = unicode1.encode('gbk') 164 | try: 165 | ord(str1) 166 | return str1 167 | except: 168 | asc = str1[0] * 256 + str1[1] 169 | if 45217 <= asc <= 45252: 170 | return 'a' 171 | if 45253 <= asc <= 45760: 172 | return 'b' 173 | if 45761 <= asc <= 46317: 174 | return 'c' 175 | if 46318 <= asc <= 46825: 176 | return 'd' 177 | if 46826 <= asc <= 47009: 178 | return 'e' 179 | if 47010 <= asc <= 47296: 180 | return 'f' 181 | if 47297 <= asc <= 47613: 182 | return 'g' 183 | if 47614 <= asc <= 48118: 184 | return 'h' 185 | if 48119 <= asc <= 49061: 186 | return 'j' 187 | if 49062 <= asc <= 49323: 188 | return 'k' 189 | if 49324 <= asc <= 49895: 190 | return 'l' 191 | if 49896 <= asc <= 50370: 192 | return 'm' 193 | if 50371 <= asc <= 50613: 194 | return 'n' 195 | if 50614 <= asc <= 50621: 196 | return 'o' 197 | if 50622 <= asc <= 50905: 198 | return 'p' 199 | if 50906 <= asc <= 51386: 200 | return 'q' 201 | if 51387 <= asc <= 51445: 202 | return 'r' 203 | if 51446 <= asc <= 52217: 204 | return 's' 205 | if 52218 <= asc <= 52697: 206 | return 't' 207 | if 52698 <= asc <= 52979: 208 | return 'w' 209 | if 52980 <= asc <= 53688: 210 | return 'x' 211 | if 53689 <= asc <= 54480: 212 | return 'y' 213 | if 54481 <= asc <= 55289: 214 | return 'z' 215 | return '' 216 | 217 | def getPinyin(string): 218 | if string == None: 219 | return None 220 | lst = list(string) 221 | charLst = [] 222 | for l in lst: 223 | if u'\u4e00' <= l <= u'\u9fa5': 224 | charLst.append(single_get_first(l)) 225 | else: 226 | charLst.append(l) 227 | return ''.join(charLst) 228 | -------------------------------------------------------------------------------- /key.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/key.wav -------------------------------------------------------------------------------- /list/abbreviation_index_list.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/abbreviation_index_list.csv -------------------------------------------------------------------------------- /list/abbreviation_list.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/abbreviation_list.csv -------------------------------------------------------------------------------- /list/concept_industry_board.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/concept_industry_board.csv -------------------------------------------------------------------------------- /list/index.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/index.csv -------------------------------------------------------------------------------- /list/index_list.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/index_list.csv -------------------------------------------------------------------------------- /list/my_stock.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/my_stock.csv -------------------------------------------------------------------------------- /list/rising_speed.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/rising_speed.csv -------------------------------------------------------------------------------- /list/rising_speed.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/rising_speed.txt -------------------------------------------------------------------------------- /list/stock_list.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/list/stock_list.csv -------------------------------------------------------------------------------- /logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjh4312/stock-quotes/db67c774620fa1e2c7a040c38545e4dfddc0e9d5/logo.ico -------------------------------------------------------------------------------- /modelAnalysisTable.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | 6 | from PySide6.QtCore import QAbstractTableModel,Qt 7 | from PySide6.QtGui import QColor,QFont 8 | 9 | class AnalysisTable(QAbstractTableModel): 10 | def __init__(self, data): 11 | QAbstractTableModel.__init__(self) 12 | self._data = data 13 | 14 | def rowCount(self, parent=None): 15 | return self._data.shape[0] 16 | 17 | def columnCount(self, parent=None): 18 | return self._data.shape[1] 19 | 20 | # 显示数据 21 | def data(self, index, role=Qt.DisplayRole): 22 | if index.isValid(): 23 | grid=self._data.iloc[index.row(), index.column()] 24 | if role == Qt.DisplayRole: 25 | if isinstance(grid,float): 26 | if float(grid)>=100000000: 27 | return str(round(float(grid)/100000000,4))+'亿' 28 | elif float(grid)>=10000: 29 | return str(round(float(grid)/10000,2))+'万' 30 | elif float(grid)<=-100000000: 31 | return str(round(float(grid)/100000000,4))+'亿' 32 | elif float(grid)<=-10000: 33 | return str(round(float(grid)/10000,2))+'万' 34 | return round(float(grid),2) 35 | elif isinstance(grid,int): 36 | if int(grid)>=100000000: 37 | return str(round(int(grid)/100000000,4))+'亿' 38 | elif int(grid)>=10000: 39 | return str(round(int(grid)/10000,2))+'万' 40 | elif int(grid)<=-100000000: 41 | return str(round(int(grid)/100000000,4))+'亿' 42 | elif int(grid)<=-10000: 43 | return str(round(int(grid)/10000,2))+'万' 44 | elif str(grid).isdigit(): 45 | if int(grid)>=100000000: 46 | return str(round(int(grid)/100000000,4))+'亿' 47 | elif int(grid)>=10000 and index.column()!=0: 48 | return str(round(int(grid)/10000,2))+'万' 49 | elif int(grid)<=-100000000: 50 | return str(round(int(grid)/100000000,4))+'亿' 51 | elif int(grid)<=-10000: 52 | return str(round(int(grid)/10000,2))+'万' 53 | return str(grid) 54 | elif role == Qt.ForegroundRole: 55 | if self._data.iloc[index.row(), 2]=='合计': 56 | return QColor(Qt.red) 57 | elif self._data.iloc[index.row(), 1]=='按行业分': 58 | return QColor(255,185,15) 59 | elif self._data.iloc[index.row(), 1]=='按地区分': 60 | return QColor(Qt.blue) 61 | elif self._data.iloc[index.row(), 1]=='按产品分': 62 | return QColor(255,0,255) 63 | #涨红 跌绿 64 | elif isinstance(grid,float): 65 | if grid<0: 66 | return QColor(0,191,0) 67 | 68 | elif role == Qt.FontRole: 69 | if self._data.iloc[index.row(), 2]=='合计': 70 | boldFont = QFont() 71 | boldFont.setBold(True) 72 | return boldFont 73 | return None 74 | 75 | # 显示行和列头 76 | def headerData(self, col, orientation, role): 77 | if orientation == Qt.Horizontal and role == Qt.DisplayRole: 78 | return self._data.columns[col] 79 | elif orientation == Qt.Vertical and role == Qt.DisplayRole: 80 | return self._data.axes[0][col] 81 | return None 82 | 83 | -------------------------------------------------------------------------------- /modelTableStock.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | 6 | from PySide6.QtCore import QAbstractTableModel,Qt 7 | from PySide6.QtGui import QColor,QFont 8 | 9 | class ModelTableStock(QAbstractTableModel): 10 | def __init__(self, data): 11 | QAbstractTableModel.__init__(self) 12 | self._data = data 13 | 14 | def rowCount(self, parent=None): 15 | return self._data.shape[0] 16 | 17 | def columnCount(self, parent=None): 18 | return self._data.shape[1] 19 | 20 | # 显示数据 21 | def data(self, index, role=Qt.DisplayRole): 22 | if index.isValid(): 23 | if role == Qt.DisplayRole: 24 | grid=self._data.iloc[index.row(), index.column()] 25 | if isinstance(grid,float): 26 | if float(grid)>=100000000: 27 | return str(round(float(grid)/100000000,2))+'亿' 28 | elif float(grid)>=10000: 29 | return str(round(float(grid)/10000,2))+'万' 30 | return str(grid) 31 | elif role == Qt.ForegroundRole: 32 | #涨红 跌绿 33 | if index.column()==3 and self._data.iloc[index.row(), 3]>0: 34 | return QColor(Qt.red) 35 | elif index.column()==3 and self._data.iloc[index.row(), 3]<0: 36 | return QColor(0,191,0) 37 | #成交额大于1个亿或者于10个亿 38 | elif index.column()==5 and self._data.iloc[index.row(), 5]>=1000000000: 39 | return QColor(153,0,153) 40 | elif index.column()==5 and self._data.iloc[index.row(), 5]>=300000000: 41 | return QColor(0,191,255) 42 | #换手大于15 43 | elif index.column()==4 and self._data.iloc[index.row(), 4]>=15: 44 | return QColor(204,204,0) 45 | #涨速 46 | elif index.column()==6 and self._data.iloc[index.row(), 6]>=2: 47 | return QColor(153,0,153) 48 | elif index.column()==6 and self._data.iloc[index.row(), 6]>0: 49 | return QColor(Qt.red) 50 | elif index.column()==6 and self._data.iloc[index.row(), 6]<0: 51 | return QColor(0,191,0) 52 | # #市值大于100个亿 53 | # elif index.column()==8 and self._data.iloc[index.row(), 8]>=10000000000: 54 | # return QColor(153,0,153) 55 | # elif index.column()==9 and self._data.iloc[index.row(), 9]>=10000000000: 56 | # return QColor(153,0,153) 57 | # #5分钟涨跌 58 | # elif index.column()==15 and self._data.iloc[index.row(), 15]>0: 59 | # return QColor(Qt.red) 60 | # elif index.column()==15 and self._data.iloc[index.row(), 15]<0: 61 | # return QColor(0,191,0) 62 | #60日涨跌 63 | elif index.column()==11 and self._data.iloc[index.row(), 11]>0 and self._data.iloc[index.row(), 11]<100: 64 | return QColor(255,155,153) 65 | elif index.column()==11 and self._data.iloc[index.row(), 11]>=100: 66 | return QColor(153,0,153) 67 | elif index.column()==11 and self._data.iloc[index.row(), 11]<0: 68 | return QColor(0,191,0) 69 | #今年涨跌 70 | elif index.column()==10 and self._data.iloc[index.row(), 10]>0 and self._data.iloc[index.row(), 10]<100: 71 | return QColor(255,155,153) 72 | elif index.column()==10 and self._data.iloc[index.row(), 10]>=100: 73 | return QColor(153,0,153) 74 | elif index.column()==10 and self._data.iloc[index.row(), 10]<0: 75 | return QColor(0,191,0) 76 | 77 | #阳线红,阴线绿 78 | elif (index.column()==2 or index.column()==15)and self._data.iloc[index.row(), 2]>self._data.iloc[index.row(), 15]: 79 | return QColor(255,0,255) 80 | elif (index.column()==2 or index.column()==15)and self._data.iloc[index.row(), 2]self._data.iloc[index.row(), 16]: 84 | return QColor(Qt.red) 85 | elif index.column()==13 and self._data.iloc[index.row(), 13]self._data.iloc[index.row(), 16]: 88 | return QColor(Qt.red) 89 | elif index.column()==14 and self._data.iloc[index.row(), 14]= u'\u4e00' and l <= u'\u9fa5': 27 | charLst.append(pinyin.get(l)[0]) 28 | else: 29 | charLst.append(l) 30 | if ''.join(charLst)==self.stock_code: 31 | self.stock_code=row['code'] 32 | self.name=row['code_name'] 33 | self.industry='--'+str(row['industry']) 34 | if self.industry=='--nan': 35 | self.industry='' 36 | return 37 | self.name='666' 38 | 39 | def from_pinyin_to_code(self): 40 | stock=pd.read_csv('e:/cjh/Documents/python_stock/stock_industry.csv',encoding="gbk") 41 | for index,row in stock.iterrows(): 42 | if self.getPinyin(row['code_name'])==self.code_text.text(): 43 | 44 | self.stock_code=row['code'] 45 | self.name=row['code_name'] 46 | self.industry='--'+str(row['industry']) 47 | if self.industry=='--nan': 48 | self.industry='' 49 | return (self.name,self.industry) 50 | self.name='666' 51 | return self.name 52 | 53 | def getNameIndustry(self): 54 | stock=pd.read_csv('e:/cjh/Documents/python_stock/stock_industry.csv',encoding="gbk") 55 | n=len(stock) 56 | l=0 57 | r=n-1 58 | while l<=r: 59 | mid=(l+r)//2 60 | if stock.loc[mid].iloc[0]==self.stock_code: 61 | #self.stock_code=str(stock.loc[mid].iloc[0]) 62 | (self.name,self.industry)=(str(stock.loc[mid].iloc[1]),'--'+str(stock.loc[mid].iloc[2])) 63 | if self.industry=='--nan': 64 | self.industry='' 65 | return (self.name,self.industry) 66 | elif stock.loc[mid].iloc[0]>self.stock_code: 67 | r=mid-1 68 | else: 69 | l=mid+1 70 | self.name='666' 71 | return self.name 72 | 73 | def single_get_first(self,unicode1): 74 | str1 = unicode1.encode('gbk') 75 | try: 76 | ord(str1) 77 | return str1 78 | except: 79 | asc = str1[0] * 256 + str1[1] 80 | if asc >= 45217 and asc <= 45252: 81 | return 'a' 82 | if asc >= 45253 and asc <= 45760: 83 | return 'b' 84 | if asc >= 45761 and asc <= 46317: 85 | return 'c' 86 | if asc >= 46318 and asc <= 46825: 87 | return 'd' 88 | if asc >= 46826 and asc <= 47009: 89 | return 'e' 90 | if asc >= 47010 and asc <= 47296: 91 | return 'f' 92 | if asc >= 47297 and asc <= 47613: 93 | return 'g' 94 | if asc >= 47614 and asc <= 48118: 95 | return 'h' 96 | if asc >= 48119 and asc <= 49061: 97 | return 'j' 98 | if asc >= 49062 and asc <= 49323: 99 | return 'k' 100 | if asc >= 49324 and asc <= 49895: 101 | return 'l' 102 | if asc >= 49896 and asc <= 50370: 103 | return 'm' 104 | if asc >= 50371 and asc <= 50613: 105 | return 'n' 106 | if asc >= 50614 and asc <= 50621: 107 | return 'o' 108 | if asc >= 50622 and asc <= 50905: 109 | return 'p' 110 | if asc >= 50906 and asc <= 51386: 111 | return 'q' 112 | if asc >= 51387 and asc <= 51445: 113 | return 'r' 114 | if asc >= 51446 and asc <= 52217: 115 | return 's' 116 | if asc >= 52218 and asc <= 52697: 117 | return 't' 118 | if asc >= 52698 and asc <= 52979: 119 | return 'w' 120 | if asc >= 52980 and asc <= 53688: 121 | return 'x' 122 | if asc >= 53689 and asc <= 54480: 123 | return 'y' 124 | if asc >= 54481 and asc <= 55289: 125 | return 'z' 126 | return '' 127 | 128 | def getPinyin(self,string): 129 | if string == None: 130 | return None 131 | lst = list(string) 132 | charLst = [] 133 | for l in lst: 134 | if l >= u'\u4e00' and l <= u'\u9fa5': 135 | charLst.append(self.single_get_first(l)) 136 | else: 137 | charLst.append(l) 138 | return ''.join(charLst) 139 | -------------------------------------------------------------------------------- /stockInformation.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | #import tushare as ts 6 | import pandas as pd 7 | from xpinyin import Pinyin 8 | import requests 9 | 10 | def download(): 11 | deal_with_index_list() 12 | deal_with_concept_industry() 13 | deal_with_stock_list() 14 | 15 | def deal_with_stock_list(): 16 | data1=pd.read_csv('list/abbreviation_index_list.csv',encoding="gbk") 17 | #data1.sort_values(by=data1.columns[0],ascending=True,inplace=True) 18 | data2=pd.read_csv('list/concept_industry_board.csv',encoding="gbk") 19 | #data2.sort_values(by=data2.columns[0],ascending=True,inplace=True) 20 | data1=data1[['symbol','name','abbreviation']] 21 | data2=data2[['symbol','name','abbreviation']] 22 | # data=pd.read_csv('list/tushare_stock_basic.csv',dtype={'symbol':str}) 23 | headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 24 | url='http://api.waditu.com' 25 | params = { 26 | 'api_name': 'stock_basic', 27 | 'token': 'bbe1d68e9a152f87296960ffd981449ed98fff7cfd13b3cf2a50be79', 28 | 'fields': 'ts_code,symbol,name,area,industry,list_date,cnspell' 29 | } 30 | dd = requests.post(url, json=params,headers=headers) 31 | data=pd.DataFrame(dd.json()['data']['items']) 32 | #data.rename(columns={'cnspell':'abbreviation'},inplace=True) 33 | #data.sort_values(by=data.columns[5],ascending=True,inplace=True) 34 | #data.index = pd.RangeIndex(start=1, stop=len(data)+1, step=1) 35 | data.columns=['ts_code','symbol','name','area','industry','abbreviation','list_date'] 36 | 37 | data.to_csv('list/stock_list.csv',encoding="gbk") 38 | data=pd.concat([data2,data1,data]) 39 | data.sort_values(by=data.columns[2],ascending=True,inplace=True) 40 | data.index = pd.RangeIndex(start=1, stop=len(data)+1, step=1) 41 | data.to_csv('list/abbreviation_list.csv',encoding="gbk") 42 | print('个股处理完毕') 43 | 44 | def deal_with_index_list(): 45 | data = pd.read_html("https://www.joinquant.com/data/dict/indexData")[0] 46 | data["指数代码"] = data["指数代码"].str.split(".", expand=True)[0] 47 | del data['行情开始日期'] 48 | data.columns = ["symbol", "name", 'publish_date',"abbreviation"] 49 | for i in range(len(data)): 50 | data.loc[i,'abbreviation']=data.loc[i,'abbreviation'].lower() 51 | if data.loc[i,'symbol'][0:3]!='399': 52 | data.loc[i,'symbol']='sh.'+data.loc[i,'symbol'] 53 | data.sort_values(by=data.columns[3],ascending=True,inplace=True) 54 | data.index = pd.RangeIndex(start=1, stop=len(data)+1, step=1) 55 | data.to_csv('list/abbreviation_index_list.csv',encoding="gbk") 56 | print('指数处理完毕') 57 | 58 | def deal_with_concept_industry(): 59 | data=stock_board_concept_name_em() 60 | data=data[['板块代码','板块名称']] 61 | data.rename(columns={'板块名称':'name','板块代码':'symbol'},inplace=True) 62 | data1=stock_board_industry_name_em() 63 | data1=data1[['板块代码','板块名称']] 64 | data1.rename(columns={'板块名称':'name','板块代码':'symbol'},inplace=True) 65 | url='http://push2.eastmoney.com/api/qt/clist/get?pn=1&pz=40&po=0&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:90+t:1+f:!50&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f26,f22,f33,f11,f62,f128,f136,f115,f152,f124,f107,f104,f105,f140,f141,f207,f208,f209,f222&_=1665566741514' 66 | headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 67 | data2=pd.DataFrame(requests.get(url,headers=headers).json()['data']['diff'])[['f12','f14']] 68 | data2.rename(columns={'f12':'symbol','f14':'name'},inplace=True) 69 | data=pd.concat([data,data1,data2]) 70 | data.index = pd.RangeIndex(start=0, stop=len(data), step=1) 71 | for row in range(len(data)): 72 | #name=globalVariable.getPinyin(data.loc[row,'display_name']) 73 | data.loc[row,'abbreviation']=get_pinyin_to_abbreviation(data.loc[row,'name']) 74 | data.sort_values(by=data.columns[2],ascending=True,inplace=True) 75 | data.index = pd.RangeIndex(start=1, stop=len(data)+1, step=1) 76 | data.to_csv('list/concept_industry_board.csv',encoding='gbk') 77 | print('板块处理完毕') 78 | 79 | def get_pinyin_to_abbreviation(stock): 80 | p=Pinyin() 81 | result1=p.get_pinyin(stock) 82 | l=[] 83 | s=result1.split('-') 84 | for i in range(len(s)): 85 | if len(s[i])==0: 86 | continue 87 | for j in range(len(s[i])): 88 | if not s[i][j].islower(): 89 | l.append(''.join(s[i]).lower()) 90 | break 91 | if j==len(s[i])-1: 92 | l.append(''.join(s[i][0])) 93 | continue 94 | return ''.join(l) 95 | 96 | def stock_board_concept_name_em(): 97 | """ 98 | 东方财富网-沪深板块-概念板块-名称 99 | http://quote.eastmoney.com/center/boardlist.html#concept_board 100 | :return: 概念板块-名称 101 | :rtype: pandas.DataFrame 102 | """ 103 | url = "http://79.push2.eastmoney.com/api/qt/clist/get" 104 | params = { 105 | "pn": "1", 106 | "pz": "2000", 107 | "po": "1", 108 | "np": "1", 109 | "ut": "bd1d9ddb04089700cf9c27f6f7426281", 110 | "fltt": "2", 111 | "invt": "2", 112 | "fid": "f3", 113 | "fs": "m:90 t:3 f:!50", 114 | "fields": "f2,f3,f4,f8,f12,f14,f15,f16,f17,f18,f20,f21,f24,f25,f22,f33,f11,f62,f128,f124,f107,f104,f105,f136", 115 | "_": "1626075887768", 116 | } 117 | r = requests.get(url, params=params) 118 | data_json = r.json() 119 | temp_df = pd.DataFrame(data_json["data"]["diff"]) 120 | temp_df.reset_index(inplace=True) 121 | temp_df["index"] = range(1, len(temp_df) + 1) 122 | temp_df.columns = [ 123 | "排名", 124 | "最新价", 125 | "涨跌幅", 126 | "涨跌额", 127 | "换手率", 128 | "_", 129 | "板块代码", 130 | "板块名称", 131 | "_", 132 | "_", 133 | "_", 134 | "_", 135 | "总市值", 136 | "_", 137 | "_", 138 | "_", 139 | "_", 140 | "_", 141 | "_", 142 | "上涨家数", 143 | "下跌家数", 144 | "_", 145 | "_", 146 | "领涨股票", 147 | "_", 148 | "_", 149 | "领涨股票-涨跌幅", 150 | ] 151 | temp_df = temp_df[ 152 | [ 153 | "排名", 154 | "板块名称", 155 | "板块代码", 156 | "最新价", 157 | "涨跌额", 158 | "涨跌幅", 159 | "总市值", 160 | "换手率", 161 | "上涨家数", 162 | "下跌家数", 163 | "领涨股票", 164 | "领涨股票-涨跌幅", 165 | ] 166 | ] 167 | temp_df["最新价"] = pd.to_numeric(temp_df["最新价"], errors="coerce") 168 | temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"], errors="coerce") 169 | temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"], errors="coerce") 170 | temp_df["总市值"] = pd.to_numeric(temp_df["总市值"], errors="coerce") 171 | temp_df["换手率"] = pd.to_numeric(temp_df["换手率"], errors="coerce") 172 | temp_df["上涨家数"] = pd.to_numeric(temp_df["上涨家数"], errors="coerce") 173 | temp_df["下跌家数"] = pd.to_numeric(temp_df["下跌家数"], errors="coerce") 174 | temp_df["领涨股票-涨跌幅"] = pd.to_numeric(temp_df["领涨股票-涨跌幅"], errors="coerce") 175 | return temp_df 176 | 177 | def stock_board_industry_name_em(): 178 | """ 179 | 东方财富网-沪深板块-行业板块-名称 180 | http://quote.eastmoney.com/center/boardlist.html#industry_board 181 | :return: 行业板块-名称 182 | :rtype: pandas.DataFrame 183 | """ 184 | url = "http://17.push2.eastmoney.com/api/qt/clist/get" 185 | params = { 186 | "pn": "1", 187 | "pz": "2000", 188 | "po": "1", 189 | "np": "1", 190 | "ut": "bd1d9ddb04089700cf9c27f6f7426281", 191 | "fltt": "2", 192 | "invt": "2", 193 | "fid": "f3", 194 | "fs": "m:90 t:2 f:!50", 195 | "fields": "f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f26,f22,f33,f11,f62,f128,f136,f115,f152,f124,f107,f104,f105,f140,f141,f207,f208,f209,f222", 196 | "_": "1626075887768", 197 | } 198 | r = requests.get(url, params=params) 199 | data_json = r.json() 200 | temp_df = pd.DataFrame(data_json["data"]["diff"]) 201 | temp_df.reset_index(inplace=True) 202 | temp_df["index"] = temp_df.index + 1 203 | temp_df.columns = [ 204 | "排名", 205 | "-", 206 | "最新价", 207 | "涨跌幅", 208 | "涨跌额", 209 | "-", 210 | "_", 211 | "-", 212 | "换手率", 213 | "-", 214 | "-", 215 | "-", 216 | "板块代码", 217 | "-", 218 | "板块名称", 219 | "-", 220 | "-", 221 | "-", 222 | "-", 223 | "总市值", 224 | "-", 225 | "-", 226 | "-", 227 | "-", 228 | "-", 229 | "-", 230 | "-", 231 | "-", 232 | "上涨家数", 233 | "下跌家数", 234 | "-", 235 | "-", 236 | "-", 237 | "领涨股票", 238 | "-", 239 | "-", 240 | "领涨股票-涨跌幅", 241 | "-", 242 | "-", 243 | "-", 244 | "-", 245 | "-", 246 | ] 247 | temp_df = temp_df[ 248 | [ 249 | "排名", 250 | "板块名称", 251 | "板块代码", 252 | "最新价", 253 | "涨跌额", 254 | "涨跌幅", 255 | "总市值", 256 | "换手率", 257 | "上涨家数", 258 | "下跌家数", 259 | "领涨股票", 260 | "领涨股票-涨跌幅", 261 | ] 262 | ] 263 | temp_df["最新价"] = pd.to_numeric(temp_df["最新价"], errors="coerce") 264 | temp_df["涨跌额"] = pd.to_numeric(temp_df["涨跌额"], errors="coerce") 265 | temp_df["涨跌幅"] = pd.to_numeric(temp_df["涨跌幅"], errors="coerce") 266 | temp_df["总市值"] = pd.to_numeric(temp_df["总市值"], errors="coerce") 267 | temp_df["换手率"] = pd.to_numeric(temp_df["换手率"], errors="coerce") 268 | temp_df["上涨家数"] = pd.to_numeric(temp_df["上涨家数"], errors="coerce") 269 | temp_df["下跌家数"] = pd.to_numeric(temp_df["下跌家数"], errors="coerce") 270 | temp_df["领涨股票-涨跌幅"] = pd.to_numeric(temp_df["领涨股票-涨跌幅"], errors="coerce") 271 | return temp_df 272 | -------------------------------------------------------------------------------- /threadDealTimeShare.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6 import QtCore 6 | from PySide6.QtCore import Signal 7 | import requests 8 | from pandas.core.frame import DataFrame 9 | import globalVariable 10 | import datetime 11 | class DealTimeShareThread(QtCore.QThread): 12 | # 通过类成员对象定义信号对象 13 | _signal = Signal() 14 | 15 | def __init__(self,parent): 16 | super(DealTimeShareThread, self).__init__() 17 | self.parent=parent 18 | self.isTrue=True 19 | 20 | def deal_time_share_chart(self): 21 | code=self.parent.stock_code 22 | if not code[0:3].isdigit() and code[0:2]!='sh': 23 | return 24 | if code[0:4]=='100.' or code[0:4]=='103.' or code[0:4]=='104.': 25 | self.isTrue=False 26 | (self.parent.pre_close,time_share_list)=self.parent.worldIndex.get_index_time_share_chart(code) 27 | elif code[0:4]=='105.' or code[0:4]=='106.' or code[0:4]=='107.': 28 | self.isTrue=False 29 | (self.parent.pre_close,time_share_list)=self.parent.worldIndex.get_us_hk_time_share_chart(code) 30 | elif len(code)==5: 31 | code='116.'+code 32 | self.isTrue=False 33 | (self.parent.pre_close,time_share_list)=self.parent.worldIndex.get_us_hk_time_share_chart(code) 34 | else: 35 | self.isTrue=True 36 | if code[0]=='3' or code[0]=='0' or code[0]=='8' or code[0]=='4': 37 | num=0 38 | else: 39 | num=1 40 | if code[0]=='s' and code[2]=='.' and code[3].isdigit(): 41 | code=code[3:9] 42 | (self.parent.pre_close,time_share_list)=self.parent.worldIndex.get_time_share_chart_data5(num,code) 43 | if len(time_share_list)==0: 44 | return 45 | pre_close=self.parent.pre_close 46 | 47 | if self.parent.whichDay>0 and self.parent.whichDay<5: 48 | self.parent.pre_close=self.parent.data.data.loc[len(self.parent.data.data)-self.parent.whichDay-1,'close']-\ 49 | self.parent.data.data.loc[len(self.parent.data.data)-self.parent.whichDay-1,'pctVal'] 50 | elif self.parent.whichDay==0: 51 | self.parent.pre_close=pre_close 52 | elif self.parent.whichDay>4: 53 | return 54 | 55 | l1=0 56 | l2=len(time_share_list) 57 | if self.isTrue: 58 | if self.parent.period!='101': 59 | return 60 | l1=(4-self.parent.whichDay)*241 61 | if self.parent.whichDay>0: 62 | l2=(5-self.parent.whichDay)*241 63 | self.parent.time_share_chart_data.drop(self.parent.time_share_chart_data.index, inplace=True) 64 | 65 | self.parent.high_low_point=[0]*5 66 | a=self.parent.pre_close*1.1 67 | b=self.parent.pre_close*0.9 68 | from decimal import Decimal, ROUND_HALF_UP 69 | c=Decimal(str(a)).quantize(Decimal("0.000"), rounding=ROUND_HALF_UP) 70 | d=Decimal(str(b)).quantize(Decimal("0.000"), rounding=ROUND_HALF_UP) 71 | c=Decimal(str(c)).quantize(Decimal("0.00"), rounding=ROUND_HALF_UP) 72 | d=Decimal(str(d)).quantize(Decimal("0.00"), rounding=ROUND_HALF_UP) 73 | self.parent.high_low_point[3]=round((float(c)-self.parent.pre_close)*100/self.parent.pre_close,2) 74 | self.parent.high_low_point[4]=round((float(d)-self.parent.pre_close)*100/self.parent.pre_close,2) 75 | for i in range(l1,l2): 76 | time_share_list[i]=time_share_list[i].split(',',8) 77 | 78 | pd_len=len(self.parent.time_share_chart_data) 79 | self.parent.time_share_chart_data.loc[pd_len,'Time']=time_share_list[i][0] 80 | price=round((float(time_share_list[i][2])-self.parent.pre_close)*100/self.parent.pre_close,2) 81 | price_high=round((float(time_share_list[i][3])-self.parent.pre_close)*100/self.parent.pre_close,2) 82 | price_low=round((float(time_share_list[i][4])-self.parent.pre_close)*100/self.parent.pre_close,2) 83 | ave_price=round((float(time_share_list[i][7])-self.parent.pre_close)*100/self.parent.pre_close,2) 84 | vol=int(time_share_list[i][5]) 85 | if float(time_share_list[i][2])>float(time_share_list[i][1]): 86 | self.parent.time_share_chart_data.loc[pd_len,'direct']=2 87 | elif float(time_share_list[i][2])self.parent.high_low_point[0]: 92 | self.parent.high_low_point[0]=price_high 93 | if price_lowself.parent.high_low_point[2]: 96 | self.parent.high_low_point[2]=vol 97 | self.parent.time_share_chart_data.loc[pd_len,'vol']=vol 98 | self.parent.time_share_chart_data.loc[pd_len,'price']=price 99 | self.parent.time_share_chart_data.loc[pd_len,'ave_price']=ave_price 100 | 101 | def get_earning_and_pe_static(self): 102 | headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 103 | code=self.parent.stock_code 104 | stock_code='' 105 | if globalVariable.marketNum==1 or globalVariable.marketNum==3: 106 | if code[0:1]=='s' or code[0:3]=='399': 107 | return 108 | if code[0] == '6': 109 | stock_code = 'SH'+code 110 | elif code[0] in ['4','8']: 111 | stock_code = 'BJ'+code 112 | elif code[0] in ['0','3']: 113 | stock_code = 'SZ'+code 114 | 115 | url='https://emweb.securities.eastmoney.com/PC_HSF10/NewFinanceAnalysis/ZYZBAjaxNew?type=0&code={}'.format(stock_code) 116 | d=DataFrame(requests.get(url,headers=headers,timeout=0.5).json()['data']).T 117 | l=d.loc['REPORT_DATE_NAME',0] 118 | list={'一季度':1,'中报':2,'三季报':3,'年报':4} 119 | A={1:'一',2:'二',3:'三',4:'四',5:'五'} 120 | a=list[l[4:len(l)]] 121 | 122 | self.parent.baseInformation.base_info['self.earnings'].setText(f"收益({A[a]})") 123 | self.parent.baseInformation.base_info['self.earnings_data'].setText(str(d.loc['EPSJB',0])) 124 | self.parent.baseInformation.base_info['self.pe_static_data'].setText(str(round(self.parent.now_close/d.loc['EPSJB',a%4],2))) 125 | 126 | def __del__(self): 127 | self.wait() 128 | 129 | def run(self): 130 | try: 131 | self.deal_time_share_chart() 132 | self._signal.emit() 133 | if self.isTrue: 134 | self.get_earning_and_pe_static() 135 | except Exception as e: 136 | print('Reason:', e) 137 | 138 | -------------------------------------------------------------------------------- /threadGetCandle.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6.QtCore import Signal,QThread 6 | 7 | class GetCandle(QThread): 8 | # 通过类成员对象定义信号对象 9 | _signal = Signal() 10 | 11 | def __init__(self,parent): 12 | super(GetCandle, self).__init__() 13 | self.parent=parent 14 | 15 | def __del__(self): 16 | self.wait() 17 | 18 | def run(self): 19 | code=self.parent.stock_code 20 | if self.parent.ui.us_market.isChecked()==False and self.parent.ui.hk_market.isChecked()==False: 21 | self.parent.data.login_init(code,self.parent.period,self.parent.adjustflag) 22 | elif self.parent.ui.us_market.isChecked()==True: 23 | self.parent.data.get_us_data_from_east(code,self.parent.period,self.parent.adjustflag) 24 | elif self.parent.ui.hk_market.isChecked()==True: 25 | if code[0:3]=='sh.' or code[0:3]=='399': 26 | self.parent.data.login_init(code,self.parent.period,self.parent.adjustflag) 27 | else: 28 | self.parent.data.get_hk_data_from_east(code,self.parent.period,self.parent.adjustflag) 29 | self._signal.emit() 30 | -------------------------------------------------------------------------------- /threadIndex.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6.QtCore import Signal,QThread 6 | import globalVariable 7 | import stockInformation 8 | 9 | class IndexThread(QThread): 10 | # 通过类成员对象定义信号对象 11 | _signal = Signal() 12 | _finishSignal=Signal() 13 | 14 | def __init__(self,parent): 15 | super(IndexThread, self).__init__() 16 | self.parent=parent 17 | self.isTrue=False 18 | self.num=0 19 | 20 | def __del__(self): 21 | self.wait() 22 | 23 | def run(self): 24 | if self.parent.downloadInfoStart: 25 | stockInformation.download() 26 | self.parent.downloadInfoStart=False 27 | self._finishSignal.emit() 28 | try: 29 | #刷新市场对应的指数(亚洲和欧美) 30 | if globalVariable.marketNum==1 or globalVariable.marketNum==5: 31 | worldIndexData=self.parent.worldIndex.getAllIndex() 32 | self.parent.baseInformation.flashLabel(0,worldIndexData) 33 | elif globalVariable.marketNum==2: 34 | worldIndexData=self.parent.worldIndex.getAllIndex() 35 | self.parent.baseInformation.flashLabel(8,worldIndexData) 36 | 37 | self.parent.worldFuturesData=self.parent.worldIndex.get_futures_data() 38 | except Exception as e: 39 | print('Reason:', e) 40 | i=0 41 | if self.isTrue: 42 | for j in range(len(self.parent.worldFuturesData)): 43 | if self.parent.worldFuturesData.iat[j,0]=='小型道指当月连续': 44 | i=j 45 | else: 46 | for j in range(len(self.parent.worldFuturesData)): 47 | if self.parent.worldFuturesData.iat[j,0]=='A50期指当月连续': 48 | i=j 49 | self.parent.baseInformation.createVar['self.index8'].setText(self.parent.worldFuturesData.iat[i,0][0:len(self.parent.worldFuturesData.iat[i,0])-4]) 50 | if self.parent.worldFuturesData.iat[i,2]=='-' or self.parent.worldFuturesData.iat[i,2]>=0: 51 | self.parent.baseInformation.createVar['self.indexData8'].setPalette(globalVariable.pered) 52 | else: 53 | self.parent.baseInformation.createVar['self.indexData8'].setPalette(globalVariable.pegreen) 54 | self.parent.baseInformation.createVar['self.indexData8'].setText(f"{self.parent.worldFuturesData.iat[i,1]} {self.parent.worldFuturesData.iat[i,2]}%") 55 | self.isTrue=not self.isTrue 56 | 57 | if globalVariable.getValue()==1 and globalVariable.isZhMarketDay(): 58 | self.parent.stock_data=self.parent.tableView.stock_data_copy 59 | l=0 60 | if not self.parent.stock_data.empty: 61 | l=len(self.parent.stock_data) 62 | for i in range(l): 63 | if self.parent.stock_code==self.parent.stock_data.iat[i,0]: 64 | self.parent.baseInformation.flash_base_information_click(i,self.parent.stock_data,self.parent.name) 65 | return 66 | 67 | elif (globalVariable.getValue()==2 and globalVariable.isUSMarketDay()) or\ 68 | (globalVariable.getValue()==5 and globalVariable.isHKMarketDay()): 69 | self.parent.stock_data=self.parent.tableView.stock_data 70 | for i in range(len(self.parent.stock_data)): 71 | if self.parent.stock_code==self.parent.stock_data.iat[i,0]: 72 | self.parent.baseInformation.flash_base_information_click(i,self.parent.stock_data,self.parent.name) 73 | return 74 | -------------------------------------------------------------------------------- /threadNewsReport.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6.QtCore import Signal, QThread 6 | # import pyttsx3 7 | # from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput 8 | # from PySide6.QtCore import QUrl 9 | # from PySide6.QtGui import QColor,QTextCursor 10 | # import akshare as ak 11 | from memory_profiler import profile 12 | 13 | import json 14 | import requests 15 | import datetime, time 16 | # import pyttsx3 17 | import re 18 | import win32com.client as win 19 | from lxml import etree 20 | import operator 21 | 22 | class NewsReport(QThread): 23 | _signal = Signal() 24 | 25 | def __init__(self, parent): 26 | super(NewsReport, self).__init__() 27 | self.parent = parent 28 | recent_time = datetime.datetime.now() + datetime.timedelta(hours=-1) 29 | self.id = datetime.datetime.strftime(recent_time, "%Y%m%d%H%M%S000000") 30 | self.time = self.parent.eastNewsReportCurTime 31 | self.headers = { 32 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 33 | self.url = 'https://www.jin10.com/flash_newest.js?t=1667528593473' 34 | self.url2 = 'https://finance.eastmoney.com/yaowen.html' 35 | self.is_str = ['金十图示', '金十出品', '点击大图', '点击查看', '点击观看', '点击马上观看', '立即查看',\ 36 | '马上观看', '立即开通', '点击阅读全文', '马上参与', '金十期货图示', '点击报名', ' {news_data} ' 103 | self._signal.emit() 104 | news_data = re.sub(r'<(.*?)>', '', news_data) 105 | time.sleep(0.1) 106 | if self.parent.isOpenNewsReport: 107 | # self.engine.say(news_data) 108 | # self.engine.runAndWait() 109 | # self.engine.stop() 110 | self.speak.Speak(news_data) 111 | self.id = self.new_id 112 | self.parent.jinShiNewsReportCurTime = self.parent.text1 113 | self.parent.settings.setValue("General/jinShiNewsReportCurTime", self.parent.jinShiNewsReportCurTime) 114 | 115 | def is_report_east_news(self): 116 | if int(self.time) >= int(self.new_time): 117 | return 118 | news_data = self.east_data[self.east_count]['title'] 119 | self.parent.text1 = self.east_data[self.east_count]['time'] 120 | self.parent.text = f''' {news_data} ''' 121 | self._signal.emit() 122 | time.sleep(0.1) 123 | if self.parent.isOpenNewsReport: 124 | # self.engine.say(news_data) 125 | # self.engine.runAndWait() 126 | # self.engine.stop() 127 | self.speak.Speak(f"东方财经:{news_data}") 128 | self.time = self.new_time 129 | self.parent.settings.setValue("General/eastNewsReportCurTime", self.new_time) 130 | 131 | def deal_news_data(self): 132 | cur_time = str(datetime.datetime.now())[14:16] 133 | if cur_time <= '01': 134 | if self.count < 3: 135 | self.speak.Speak('休息时间,起来锻炼了!') 136 | # self.engine.say('休息时间,起来锻炼了!') 137 | self.count += 1 138 | # self.engine.runAndWait() 139 | # self.engine.stop() 140 | elif '20' <= cur_time <= '21' or '40' <= cur_time <= '41': 141 | if self.count < 3: 142 | self.speak.Speak('转转头,伸个懒腰') 143 | # self.engine.say('转转头,伸个懒腰') 144 | self.count += 1 145 | # self.engine.runAndWait() 146 | # self.engine.stop() 147 | else: 148 | self.count = 0 149 | self.get_news_data() 150 | # self.js_news_df = ak.js_news(timestamp=datetime.datetime.now()) 151 | # cur_time=str(datetime.datetime.now())[11:16] 152 | self.js_count = len(self.js_news_df) - 1 153 | self.east_count = len(self.east_data) - 1 154 | while self.js_count != -1 or self.east_count != -1: 155 | if self.js_count != -1: 156 | self.new_id = self.js_news_df[self.js_count]['id'] 157 | self.time1 = int(self.new_id[4:12]) 158 | else: 159 | self.time1 = 123456789 160 | if self.east_count != -1: 161 | a=re.findall(r'\d+',self.east_data[self.east_count]['time']) 162 | self.time2 = self.new_time =''.join(i for i in a) 163 | else: 164 | self.time2 = 123456789 165 | if self.time1 <= int(self.time2): 166 | if self.js_count != -1: 167 | self.is_report_js_news() 168 | self.js_count -= 1 169 | else: 170 | if self.east_count != -1: 171 | self.is_report_east_news() 172 | self.east_count -= 1 173 | 174 | def run(self): 175 | self.deal_news_data() 176 | self.parent.isNewsReportStop = True 177 | -------------------------------------------------------------------------------- /threadRealTime.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | from PySide6.QtCore import Signal,QThread 6 | import globalVariable 7 | import pandas as pd 8 | import requests 9 | import os 10 | 11 | class RealTimeThread(QThread): 12 | # 通过类成员对象定义信号对象 13 | _signal = Signal() 14 | 15 | def __init__(self,parent): 16 | super(RealTimeThread, self).__init__() 17 | self.parent=parent 18 | 19 | def __del__(self): 20 | self.wait() 21 | 22 | # def get_time_share_tick_data(self): 23 | # code=self.parent.stock_code 24 | # self.isIndex=False 25 | # if code[0]=='3' or code[0]=='0' or code[0]=='8' or code[0]=='4': 26 | # num=0 27 | # if code[0:3]=='399': 28 | # self.isIndex=True 29 | # else: 30 | # num=1 31 | # if code[0]=='s' and code[2]=='.' and code[3].isdigit(): 32 | # self.pre_stock_code=code 33 | # code=code[3:9] 34 | 35 | # self.isIndex=True 36 | # self.parent.tableView.get_time_share_tick(num,code) 37 | 38 | def get_time_share_tick_data(self): 39 | code=self.parent.stock_code 40 | self.data=pd.DataFrame() 41 | self.isIndex=False 42 | if code[0:4]=='100.' or code[0:4]=='103.' or code[0:4]=='104.' or not code[0:2].isdigit(): 43 | self.parent.time_share_data=self.data 44 | self._signal.emit() 45 | return 46 | 47 | if globalVariable.marketNum==1 or globalVariable.marketNum==3: 48 | if code[0:4]=='105.' or code[0:4]=='106.' or code[0:4]=='107.': 49 | return 50 | if code[0]=='3' or code[0]=='0' or code[0]=='8' or code[0]=='4': 51 | num=0 52 | if code[0:3]=='399': 53 | self.isIndex=True 54 | else: 55 | num=1 56 | if code[0]=='s' and code[2]=='.' and code[3].isdigit(): 57 | self.pre_stock_code=code 58 | code=code[3:9] 59 | self.isIndex=True 60 | (self.parent.pre_close,self.data)=self.parent.worldIndex.get_time_share_tick(num,code) 61 | elif globalVariable.marketNum==2 or globalVariable.marketNum==4: 62 | if code[0:4]=='105.' or code[0:4]=='106.' or code[0:4]=='107.': 63 | (self.parent.pre_close,self.data)=self.parent.worldIndex.get_us_time_share_tick(code) 64 | 65 | def deal_with_time_share_tick_html(self): 66 | self.parent.time_share_data = '' 67 | l = len(self.data) 68 | for i in range(0,l): 69 | ok=self.data[i].split(",", 5) 70 | if ok[4]=='2': 71 | flag='B' 72 | elif ok[4]=='1': 73 | flag='S' 74 | else: 75 | flag=' ' 76 | a=f'
{ok[0]}    ' 77 | if float(ok[1])>self.parent.pre_close: 78 | b=f'{ok[1]}    ' 79 | else: 80 | b = f'{ok[1]}    ' 81 | if not self.isIndex: 82 | if i!=l-1: 83 | self.parent.time_share_data=f"{self.parent.time_share_data}{a}{b}{ok[2]}{flag} {ok[3]}\n" 84 | else: 85 | self.parent.time_share_data = f"{self.parent.time_share_data}{a}{b}{ok[2]}{flag} {ok[3]}" 86 | if self.parent.now_close15')[a:15]}{flag} {format(ok[3], '>8')[b:8]}\n" 123 | self.parent.price[j]=float(ok[1]) 124 | self.parent.price_len[j]=len(ok[1]) 125 | self.parent.flag_direction[j]=int(ok[4]) 126 | j=j+1 127 | else: 128 | self.parent.time_share_data=f"{self.parent.time_share_data}{'{0:<12}'.format(ok[0])}{ok[1]} {format(ok[2], '>15')[a:15]}{flag} {format(ok[3], '>8')[b:8]}" 129 | self.parent.price[j]=float(ok[1]) 130 | self.parent.price_len[j]=len(ok[1]) 131 | self.parent.flag_direction[j]=int(ok[4]) 132 | self.parent.now_close=float(ok[1]) 133 | if self.parent.now_close18')[a:18]}{flag}\n" 144 | self.parent.price[j]=float(ok[1]) 145 | self.parent.price_len[j]=len(ok[1]) 146 | self.parent.flag_direction[j]=int(ok[4]) 147 | j=j+1 148 | else: 149 | self.parent.time_share_data=f"{self.parent.time_share_data}{'{0:<12}'.format(ok[0])+ok[1]} {format(ok[2], '>18')[a:18]}{flag}" 150 | self.parent.price[j]=float(ok[1]) 151 | self.parent.price_len[j]=len(ok[1]) 152 | self.parent.flag_direction[j]=int(ok[4]) 153 | self.parent.now_close=float(ok[1]) 154 | j=0 155 | #print(self.parent.time_share_data) 156 | for i in range(len(self.parent.time_share_data)): 157 | if self.parent.time_share_data[i]=='S' or self.parent.time_share_data[i]=='B': 158 | self.parent.flag_pos[j+1]=i+1 159 | if self.parent.time_share_data[i]=='\n': 160 | self.parent.line_len[j+1]=i+1 161 | j=j+1 162 | #self.parent.text_count=j+1 163 | 164 | def flash_buy_sell_and_capital(self): 165 | headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 166 | code=self.parent.stock_code 167 | 168 | if globalVariable.marketNum==1 or globalVariable.marketNum==3: 169 | if code[0:1]=='s' or code[0:3]=='399' or code[0:2]=='BK' or code[0:2]=='10' or not code[0:2].isdigit(): 170 | return 171 | num=0 172 | if code[0] == '6': 173 | num=1 174 | 175 | url='http://25.push2.eastmoney.com/api/qt/stock/get?ut=fa5fd1943c7b386f172d6893dbfba10b&fltt=2&invt=2&volt=2&fields=f116,f84,f85,f162,f31,f32,f33,f34,f35,f36,f37,f38,f39,f40,f20,f19,f18,f17,f16,f15,f14,f13,f12,f11,f531&secid={}.{}&_=1666089246963'.format(num,code) 176 | data=requests.get(url=url,headers=headers,timeout=0.3).json()['data'] 177 | for i in range(0,10,2): 178 | if data[f'f{i+31}']!='' and data[f'f{i+31}']!='-': 179 | if data[f'f{i+31}']>self.parent.pre_close: 180 | self.parent.baseInformation.buy_sell_Var[f'self.sell_price{5-i//2}'].setPalette(globalVariable.pered) 181 | elif data[f'f{i+31}']self.parent.pre_close: 191 | self.parent.baseInformation.buy_sell_Var[f'self.buy_price{5-i//2}'].setPalette(globalVariable.pered) 192 | elif data[f'f{i+11}'] self.parent.tableView.my_stock_data.loc[ 50 | i, '代码']: 51 | r = mid - 1 52 | else: 53 | l = mid + 1 54 | self.parent.tableView.my_stock_data.to_csv('list/my_stock.csv', encoding='gbk', index=False) 55 | self._signal.emit() 56 | # print(datetime.datetime.now()-t) 57 | if self.num == 6: 58 | rise = 0 59 | fall = 0 60 | for j in range(1, len(self.parent.tableView.stock_data_copy) + 1): 61 | if self.parent.tableView.stock_data_copy.loc[j, '涨跌幅'] > 0: 62 | rise += 1 63 | elif self.parent.tableView.stock_data_copy.loc[j, '涨跌幅'] < 0: 64 | fall += 1 65 | self.parent.baseInformation.base_info['self.rise_data'].setText(str(int(rise))) 66 | self.parent.baseInformation.base_info['self.fall_data'].setText(str(int(fall))) 67 | self.num = 0 68 | self.num += 1 69 | 70 | if globalVariable.isZhMarketDay() and str(t)[11:16] >= '09:30': 71 | if self.isFirst: 72 | self.isFirst = False 73 | d = pd.read_csv(r'./list/rising_speed.csv', encoding='gbk') 74 | for i in d['代码']: 75 | self.code.append(i) 76 | for n, code_tuple in enumerate(zip(self.parent.tableView.rising_speed_data['代码'], 77 | self.parent.tableView.rising_speed_data['涨速'])): 78 | speed = int(code_tuple[1]) 79 | code = int(code_tuple[0]) 80 | if speed >= 5: 81 | if code not in self.code: 82 | dd = pd.DataFrame(columns=self.order) 83 | dd.loc[1] = self.parent.tableView.rising_speed_data.loc[n + 1] 84 | dd.to_csv(r'./list/rising_speed.csv', encoding='gbk', mode='a', index=False, 85 | header=False) 86 | self.code.append(code) 87 | elif speed >= 3: 88 | if code not in self.code: 89 | dd = pd.DataFrame(columns=self.order) 90 | dd.loc[1] = self.parent.tableView.rising_speed_data.loc[n + 1] 91 | dd.to_csv(r'./list/rising_speed.csv', encoding='gbk', mode='a', index=False, 92 | header=False) 93 | self.code.append(code) 94 | elif globalVariable.getValue() == 2: 95 | if self.parent.isUsZhStock: 96 | fs = 'b:mk0201' 97 | else: 98 | fs = 'm:105,m:106,m:107' 99 | self.parent.tableView.get_us_market(fs) 100 | self.parent.tableView.init_ui() 101 | self._signal.emit() 102 | elif globalVariable.getValue() == 5: 103 | self.parent.tableView.get_hk_market() 104 | self.parent.tableView.init_ui() 105 | self._signal.emit() 106 | 107 | elif globalVariable.getValue() == 4: 108 | if globalVariable.subCount == 0: 109 | self.parent.tableView.getTbnormalFluctuation() 110 | elif globalVariable.subCount == 1: 111 | self.parent.tableView.getRoyalFlushPlateFundFlow(self.parent.period_text.currentText()) 112 | elif globalVariable.subCount == 2: 113 | self.parent.tableView.get_stock_hot_rank_em() 114 | elif globalVariable.subCount == 3: 115 | self.parent.tableView.stock_yesterday_pool_strong_em(self.parent.dateEdit.dateTime()) 116 | elif globalVariable.subCount == 4: 117 | if self.parent.period_text.currentIndex() == 0: 118 | self.parent.tableView.getTodayEastPlateFundFlow() 119 | elif self.parent.period_text.currentIndex() == 2: 120 | self.parent.tableView.getFiveEastPlateFundFlow() 121 | elif self.parent.period_text.currentIndex() == 3: 122 | self.parent.tableView.getTenEastPlateFundFlow() 123 | else: 124 | self._signalErr.emit() 125 | return 126 | 127 | elif globalVariable.subCount == 5: 128 | self.parent.tableView.get_high_low_statistics() 129 | elif globalVariable.subCount == 6: 130 | days = {'今日': '1', '3日': '3', '5日': '5', '10日': '10', '月': 'M', '季': 'Q', '年': 'Y'} 131 | # self.parent.tableView.north_plate_flows(self.parent.north_box.currentText()) 132 | self.parent.tableView.north_plate_flows1(days[self.parent.north_box.currentText()]) 133 | elif globalVariable.subCount == 7: 134 | self.parent.tableView.business_department_rank(self.parent.business_department_text.currentIndex() + 1) 135 | elif globalVariable.subCount == 8: 136 | self.parent.tableView.fund_open_fund_rank() 137 | elif globalVariable.subCount == 9: 138 | nums = {str(globalVariable.curRecentMarketDay().date()): 1, '近3日': 3, '近5日': 5, '近10日': 10, 139 | '近30日': 30} 140 | pages = {str(globalVariable.curRecentMarketDay().date()): 1, '近3日': 1, '近5日': 1, '近10日': 2, 141 | '近30日': 4} 142 | self.parent.tableView.trade_detail(nums[self.parent.tradedetail_text.currentText()], \ 143 | pages[self.parent.tradedetail_text.currentText()]) 144 | self._signal.emit() 145 | 146 | # elif globalVariable.getValue()==3: 147 | # code=self.parent.stock_code 148 | # if self.parent.ui.us_market.isChecked()==False and self.parent.ui.hk_market.isChecked()==False: 149 | # self.parent.data.login_init(code,self.parent.period,self.parent.adjustflag) 150 | # elif self.parent.ui.us_market.isChecked()==True: 151 | # self.parent.data.get_us_data_from_east(code,self.parent.period,self.parent.adjustflag) 152 | # elif self.parent.ui.hk_market.isChecked()==True: 153 | # if code[0:3]=='sh.' or code[0:3]=='399': 154 | # self.parent.data.login_init(code,self.parent.period,self.parent.adjustflag) 155 | # else: 156 | # self.parent.data.get_hk_data_from_east(code,self.parent.period,self.parent.adjustflag) 157 | # self._signal_draw.emit() 158 | -------------------------------------------------------------------------------- /ui_form.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'form.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 6.4.0 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, 12 | QMetaObject, QObject, QPoint, QRect, 13 | QSize, QTime, QUrl, Qt) 14 | from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, 15 | QCursor, QFont, QFontDatabase, QGradient, 16 | QIcon, QImage, QKeySequence, QLinearGradient, 17 | QPainter, QPalette, QPixmap, QRadialGradient, 18 | QTransform) 19 | from PySide6.QtWidgets import (QApplication, QFrame, QMainWindow, QMenu, 20 | QMenuBar, QSizePolicy, QStatusBar, QWidget) 21 | 22 | class Ui_MainWindow(object): 23 | def setupUi(self, MainWindow): 24 | if not MainWindow.objectName(): 25 | MainWindow.setObjectName(u"MainWindow") 26 | MainWindow.setEnabled(True) 27 | MainWindow.resize(1920, 1080) 28 | sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) 29 | sizePolicy.setHorizontalStretch(0) 30 | sizePolicy.setVerticalStretch(0) 31 | sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) 32 | MainWindow.setSizePolicy(sizePolicy) 33 | font = QFont() 34 | font.setBold(False) 35 | MainWindow.setFont(font) 36 | icon = QIcon() 37 | icon.addFile(u"logo.ico", QSize(), QIcon.Normal, QIcon.Off) 38 | MainWindow.setWindowIcon(icon) 39 | self.download_d = QAction(MainWindow) 40 | self.download_d.setObjectName(u"download_d") 41 | self.download_d.setEnabled(False) 42 | self.exit = QAction(MainWindow) 43 | self.exit.setObjectName(u"exit") 44 | self.download_info = QAction(MainWindow) 45 | self.download_info.setObjectName(u"download_info") 46 | self.us_market = QAction(MainWindow) 47 | self.us_market.setObjectName(u"us_market") 48 | self.us_market.setCheckable(True) 49 | self.us_market.setChecked(False) 50 | self.us_market.setEnabled(True) 51 | self.financial_flows = QAction(MainWindow) 52 | self.financial_flows.setObjectName(u"financial_flows") 53 | self.financial_flows.setCheckable(False) 54 | self.zh_market = QAction(MainWindow) 55 | self.zh_market.setObjectName(u"zh_market") 56 | self.zh_market.setCheckable(True) 57 | self.zh_market.setChecked(True) 58 | self.hk_market = QAction(MainWindow) 59 | self.hk_market.setObjectName(u"hk_market") 60 | self.hk_market.setCheckable(True) 61 | self.actF10 = QAction(MainWindow) 62 | self.actF10.setObjectName(u"actF10") 63 | self.actF3 = QAction(MainWindow) 64 | self.actF3.setObjectName(u"actF3") 65 | self.newsReport = QAction(MainWindow) 66 | self.newsReport.setObjectName(u"newsReport") 67 | self.newsReport.setCheckable(True) 68 | self.newsReport.setChecked(False) 69 | self.pick_stocks = QAction(MainWindow) 70 | self.pick_stocks.setObjectName(u"pick_stocks") 71 | self.us_zh_stock = QAction(MainWindow) 72 | self.us_zh_stock.setObjectName(u"us_zh_stock") 73 | self.us_zh_stock.setCheckable(True) 74 | self.centralwidget = QWidget(MainWindow) 75 | self.centralwidget.setObjectName(u"centralwidget") 76 | self.frame = QFrame(self.centralwidget) 77 | self.frame.setObjectName(u"frame") 78 | self.frame.setGeometry(QRect(-1, 0, 1920, 1030)) 79 | font1 = QFont() 80 | font1.setFamilies([u"Arial"]) 81 | font1.setBold(False) 82 | self.frame.setFont(font1) 83 | self.frame.setFrameShape(QFrame.StyledPanel) 84 | self.frame.setFrameShadow(QFrame.Raised) 85 | MainWindow.setCentralWidget(self.centralwidget) 86 | self.menubar = QMenuBar(MainWindow) 87 | self.menubar.setObjectName(u"menubar") 88 | self.menubar.setGeometry(QRect(0, 0, 1920, 25)) 89 | self.menu = QMenu(self.menubar) 90 | self.menu.setObjectName(u"menu") 91 | self.menu_2 = QMenu(self.menubar) 92 | self.menu_2.setObjectName(u"menu_2") 93 | self.menu_3 = QMenu(self.menubar) 94 | self.menu_3.setObjectName(u"menu_3") 95 | self.menu_4 = QMenu(self.menubar) 96 | self.menu_4.setObjectName(u"menu_4") 97 | MainWindow.setMenuBar(self.menubar) 98 | self.statusbar = QStatusBar(MainWindow) 99 | self.statusbar.setObjectName(u"statusbar") 100 | self.statusbar.setFont(font1) 101 | MainWindow.setStatusBar(self.statusbar) 102 | 103 | self.menubar.addAction(self.menu.menuAction()) 104 | self.menubar.addAction(self.menu_2.menuAction()) 105 | self.menubar.addAction(self.menu_3.menuAction()) 106 | self.menubar.addAction(self.menu_4.menuAction()) 107 | self.menu.addAction(self.download_d) 108 | self.menu.addAction(self.download_info) 109 | self.menu.addAction(self.newsReport) 110 | self.menu.addAction(self.exit) 111 | self.menu_2.addAction(self.zh_market) 112 | self.menu_2.addAction(self.us_market) 113 | self.menu_2.addAction(self.hk_market) 114 | self.menu_2.addAction(self.us_zh_stock) 115 | self.menu_3.addAction(self.financial_flows) 116 | self.menu_3.addAction(self.pick_stocks) 117 | self.menu_4.addAction(self.actF10) 118 | self.menu_4.addAction(self.actF3) 119 | 120 | self.retranslateUi(MainWindow) 121 | self.exit.triggered.connect(MainWindow.close) 122 | 123 | QMetaObject.connectSlotsByName(MainWindow) 124 | # setupUi 125 | 126 | def retranslateUi(self, MainWindow): 127 | MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) 128 | self.download_d.setText(QCoreApplication.translate("MainWindow", u"\u4e0b\u8f7dk\u7ebf\u6570\u636e", None)) 129 | self.exit.setText(QCoreApplication.translate("MainWindow", u"\u9000\u51fa", None)) 130 | self.download_info.setText(QCoreApplication.translate("MainWindow", u"\u4e0b\u8f7d\u80a1\u7968\u4fe1\u606f", None)) 131 | self.us_market.setText(QCoreApplication.translate("MainWindow", u"\u7f8e\u80a1", None)) 132 | self.financial_flows.setText(QCoreApplication.translate("MainWindow", u"\u8d44\u91d1\u6d41", None)) 133 | self.zh_market.setText(QCoreApplication.translate("MainWindow", u"A\u80a1", None)) 134 | self.hk_market.setText(QCoreApplication.translate("MainWindow", u"\u6e2f\u80a1", None)) 135 | self.actF10.setText(QCoreApplication.translate("MainWindow", u"F10---\u8d22\u52a1\u5206\u6790 \u7ecf\u8425\u5206\u6790", None)) 136 | self.actF3.setText(QCoreApplication.translate("MainWindow", u"F3---\u70ed\u5ea6\u5173\u952e\u8bcd", None)) 137 | self.newsReport.setText(QCoreApplication.translate("MainWindow", u"\u5173\u95ed\u8bed\u97f3\u64ad\u62a5", None)) 138 | self.pick_stocks.setText(QCoreApplication.translate("MainWindow", u"\u516c\u5f0f\u9009\u80a1", None)) 139 | self.us_zh_stock.setText(QCoreApplication.translate("MainWindow", u"\u7f8e\u4e2d\u6982\u80a1", None)) 140 | self.menu.setTitle(QCoreApplication.translate("MainWindow", u"\u5f00\u59cb", None)) 141 | self.menu_2.setTitle(QCoreApplication.translate("MainWindow", u"\u5176\u5b83\u5e02\u573a", None)) 142 | self.menu_3.setTitle(QCoreApplication.translate("MainWindow", u"\u5206\u6790", None)) 143 | self.menu_4.setTitle(QCoreApplication.translate("MainWindow", u"\u5e2e\u52a9", None)) 144 | # retranslateUi 145 | 146 | -------------------------------------------------------------------------------- /worldIndex.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | 3 | # if __name__ == "__main__": 4 | # pass 5 | import requests 6 | import pandas as pd 7 | from memory_profiler import profile 8 | class WorldIndex(): 9 | def __init__(self): 10 | super().__init__() 11 | self.data=pd.DataFrame() 12 | self.headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'} 13 | 14 | def getAllIndex(self): 15 | url='http://push2.eastmoney.com/api/qt/ulist.np/get?fid=f3&pi=0&pz=40&po=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&fields=f14,f12,f2,f3&np=1&secids=1.000001%2C0.399001%2C0.399006%2C100.HSI%2c100.TWII%2C100.N225%2C100.KS11%2C100.SENSEX%2C100.DJIA%2C100.SPX%2C100.NDX%2C100.FTSE%2C100.GDAXI%2C100.FCHI%2C100.RTS%2C100.AS51%2C1.000688&_=1662857186403' 16 | data=pd.DataFrame(requests.get(url,headers=self.headers,timeout=3).json()['data']['diff']) 17 | data['f2']=data['f2'].astype(float) 18 | for i in range(len(data)): 19 | if not data.loc[i,'f12'].isdigit(): 20 | data.loc[i,'f12']='100.'+data.loc[i,'f12'] 21 | if data.loc[i,'f12'][0:1]=='0': 22 | data.loc[i,'f12']='sh.'+data.loc[i,'f12'] 23 | return data 24 | 25 | def get_futures_data(self): 26 | url='http://futsseapi.eastmoney.com/list/block?orderBy=name&sort=desc&pageSize=20&pageIndex=0&blockName=financial&_=1666243575249' 27 | df=pd.DataFrame(requests.get(url,headers=self.headers,timeout=3).json()['list']) 28 | df=df[['name','p','zdf']] 29 | # df.sort_values(by=df.columns[0],ascending=False,kind="mergesort",inplace=True) 30 | # df.index = pd.RangeIndex(start=0, stop=len(df), step=1) 31 | return df 32 | 33 | def get_time_share_tick(self,num,code): 34 | url='http://push2.eastmoney.com/api/qt/stock/details/get?fields1=f1,f2,f3,f4&fields2=f51,f52,f53,f54,f55&mpi=2000&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&pos=-0&secid={num}.{code}'.format(num=num,code=code) 35 | df =requests.get(url,headers=self.headers,timeout=0.3).json()['data'] 36 | pre_close=df['prePrice'] 37 | self.data=df['details'] 38 | return (pre_close,self.data) 39 | 40 | def get_us_time_share_tick(self,code): 41 | url ="http://push2.eastmoney.com/api/qt/stock/details/get?ut=fa5fd1943c7b386f172d6893dbfba10b&fields1=f1,f2,f3,f4&fields2=f51,f52,f53,f54,f55&secid={}&pos=-30&_=1666406840175".format(code) 42 | json_data=requests.get(url,headers=self.headers).json()['data'] 43 | preClose=json_data['prePrice'] 44 | data_list=json_data['details'] 45 | return (preClose,data_list) 46 | 47 | # def get_time_share_chart_data(self,num,code): 48 | # url='http://push2his.eastmoney.com/api/qt/stock/trends2/get?fields1=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13&fields2=f51,f52,f53,f54,f55,f56,f57,f58&ut=fa5fd1943c7b386f172d6893dbfba10b&secid={num}.{code}&ndays=1&iscr=0&iscca=0:formatted'.format(num=num,code=code) 49 | # json_data=requests.get(url,headers=self.headers).json()['data'] 50 | # preClose=json_data['preClose'] 51 | # data_list=json_data['trends'] 52 | # return (preClose,data_list) 53 | 54 | def get_time_share_chart_data5(self,num,code): 55 | url5='http://push2his.eastmoney.com/api/qt/stock/trends2/get?fields1=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13&fields2=f51,f52,f53,f54,f55,f56,f57,f58&ut=fa5fd1943c7b386f172d6893dbfba10b&secid={num}.{code}&ndays=5&iscr=0&iscca=0'.format(num=num,code=code) 56 | json_data=requests.get(url5,headers=self.headers,timeout=3).json()['data'] 57 | preClose=json_data['preClose'] 58 | data_list=json_data['trends'] 59 | return (preClose,data_list) 60 | 61 | def get_us_hk_time_share_chart(self,code): 62 | url ="http://push2his.eastmoney.com/api/qt/stock/trends2/get?fields1=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13&fields2=f51,f52,f53,f54,f55,f56,f57,f58&ut=fa5fd1943c7b386f172d6893dbfba10b&iscr=0&ndays=1&secid={}&_=1666401553893".format(code) 63 | json_data=requests.get(url,headers=self.headers).json()['data'] 64 | preClose=json_data['preClose'] 65 | data_list=json_data['trends'] 66 | return (preClose,data_list) 67 | 68 | def get_index_time_share_chart(self,code): 69 | url='http://push2.eastmoney.com/api/qt/stock/trends2/get?secid={}&fields1=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13&fields2=f51,f52,f53,f54,f55,f56,f57,f58&ut=e1e6871893c6386c5ff6967026016627&iscr=0&isqhquote=&cb_1665213076163_70435755'.format(code) 70 | json_data=requests.get(url,headers=self.headers).json()['data'] 71 | preClose=json_data['preClose'] 72 | data_list=json_data['trends'] 73 | return (preClose,data_list) 74 | --------------------------------------------------------------------------------