# -*- coding: utf-8 -*- #!/usr/bin/python import sys import random from PyQt4 import QtGui, QtCore,Qt class report_painter: '''繪製行情類''' def __init__(self,parent): #初始化 self.parent = parent self.paint = QtGui.QPainter() self.paint.begin(self.parent) #設置抗鋸齒 #self.paint.setRenderHint(QtGui.QPainter.Antialiasing) #度量尺對象 self.metrics = self.paint.fontMetrics() #設置字體庫 self.fonts = dict() self.fonts['default'] = QtGui.QFont('Serif', 9, QtGui.QFont.Light) self.fonts['yahei_14_bold']= QtGui.QFont('Serif',12,QtGui.QFont.Bold) self.fonts['yahei_14']= QtGui.QFont('Serif',12,QtGui.QFont.Light) self.setFont('default') #設置筆刷樣式庫 self.pens = dict() #紅色 1px粗 1px點 2px距 線條 self.pens['red_1px_dashline'] = QtGui.QPen( QtCore.Qt.red, 1, QtCore.Qt.DashLine) self.pens['red_1px_dashline'].setDashPattern([1,2]) #紅色 1px粗 實線條 self.pens['red'] = QtGui.QPen( QtCore.Qt.red, 1, QtCore.Qt.SolidLine) #紅色 3px粗 實線條 self.pens['red_2px'] = QtGui.QPen( QtCore.Qt.red, 2, QtCore.Qt.SolidLine) #紅色 2px粗 實線條 self.pens['red_3px'] = QtGui.QPen( QtCore.Qt.red, 3, QtCore.Qt.SolidLine) #黃色 1px粗 實線條 self.pens['yellow'] = QtGui.QPen( QtCore.Qt.yellow, 1, QtCore.Qt.SolidLine) #白色 1px粗 實線條 self.pens['white'] = QtGui.QPen( QtCore.Qt.white , 1, QtCore.Qt.SolidLine) #灰色 1px粗 實線條 self.pens['gray'] = QtGui.QPen( QtCore.Qt.gray, 1, QtCore.Qt.SolidLine) #綠色 1px粗 實線條 self.pens['green'] = QtGui.QPen( QtCore.Qt.green, 1, QtCore.Qt.SolidLine) #綠色 3px粗 實線條 self.pens['green_2px'] = QtGui.QPen( QtCore.Qt.green, 2, QtCore.Qt.SolidLine) #亮藍 1px粗 1px點 2px距 線條 self.pens['cyan_1px_dashline'] = QtGui.QPen( QtCore.Qt.cyan, 1, QtCore.Qt.DashLine) self.pens['cyan_1px_dashline'].setDashPattern([3,2]) #得到窗口的長和寬 size = self.parent.size() self.w = size.width() self.h = size.height() #設置grid的上下左右補丁邊距 self.grid_padding_left = 45 #左側補丁邊距 self.grid_padding_right = 245 #右側補丁邊距 self.grid_padding_top = 25 #頂部補丁邊距 self.grid_padding_bottom = 17 #底部補丁邊距 #開始繪製 self.start_paint() self.paint.end() #結束 '''繪製流程步驟''' def start_paint(self): self.PriceGridPaint() self.rightGridPaint() self.timelinePaint() self.topInfoPaint() self.rulerPaint() self.VolumeGridPaint() self.volumePaint() self.pricePaint() self.xyPaint() '''設置使用的字體''' def setFont(self,code='default'): self.paint.setFont(self.fonts[code]) '''設置使用的筆刷''' def setPen(self,code='default'): self.paint.setPen(self.pens[code]) '''繪製股價走勢表格''' def PriceGridPaint(self): self.setPen('red') self.paint.setBrush(QtCore.Qt.NoBrush) sum_width = self.grid_padding_left+self.grid_padding_right sum_height = self.grid_padding_top+self.grid_padding_bottom grid_height = self.h-sum_height #畫邊框 self.paint.drawRect(self.grid_padding_left,self.grid_padding_top, self.w-sum_width,self.h-sum_height) #成交量和走勢的分界線 self.paint.drawLine(self.grid_padding_left,grid_height*0.7+self.grid_padding_top, self.w-self.grid_padding_right,grid_height*0.7+self.grid_padding_top) #股票昨收中間線 self.paint.drawLine(self.grid_padding_left+1, grid_height*0.35+self.grid_padding_top, self.w-self.grid_padding_right ,grid_height*0.35+self.grid_padding_top) #其餘線條 self.paint.drawLine(0,self.h-self.grid_padding_bottom,self.w-self.grid_padding_right+44,self.h-self.grid_padding_bottom) self.paint.drawLine(0,self.h-self.grid_padding_bottom+16,self.w,self.h-self.grid_padding_bottom+16) self.paint.drawLine(self.w-self.grid_padding_right,0, self.w-self.grid_padding_right,self.h-self.grid_padding_bottom+16) self.paint.drawLine(self.w-self.grid_padding_right+44,0, self.w-self.grid_padding_right+44,self.h-self.grid_padding_bottom+16) self.setPen('yellow') self.paint.drawText(self.w-self.grid_padding_right+5,self.h-self.grid_padding_bottom-4,str('成交量')) self.setPen('white') #右下角文字 self.paint.drawText(self.w-self.grid_padding_right+12,self.h-self.grid_padding_bottom+12,str('實時')) '''繪製成交量走勢表格''' def VolumeGridPaint(self): sum_width = self.grid_padding_left + self.grid_padding_right sum_height = self.grid_padding_top + self.grid_padding_bottom grid_height = self.h-sum_height max_volume = self.parent.stk_data['max_vol'] px_h_radio = max_volume/(grid_height*0.3) self.setPen('red_1px_dashline') grid_num = 6 x = grid_num cnt = grid_height*0.3/grid_num for i in range(0,grid_num): self.setPen('red_1px_dashline') #計算座標 y1 = self.grid_padding_top+(grid_height*0.7)+i*cnt x1 = self.grid_padding_left x2 = self.grid_padding_left+self.w-sum_width self.paint.drawLine(x1,y1,x2,y1) #畫價位虛線 vol_int = int(cnt*x*px_h_radio) vol_str = str(vol_int) fw = self.metrics.width(vol_str) #得到文字寬度 fh = self.metrics.height()/2 #得到文字高度 self.setPen('yellow') self.paint.drawText(x2+40-fw,y1+fh,vol_str) #寫入文字 self.setPen('white') self.paint.drawText(x1-2-self.metrics.width(str(x)),y1+fh,str(x)) #寫入文字 x-=1 '''繪製左側信息欄和盤口等內容''' def rightGridPaint(self): self.setPen('red') #繪製信息內容之間的分割線 _h = 0 _x = self.w-self.grid_padding_right+44 self.paint.drawLine(self.w-1,0,self.w-1,self.h-self.grid_padding_bottom+16) self.paint.drawLine(0,0,0,self.h-self.grid_padding_bottom+16) self.paint.drawLine(0,_h,self.w,_h) _h+=23 self.paint.drawLine(_x,_h,self.w,_h) _h+=24 self.paint.drawLine(_x,_h,self.w,_h) _h+=93 self.paint.drawLine(_x,_h,self.w,_h) _h+=20 self.paint.drawLine(_x,_h,self.w,_h) _h+=93 self.paint.drawLine(_x,_h,self.w,_h) _h+=123 self.paint.drawLine(_x,_h,self.w,_h) _h+=23 self.paint.drawLine(_x,_h,self.w,_h) #股票名稱和代碼 self.setFont('yahei_14_bold') self.setPen('yellow') name_str = str('%s %s'%(self.parent.stk_info['code'],self.parent.stk_info['name'])) self.paint.drawText(_x+35,18,name_str) #委比和委差 self.setFont('yahei_14') zx_str = str('最新') self.paint.drawText(_x+3 ,156,zx_str) self.setPen('gray') wb_str = str('委比') wc_str = str('委差') xs_str = str('現手') self.paint.drawText(_x+3 ,39,wb_str) self.paint.drawText(_x+100,39,wc_str) self.paint.drawText(_x+100,156,xs_str) fh = self.metrics.height() left_field_list = ['漲跌','漲幅','振幅','總手','總額','換手','分筆'] i = 1 for field in left_field_list: field_str = str(field) self.paint.drawText(_x+3,253+(i*17),field_str) i+=1 right_field_list = ['均價','前收','今開','最高','最低','量比','均量'] i = 1 for field in right_field_list: field_str = str(field) self.paint.drawText(_x+100,253+(i*17),field_str) i+=1 wp_str = str('外盤') np_str = str('內盤') self.paint.drawText(_x+3,395,wp_str) self.paint.drawText(_x+100,395,np_str) #賣①②③④⑤ i = 0 sell_queue = ['賣⑤','賣④','賣③','賣②','賣①'] for sell in sell_queue: sell_str = str(sell) self.paint.drawText(_x+3,62+(i*18),sell_str) i+=1 #買①②③④⑤ buy_queue = ['買①','買②','買③','買④','買⑤'] for buy in buy_queue: buy_str = str(buy) self.paint.drawText(_x+3,87+(i*18),buy_str) i+=1 self.setPen('red_2px') self.paint.drawLine(_x+1,377,_x+99,377) self.paint.drawLine(_x+1,46,_x+65,46) self.setPen('green_2px') self.paint.drawLine(_x+102,377,_x+199,377) self.paint.drawLine(_x+67,46,_x+199,46) self.setFont('default') '''繪製左右側的價格刻度''' def rulerPaint(self): sum_width = self.grid_padding_left+self.grid_padding_right sum_height = self.grid_padding_top+self.grid_padding_bottom grid_height = self.h-sum_height high = self.parent.stk_data['high'] low = self.parent.stk_data['low'] lastclose = self.parent.stk_data['lastclose'] top = high-lastclose bottom = lastclose-low if top>bottom: padding = top else: padding = bottom limit_top = lastclose+padding limit_low = lastclose-padding px_h_radio = (grid_height*0.7)/((limit_top-limit_low)*100) self.setPen('red_1px_dashline') grid_num = 16 cnt = grid_height*0.7/grid_num for i in range(0,grid_num): self.setPen('red_1px_dashline') #計算座標 y1 = self.grid_padding_top+i*cnt x1 = self.grid_padding_left x2 = self.grid_padding_left+self.w-sum_width self.paint.drawLine(x1,y1,x2,y1) #畫價位虛線 price_float = (limit_top - ((i*cnt)/px_h_radio/100)) #計算價格 price = '%4.2f'%(price_float) #格式化價格成str fw = self.metrics.width(price) #得到文字寬度 fh = self.metrics.height()/2 #得到文字高度 radio_float = (price_float/lastclose-1)*100 #計算波動百分比 radio_str = "%2.2f%%"%(radio_float) #格式化百分比成str r_fw = self.metrics.width(radio_str) r_fh = self.metrics.height()/2 #判斷文字使用的顏色 if price_float == lastclose: self.setPen('white') if price_float < lastclose: self.setPen('green') self.paint.drawText(x1-fw-2,y1+fh,price) #寫入文字 self.paint.drawText(x2+40-r_fw,y1+r_fh,radio_str) #寫入文字 '''繪製x,y準星''' def xyPaint(self): if self.parent.m_x >= self.grid_padding_left and self.parent.m_x<=self.w-self.grid_padding_right and self.parent.m_y>=self.grid_padding_top and self.parent.m_y<=self.h-self.grid_padding_bottom: self.setPen('gray') x1 = self.grid_padding_left x2 = self.w-self.grid_padding_right y1 = self.grid_padding_top y2 = self.h-self.grid_padding_bottom self.paint.drawLine(x1+1,self.parent.m_y,x2-1,self.parent.m_y) self.paint.drawLine(self.parent.m_x,y1+1,self.parent.m_x,y2-1) '''繪製時間軸刻度''' def timelinePaint(self): fw = self.metrics.width('00:00') #計算文字的寬度 sum_width = self.grid_padding_left+self.grid_padding_right sum_height = self.grid_padding_top+self.grid_padding_bottom grid_width = self.w-sum_width-2 y1 = self.grid_padding_top y2 = y1+(self.h-sum_height) #時間軸中線 self.setPen('red') x_pos = grid_width/2+self.grid_padding_left self.paint.drawLine(x_pos,y1,x_pos,y2) self.paint.drawText(x_pos-fw/2,y2+12,str('13:00')) #時間軸09點30分 x_pos = self.grid_padding_left self.paint.drawText(x_pos,y2+12,str('09:30')) #時間軸10點30分 x_pos = grid_width*0.25+self.grid_padding_left self.paint.drawLine(x_pos,y1,x_pos,y2) self.paint.drawText(x_pos-fw/2,y2+12,str('10:30')) #時間軸14點00分 x_pos = grid_width*0.75+self.grid_padding_left self.paint.drawLine(x_pos,y1,x_pos,y2) self.paint.drawText(x_pos-fw/2,y2+12,str('14:00')) #時間軸15點00分 x_pos = grid_width+self.grid_padding_left self.paint.drawText(x_pos-fw,y2+12,str('15:00')) #時間虛線 by 30min self.setPen('red_1px_dashline') x_pos_array = [0.125,0.375,0.625,0.875] for i in x_pos_array: x_pos = grid_width*i+self.grid_padding_left self.paint.drawLine(x_pos,y1,x_pos,y2) '''繪製表格上方的股票信息''' def topInfoPaint(self): self.setPen('yellow') self.paint.drawText(4+self.grid_padding_left,self.grid_padding_top-4 ,str(self.parent.stk_info['name'])) #股票名稱 self.paint.drawText(4+self.grid_padding_left+120,self.grid_padding_top-4 ,str('均價線:')) #均價線 lastclose = self.parent.stk_data['lastclose'] close = self.parent.stk_data['close'] mma = self.parent.stk_data['list']['mma'][-1] if lastclose>close: self.setPen('green') str_1 = '%.2f -%.2f'%(close,lastclose-close) if lastclose==close: self.setPen('white') str_1 = '%.2f +%.2f'%(close,0.00) if lastclose<close: self.setPen('red') str_1 = '%.2f +%.2f'%(close,close-lastclose) if mma>close: self.setPen('green') if mma==close: self.setPen('white') if mma<close: self.setPen('red') self.paint.drawText(4+self.grid_padding_left+55,self.grid_padding_top-4,str(str_1)) self.paint.drawText(4+self.grid_padding_left+165,self.grid_padding_top-4,str('%.2f'%mma)) #均價 #漲停價 self.setPen('red') self.paint.drawText(4+self.grid_padding_left+200,self.grid_padding_top-4,str('漲停價:%.2f'%(lastclose*1.1))) #均價 #跌停價 self.setPen('green') self.paint.drawText(4+self.grid_padding_left+280,self.grid_padding_top-4,str('跌停價:%.2f'%(lastclose*0.9))) #均價 '''繪製股價走勢''' def pricePaint(self): sum_width = self.grid_padding_left+self.grid_padding_right sum_height = self.grid_padding_top+self.grid_padding_bottom grid_height = self.h-sum_height-2 high = self.parent.stk_data['high'] low = self.parent.stk_data['low'] lastclose = self.parent.stk_data['lastclose'] top = high-lastclose bottom = lastclose-low if top>bottom: padding = top else: padding = bottom limit_top = lastclose+padding limit_low = lastclose-padding h_radio = (grid_height*0.7)/((limit_top-limit_low)*100) w_radio = (self.w-sum_width-2)/240.00 w = self.grid_padding_left self.setPen('white') path = QtGui.QPainterPath() path.moveTo(w,(limit_top-self.parent.stk_data['open'])*100*h_radio+self.grid_padding_top) i = 1 for price in self.parent.stk_data['list']['close']: w = i*w_radio+self.grid_padding_left y = (limit_top-price)*100*h_radio+self.grid_padding_top path.lineTo(w,y) i+=1 self.paint.drawPath(path) self.setPen('cyan_1px_dashline') self.paint.drawLine(self.grid_padding_left+1,y,w-1,y) self.setPen('yellow') path = QtGui.QPainterPath() w = self.grid_padding_left path.moveTo(w,(limit_top-self.parent.stk_data['open'])*100*h_radio+self.grid_padding_top) i = 1 for price in self.parent.stk_data['list']['mma']: w = i*w_radio+self.grid_padding_left y = (limit_top-price)*100*h_radio+self.grid_padding_top path.lineTo(w,y) i+=1 self.paint.drawPath(path) '''繪製成交量''' def volumePaint(self): sum_width = self.grid_padding_left + self.grid_padding_right sum_height = self.grid_padding_top + self.grid_padding_bottom max_volume = self.parent.stk_data['max_vol'] #最大分鐘成交量 w_radio = (self.w-sum_width-2)/240.00 h_radio = ((self.h-sum_height-2)*0.3)/max_volume y = (self.h-sum_height)+self.grid_padding_top self.setPen('yellow') for i in range(1,len(self.parent.stk_data['list']['vol'])+1): x = i*w_radio+self.grid_padding_left y2 = h_radio*self.parent.stk_data['list']['vol'][i-1] self.paint.drawLine(x,y-1,x,y-y2) class Test(QtGui.QWidget): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.setMinimumSize(640, 430) #設置窗口最小尺寸 self.setGeometry(300, 300, 960, 650) self.setWindowTitle(str('超級狙擊手[內部開發測試版]-行情實時走勢')) self.setStyleSheet("QWidget { background-color: black }") self.setWindowIcon(QtGui.QIcon('ruby.png')) self.setMouseTracking(True) self.m_x = 0 #光標x軸位置 self.m_y = 0 #光標y軸位置 self.stk_info = {} self.stk_info['name'] = '浙江東方' self.stk_info['code'] = '600120' self.stk_info['market'] = 'SH' self.stk_data = {} self.stk_data['list'] = {} #股價序列 self.stk_data['list']['time'] = [] #時間 self.stk_data['list']['open'] = [] #開盤價 self.stk_data['list']['high'] = [] #最高價 self.stk_data['list']['low'] = [] #最低價 self.stk_data['list']['close'] = [] #收盤價 self.stk_data['list']['vol'] = [] #成交量 self.stk_data['list']['amount']= [] #成交額 self.stk_data['list']['mma']= [] #分時均價 self.stk_data['list']['buy_port'] = [(0.00,0),(0.00,0),(0.00,0),(0.00,0),(0.00,0)] #買盤前五 self.stk_data['list']['sell_port'] = [(0.00,0),(0.00,0),(0.00,0),(0.00,0),(0.00,0)] #賣盤前五 #讀取數據 f = open('SH600120.txt','r') data = f.readlines() f.close() for row in data: vars = row.split(' ') self.stk_data['list']['time'].append(vars[1]) self.stk_data['list']['open'].append(float(vars[2])) self.stk_data['list']['high'].append(float(vars[3])) self.stk_data['list']['low'].append(float(vars[4])) self.stk_data['list']['close'].append(float(vars[5])) self.stk_data['list']['vol'].append(int(float(vars[6]))) self.stk_data['list']['amount'].append(int(float(vars[7]))) sum_vol = sum(self.stk_data['list']['vol']) sum_amt = sum(self.stk_data['list']['amount']) self.stk_data['list']['mma'].append(float(sum_amt)/(sum_vol*100.00)) self.stk_data['lastclose'] = 10.12 #上一個交易日收盤價 self.stk_data['open'] = self.stk_data['list']['open'][0] #開盤價 self.stk_data['high'] = max(self.stk_data['list']['high']) #最高價 self.stk_data['low'] = min(self.stk_data['list']['low']) #最低價 self.stk_data['close']= self.stk_data['list']['close'][-1] #收盤價 self.stk_data['max_vol'] = max(self.stk_data['list']['vol']) #當日最高成交量 def mouseMoveEvent(self, event): self.m_x = int(event.x()) self.m_y = int(event.y()) self.repaint() def paintEvent(self, event): report_painter(self) app = QtGui.QApplication(sys.argv) dt = Test() dt.show() app.exec_()