#-*- coding: utf-8 -*-

#Qt相关和十字光标

from qtpy.QtGui import *

from qtpy.QtCore import *

from qtpy importQtWidgets, QtGui, QtCorefrom qtpy.QtWidgets importQApplication, QWidgetfrom uiCrosshair importCrosshairimportpyqtgraph as pg#其他

importnumpy as npimportpandas as pdfrom functools importpartialfrom datetime importdatetime, timedeltafrom collections importdeque#字符串转换#---------------------------------------------------------------------------------------

try:

_fromUtf8=QtCore.QString.fromUtf8exceptAttributeError:def_fromUtf8(s):returns#########################################################################键盘鼠标功能########################################################################

classKeyWraper(QtWidgets.QWidget):"""键盘鼠标功能支持的元类"""

#初始化

#----------------------------------------------------------------------

def __init__(self, parent=None):

QtWidgets.QWidget.__init__(self, parent)#重载方法keyPressEvent(self,event),即按键按下事件方法

#----------------------------------------------------------------------

defkeyPressEvent(self, event):if event.key() ==QtCore.Qt.Key_Up:

self.onUp()elif event.key() ==QtCore.Qt.Key_Down:

self.onDown()elif event.key() ==QtCore.Qt.Key_Left:

self.onLeft()elif event.key() ==QtCore.Qt.Key_Right:

self.onRight()elif event.key() ==QtCore.Qt.Key_PageUp:

self.onPre()elif event.key() ==QtCore.Qt.Key_PageDown:

self.onNxt()#重载方法mousePressEvent(self,event),即鼠标点击事件方法

#----------------------------------------------------------------------

defmousePressEvent(self, event):if event.button() ==QtCore.Qt.RightButton:

self.onRClick(event.pos())elif event.button() ==QtCore.Qt.LeftButton:

self.onLClick(event.pos())#重载方法mouseReleaseEvent(self,event),即鼠标点击事件方法

#----------------------------------------------------------------------

defmouseReleaseEvent(self, event):if event.button() ==QtCore.Qt.RightButton:

self.onRRelease(event.pos())elif event.button() ==QtCore.Qt.LeftButton:

self.onLRelease(event.pos())

self.releaseMouse()#重载方法wheelEvent(self,event),即滚轮事件方法

#----------------------------------------------------------------------

defwheelEvent(self, event):if event.delta() >0:

self.onUp()else:

self.onDown()#重载方法dragMoveEvent(self,event),即拖动事件方法

#----------------------------------------------------------------------

defpaintEvent(self, event):

self.onPaint()#PgDown键

#----------------------------------------------------------------------

defonNxt(self):pass

#PgUp键

#----------------------------------------------------------------------

defonPre(self):pass

#向上键和滚轮向上

#----------------------------------------------------------------------

defonUp(self):pass

#向下键和滚轮向下

#----------------------------------------------------------------------

defonDown(self):pass

#向左键

#----------------------------------------------------------------------

defonLeft(self):pass

#向右键

#----------------------------------------------------------------------

defonRight(self):pass

#鼠标左单击

#----------------------------------------------------------------------

defonLClick(self, pos):pass

#鼠标右单击

#----------------------------------------------------------------------

defonRClick(self, pos):pass

#鼠标左释放

#----------------------------------------------------------------------

defonLRelease(self, pos):pass

#鼠标右释放

#----------------------------------------------------------------------

defonRRelease(self, pos):pass

#画图

#----------------------------------------------------------------------

defonPaint(self):pass

#########################################################################选择缩放功能支持########################################################################

classCustomViewBox(pg.ViewBox):#----------------------------------------------------------------------

def __init__(self, parent, *args, **kwds):

pg.ViewBox.__init__(self, *args, **kwds)

self.parent=parent#拖动放大模式

#self.setMouseMode(self.RectMode)

## 右键自适应

#----------------------------------------------------------------------

defmouseClickEvent(self, ev):if ev.button() ==QtCore.Qt.RightButton:

self.autoRange()#重载方法mousePressEvent(self,event),即鼠标点击事件方法

#----------------------------------------------------------------------

defmousePressEvent(self, event):

pg.ViewBox.mousePressEvent(self, event)#重载方法mouseDragEvent(self,event),即拖动事件方法

def mouseDragEvent(self, ev, axis=None):#if ev.start==True and ev.finish==False: ##判断拖拽事件是否结束

pos =ev.pos()

lastPos=ev.lastPos()

dif= pos -lastPos

rect=self.sceneBoundingRect()

pianyi= dif.x() * self.parent.countK * 2 /rect.width()

self.parent.index-=int(pianyi)

self.parent.index= max(self.parent.index, 60)

xMax= self.parent.index + self.parent.countK ##

xMin = self.parent.index -self.parent.countKif xMin <0:

xMin=0#self.parent.plotAll(False, xMin, xMax) #注释原因:拖动事件不需要先绘制图形界面

pg.ViewBox.mouseDragEvent(self, ev, axis)### 重载方法resizeEvent(self, ev)

defresizeEvent(self, ev):

self.linkedXChanged()

self.linkedYChanged()

self.updateAutoRange()

self.updateViewRange()

self._matrixNeedsUpdate=True

self.sigStateChanged.emit(self)

self.background.setRect(self.rect())

self.sigResized.emit(self)

self.parent.refreshHeight()#########################################################################时间序列,横坐标支持########################################################################

classMyStringAxis(pg.AxisItem):"""时间序列横坐标支持"""

#初始化

#----------------------------------------------------------------------

def __init__(self, xdict, *args, **kwargs):

pg.AxisItem.__init__(self, *args, **kwargs)

self.minVal=0

self.maxVal=0

self.xdict=xdict

self.x_values=np.asarray(xdict.keys())

self.x_strings=xdict.values()

self.setPen(color=(255, 255, 255, 255), width=0.8)

self.setStyle(tickFont=QFont("Roman times", 10, QFont.Bold), autoExpandTextSpace=True)#更新坐标映射表

#----------------------------------------------------------------------

defupdate_xdict(self, xdict):

self.xdict.update(xdict)

self.x_values=np.asarray(self.xdict.keys())

self.x_strings=self.xdict.values()#将原始横坐标转换为时间字符串,第一个坐标包含日期

#----------------------------------------------------------------------

deftickStrings(self, values, scale, spacing):

strings=[]for v invalues:

vs= v *scaleif vs inself.x_values:

vstr= self.x_strings[np.abs(self.x_values -vs).argmin()]if(isinstance(vstr, (str))):

vstr=vstrelse:

vstr= vstr.strftime('%Y-%m-%d %H:%M:%S')else:

vstr= ""strings.append(vstr)returnstrings#########################################################################K线图形对象########################################################################

classCandlestickItem(pg.GraphicsObject):"""K线图形对象"""

#初始化

#----------------------------------------------------------------------

def __init__(self, data):"""初始化"""pg.GraphicsObject.__init__(self)#数据格式: [ (time, open, close, low, high),...]

self.data =data#只重画部分图形,大大提高界面更新速度

self.setFlag(self.ItemUsesExtendedStyleOption)#画笔和画刷

w = 0.4self.offset=0

self.low=0

self.high= 1self.picture=QtGui.QPicture()

self.pictures=[]

self.bPen= pg.mkPen(color=(0, 240, 240, 255), width=w * 2)

self.bBrush= pg.mkBrush((0, 240, 240, 255))

self.rPen= pg.mkPen(color=(255, 60, 60, 255), width=w * 2)

self.rBrush= pg.mkBrush((255, 60, 60, 255))

self.rBrush.setStyle(Qt.NoBrush)#刷新K线

self.generatePicture(self.data)#画K线

#----------------------------------------------------------------------

def generatePicture(self, data=None, redraw=False):"""重新生成图形对象"""

#重画或者只更新最后一个K线

ifredraw:

self.pictures=[]elifself.pictures:

self.pictures.pop()

w= 0.4bPen=self.bPen

bBrush=self.bBrush

rPen=self.rPen

rBrush=self.rBrush

low, high= (data[0]['low'], data[0]['high']) if len(data) > 0 else (0, 1)for (t, open0, close0, low0, high0) indata:if t >=len(self.pictures):

tShift=t

low, high=(min(low, low0), max(high, high0))

picture=QtGui.QPicture()

p=QtGui.QPainter(picture)## 下跌蓝色(实心), 上涨红色(空心)

pen, brush, pmin, pmax =(bPen, bBrush, close0, open0) \if open0 > close0 else(rPen, rBrush, open0, close0)

p.setPen(pen)

p.setBrush(brush)#画K线方块和上下影线

if pmin >low0:

p.drawLine(QtCore.QPointF(tShift, low0), QtCore.QPointF(tShift, pmin))if high0 >pmax:

p.drawLine(QtCore.QPointF(tShift, pmax), QtCore.QPointF(tShift, high0))

p.drawRect(QtCore.QRectF(tShift- w, open0, w * 2, close0 -open0))#if open0 == close0:

#p.drawRect(QtCore.QPointF(tShift - w, open0), QtCore.QPointF(tShift + w, close0))

#else:

#p.drawRect(QtCore.QRectF(tShift - w, open0, w * 2, close0 - open0))

#if pmin > low0:

#p.drawLine(QtCore.QPointF(tShift, low0), QtCore.QPointF(tShift, pmin))

#if high0 > pmax:

#p.drawLine(QtCore.QPointF(tShift, pmax), QtCore.QPointF(tShift, high0))

p.end()

self.pictures.append(picture)

self.low, self.high=low, high#手动重画

#----------------------------------------------------------------------

defupdate(self):if not self.scene() isNone:

self.scene().update()#自动重画

#----------------------------------------------------------------------

defpaint(self, p, o, w):

rect=o.exposedRect

xmin, xmax=(max(0, int(rect.left())), min(len(self.pictures), int(rect.right())))

[p.drawPicture(0, 0, pic)for pic inself.pictures[xmin:xmax]]#定义边界

#----------------------------------------------------------------------

defboundingRect(self):return QtCore.QRectF(0, self.low, len(self.pictures), (self.high -self.low))########################################################################

classKLineWidget(KeyWraper):"""用于显示价格走势图"""

#保存K线数据的列表和Numpy Array对象

listBar =[]

listVol=[]

listHigh=[]

listLow=[]

listSig=[]

listOpenInterest=[]

arrows=[]#是否完成了历史数据的读取

initCompleted =False#----------------------------------------------------------------------

def __init__(self, parent=None, name=None):"""Constructor"""self.parent=parent

self.name=name

super(KLineWidget, self).__init__(parent)#当前序号

self.index = None #下标

self.countK = 60 #显示的K线范围

self.oldsize=0#rectd的hieght

#缓存数据

self.datas=[]

self.listBar=[]

self.listVol=[]

self.listHigh=[]

self.listLow=[]

self.listSig=[]

self.listOpenInterest=[]

self.arrows=[]

self.sars=[]#所有K线上信号图

self.allColor = deque(['blue', 'green', 'yellow', 'white'])

self.sigData={}

self.sigColor={}

self.sigPlots={}#初始化完成

self.initCompleted =False#调用函数

self.initUi()#----------------------------------------------------------------------

#初始化相关

#----------------------------------------------------------------------

definitUi(self):"""初始化界面"""self.setWindowTitle(u'K线工具')#主图

self.pw =pg.PlotWidget()#界面布局

self.lay_KL = pg.GraphicsLayout(border=(100, 100, 100))

self.lay_KL.setContentsMargins(10, 10, 10, 10)

self.lay_KL.setSpacing(0)

self.lay_KL.setBorder(color=(255, 255, 255, 255), width=0.8)

self.lay_KL.setZValue(0)

self.lay_KL.setMinimumHeight(140)

self.KLtitle= self.lay_KL.addLabel(u'')

self.pw.setCentralItem(self.lay_KL)#设置横坐标

xdict ={}

self.axisTime= MyStringAxis(xdict, orientation='bottom')#初始化子图

self.initplotKline()

self.initplotVol()

self.initplotOI()#注册十字光标

self.crosshair =Crosshair(self.pw, self)#设置界面

self.vb =QtWidgets.QVBoxLayout()

self.vb.addWidget(self.pw)

self.setLayout(self.vb)#初始化完成

self.initCompleted =True

self.oldsize=self.rect().height()

self.customBox={}#----------------------------------------------------------------------

defmakePI(self, name):"""生成PlotItem对象"""vb=CustomViewBox(self)

plotItem= pg.PlotItem(viewBox=vb, name=name, axisItems={'bottom': self.axisTime})

plotItem.setMenuEnabled(False)

plotItem.setClipToView(True)

plotItem.hideAxis('left')

plotItem.showAxis('right')

plotItem.setDownsampling(mode='peak')

plotItem.setRange(xRange=(0, 1), yRange=(0, 1))

plotItem.getAxis('right').setWidth(60)

plotItem.getAxis('right').setStyle(tickFont=QFont("Roman times", 10, QFont.Bold))

plotItem.getAxis('right').setPen(color=(255, 255, 255, 255), width=0.8)

plotItem.showGrid(True, True)

plotItem.hideButtons()returnplotItem#----------------------------------------------------------------------

definitplotVol(self):"""初始化成交量子图"""self.pwVol= self.makePI('PlotVol' +self.name)

self.volume=CandlestickItem(self.listVol)

self.pwVol.addItem(self.volume)

self.pwVol.setMaximumHeight((self.rect().height()-30)/4)

self.pwVol.setMinimumHeight(12)

self.pwVol.setXLink('PlotOI' +self.name)

self.pwVol.hideAxis('bottom')

self.lay_KL.nextRow()

self.lay_KL.addItem(self.pwVol)

self.lay_KL.adjustSize()#----------------------------------------------------------------------

definitplotKline(self):"""初始化K线子图"""self.pwKL= self.makePI('PlotKL' +self.name)

self.candle=CandlestickItem(self.listBar)

self.pwKL.addItem(self.candle)

self.pwKL.setXLink('PlotOI' +self.name)

self.pwKL.hideAxis('bottom')

self.pwKL.setMinimumHeight((self.rect().height()-30)/3)

self.lay_KL.nextRow()

self.lay_KL.addItem(self.pwKL)#----------------------------------------------------------------------

definitplotOI(self):"""初始化持仓量子图"""self.pwOI= self.makePI('PlotOI' +self.name)

self.curveOI=self.pwOI.plot()

self.pwOI.setMaximumHeight((self.rect().height()- 30) / 4)

self.pwOI.setMinimumHeight(20)

self.lay_KL.nextRow()

self.lay_KL.addItem(self.pwOI)#----------------------------------------------------------------------

#画图相关

#----------------------------------------------------------------------

def plotVol(self, redraw=False, xmin=0, xmax=-1):"""重画成交量子图"""

ifself.initCompleted:

self.volume.generatePicture(self.listVol[xmin:xmax], redraw)#画成交量子图

#----------------------------------------------------------------------

def plotKline(self, redraw=False, xmin=0, xmax=-1):"""重画K线子图"""

ifself.initCompleted:

self.candle.generatePicture(self.listBar[xmin:xmax], redraw)#画K线

self.plotMark() #显示开平仓信号位置

#----------------------------------------------------------------------

def plotOI(self, xmin=0, xmax=-1):"""重画持仓量子图"""

ifself.initCompleted:#self.curveOI.setData(self.listOpenInterest[xmin:xmax]+[0], symbol='o', name="OpenInterest")

self.curveOI.setData(self.listOpenInterest[xmin:xmax] +[0],

name="OpenInterest" + self.name) #去除symbol='o'

defupdateIndicatorSar(self, sarDatas, startIndex):"""更新sar指标 startIndex 从0到 len -1"""

if len(sarDatas) ==0:return

while (len(self.sars) > (startIndex - 1)):

sar= self.sars[-1]

self.pwKL.removeItem(sar)

self.sars.remove(sar)for i inrange(startIndex, len(sarDatas)):

arrow= pg.ArrowItem(pos=(i, sarDatas[i]), angle=90, tipAngle=5, headLen=2, tailWidth=4, pen={'width': 1},

brush=(0, 0, 255))

defaultOpts={'pxMode': True,'angle': -150, ## If the angle is 0, the arrow points left

'pos': (0, 0),'headLen': 10,'tipAngle': 10,'baseAngle': 0,'tailLen': None,'tailWidth': 3,'pen': (200, 200, 200),'brush': (255, 0, 0),

}#arrow.setStyle(defaultOpts)

self.pwKL.addItem(arrow)

self.sars.append(arrow)defaddIndicatorSar(self, sarDatas):"""增加sar指标"""

if len(sarDatas) ==0:return

for sar inself.sars:

self.pwKL.removeItem(sar)#画信号

for i inrange(len(sarDatas)):#arrow = pg.ArrowItem(pos=(i, sarDatas[i]),headLen=10, angle=90, brush=(0, 0, 255))

arrow = pg.ArrowItem(pos=(i, sarDatas[i]), angle=90, tipAngle=5, headLen=2, tailWidth=4, pen={'width': 1},

brush=(0, 0, 255))

defaultOpts={'pxMode': True,'angle': -150, ## If the angle is 0, the arrow points left

'pos': (0, 0),'headLen': 10,'tipAngle': 10,'baseAngle': 0,'tailLen': None,'tailWidth': 3,'pen': (200, 200, 200),'brush': (255, 0, 0),

}#arrow.setStyle(defaultOpts)

self.pwKL.addItem(arrow)

self.sars.append(arrow)#----------------------------------------------------------------------

defaddSig(self, sig):"""新增信号图"""

if sig inself.sigPlots:

self.pwKL.removeItem(self.sigPlots[sig])

self.sigPlots[sig]=self.pwKL.plot()

self.sigColor[sig]=self.allColor[0]

self.allColor.append(self.allColor.popleft())#----------------------------------------------------------------------

defshowSig(self, datas):"""刷新信号图"""

for sig inself.sigPlots:

self.sigData[sig]=datas[sig]

[self.sigPlots[sig].setData(datas[sig], pen=self.sigColor[sig][0], name=sig) \for sig in self.sigPlots] #if sig in datas]

#----------------------------------------------------------------------

defplotMark(self):"""显示开平仓信号"""

#检查是否有数据

if len(self.datas) ==0:return

for arrow inself.arrows:

self.pwKL.removeItem(arrow)#画买卖信号

for i inrange(len(self.listSig)):#无信号

if self.listSig[i] ==None:continue

#买信号

elif self.listSig[i] !=None:

direction= self.listSig[i]["direction"]

offset= self.listSig[i]["offset"]

price= self.listSig[i]["price"]if direction == "空" and offset == "开仓":#arrow = pg.ArrowItem(pos=(i, price), angle=-90, brush=(255, 0, 0))

arrow = pg.ArrowItem(pos=(i, price), angle=180, tipAngle=60, headLen=8, tailLen=3, tailWidth=5,

pen={'color': 'w', 'width': 1}, brush='r')elif direction == "多" and offset == "开仓":#arrow = pg.ArrowItem(pos=(i, price), angle=90, brush=(255, 0, 0))

arrow = pg.ArrowItem(pos=(i, price), angle=180, tipAngle=60, headLen=8, tailLen=3, tailWidth=5,

pen={'color': 'w', 'width': 1}, brush='b')elif direction == "空" and offset == "平仓":#arrow = pg.ArrowItem(pos=(i, price), angle=-90, brush=(0, 0, 255))

arrow = pg.ArrowItem(pos=(i, price), angle=0, tipAngle=40, headLen=8, tailLen=None, tailWidth=8,

pen={'color': 'w', 'width': 1}, brush='y')elif direction == "多" and offset == "平仓":#arrow = pg.ArrowItem(pos=(i, price), angle=90, brush=(0, 0, 255))

arrow = pg.ArrowItem(pos=(i, price), angle=0, tipAngle=40, headLen=8, tailLen=None, tailWidth=8,

pen={'color': 'w', 'width': 1}, brush='y')

self.pwKL.addItem(arrow)

self.arrows.append(arrow)#----------------------------------------------------------------------

defupdateAll(self):"""手动更新所有K线图形,K线播放模式下需要"""datas=self.datas

self.volume.update()

self.candle.update()defupdate(view, low, high):

vRange=view.viewRange()

xmin=max(0, int(vRange[0][0]))

xmax= max(0, int(vRange[0][1]))

xmax=min(xmax, len(datas))if len(datas) > 0 and xmax >xmin:

ymin=min(datas[xmin:xmax][low])

ymax=max(datas[xmin:xmax][high])if ymin andymax:

view.setRange(yRange=(ymin, ymax))else:

view.setRange(yRange=(0, 1))

update(self.pwKL.getViewBox(),'low', 'high')

update(self.pwVol.getViewBox(),'volume', 'volume')#update(self.pwOI.getViewBox(), 'openInterest', 'openInterest')

update(self.curveOI.getViewBox(), 'openInterest', 'openInterest')#----------------------------------------------------------------------

def plotAll(self, redraw=True, xMin=0, xMax=-1):"""重画所有界面

redraw :False=重画最后一根K线; True=重画所有

xMin,xMax : 数据范围"""

#xMax = len(self.datas) if xMax < 0 else xMax

#self.countK = xMax-xMin

#self.index = int((xMax+xMin)/2)

ifredraw:

xmax= len(self.datas) if xMax < 0 elsexMax

xmin=max(0,xmax-self.countK)

self.index= int((xmax + xmin) / 2)

self.pwOI.setLimits(xMin=xMin, xMax=xMax)

self.pwKL.setLimits(xMin=xMin, xMax=xMax)

self.pwVol.setLimits(xMin=xMin, xMax=xMax)

self.plotKline(redraw, xMin, xMax)#K线图

self.plotVol(redraw, xMin, xMax) #K线副图,成交量

self.plotOI(0, len(self.datas)) #K线副图,持仓量

self.refresh()defrefreshHeight(self):#super.__init__(QResizeEvent)

#如果窗口最大化,不修改比例,防御性设计

#if self.isMaximized():

#return

if len(self.datas)!=0:

height=self.rect().height()if height!=self.oldsize:

self.oldsize=height

height=(height-30)/4self.pwKL.setMinimumHeight(height* 2-24)

self.pwVol.setMaximumHeight(height)

self.pwVol.setMinimumHeight(12)

self.pwOI.setMaximumHeight(height)

self.pwOI.setMinimumHeight(12)#print height

#----------------------------------------------------------------------

defrefresh(self):"""刷新三个子图的现实范围"""datas=self.datas

minutes= int(self.countK / 2)

xmin= max(0, self.index -minutes)

xmax= xmin + 2 *minutes

self.pwOI.setRange(xRange=(xmin, xmax))

self.pwKL.setRange(xRange=(xmin, xmax))

self.pwVol.setRange(xRange=(xmin, xmax))#----------------------------------------------------------------------

#快捷键相关

#----------------------------------------------------------------------

defonNxt(self):"""跳转到下一个开平仓点"""

if len(self.listSig) > 0 and not self.index isNone:

datalen=len(self.listSig)

self.index+= 1

while self.index < datalen and self.listSig[self.index] ==0:

self.index+= 1self.refresh()

x=self.index

y= self.datas[x]['close']

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

defonPre(self):"""跳转到上一个开平仓点"""

if len(self.listSig) > 0 and not self.index isNone:

self.index-= 1

while self.index > 0 and self.listSig[self.index] ==0:

self.index-= 1self.refresh()

x=self.index

y= self.datas[x]['close']

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

defonDown(self):"""放大显示区间"""self.countK= min(len(self.datas), int(self.countK * 1.2) + 1)

self.refresh()if len(self.datas) >0:

x= self.index - self.countK / 2 + 2 ifint(

self.crosshair.xAxis)< self.index - self.countK / 2 + 2 elseint(self.crosshair.xAxis)

x= self.index + self.countK / 2 - 2 if x > self.index + self.countK / 2 - 2 elsex

x=min(x,len(self.datas)-1)

y= self.datas[x][2]#y = self.datas[x]['close']

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

defonUp(self):"""缩小显示区间"""

#self.countK = max(3,int(self.countK/1.2)-1)

self.countK = max(20, int(self.countK / 1.2) - 1) #最小显示k线范围20

self.refresh()if len(self.datas) >0:

x= self.index - self.countK / 2 + 2 ifint(

self.crosshair.xAxis)< self.index - self.countK / 2 + 2 elseint(self.crosshair.xAxis)

x= self.index + self.countK / 2 - 2 if x > self.index + self.countK / 2 - 2 elsex

x= min(x, len(self.datas)-1)

y= self.datas[x]['close']

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

defonLeft(self):"""向左移动"""

if len(self.datas) > 0 and int(self.crosshair.xAxis) > 2:

x= int(self.crosshair.xAxis) - 1y= self.datas[x]['close']if x <= self.index - self.countK / 2 + 2 and self.index > 1:

self.index-= 1self.refresh()

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

defonRight(self):"""向右移动"""

if len(self.datas) > 0 and int(self.crosshair.xAxis) < len(self.datas) - 1:

x= int(self.crosshair.xAxis) + 1y= self.datas[x]['close']if x >= self.index + int(self.countK / 2) - 2:

self.index+= 1self.refresh()

self.crosshair.signal.emit((x, y))#----------------------------------------------------------------------

#界面回调相关

#----------------------------------------------------------------------

defonPaint(self):"""界面刷新回调"""view=self.pwKL.getViewBox()

vRange=view.viewRange()#xmin = max(0,int(vRange[0][0]))

#xmax = max(0,int(vRange[0][1]))

#self.index = int((xmin+xmax)/2)+1

#----------------------------------------------------------------------

defresignData(self, datas):"""更新数据,用于Y坐标自适应"""self.crosshair.datas=datasdefviewXRangeChanged(low, high, self):

vRange=self.viewRange()

xmin=max(0, int(vRange[0][0]))

xmax= max(0, int(vRange[0][1]))

xmax=min(xmax, len(datas))if len(datas) > 0 and xmax >xmin:

ymin=min(datas[xmin:xmax][low])

ymax=max(datas[xmin:xmax][high])if ymin andymax:

self.setRange(yRange=(ymin, ymax))else:

self.setRange(yRange=(0, 1))

view=self.pwKL.getViewBox()

view.sigXRangeChanged.connect(partial(viewXRangeChanged,'low', 'high'))

view=self.pwVol.getViewBox()

view.sigXRangeChanged.connect(partial(viewXRangeChanged,'volume', 'volume'))

view=self.pwOI.getViewBox()

view.sigXRangeChanged.connect(partial(viewXRangeChanged,'openInterest', 'openInterest'))#----------------------------------------------------------------------

#数据相关

#----------------------------------------------------------------------

defclearData(self):"""清空数据"""

#清空数据,重新画图

self.time_index =[]

self.listBar=[]

self.listVol=[]

self.listLow=[]

self.listHigh=[]

self.listOpenInterest=[]

self.listSig=[]

self.sigData={}

self.arrows=[]

self.datas=None#----------------------------------------------------------------------

defupdateSig(self, sig):"""刷新买卖信号"""self.listSig=sig

self.plotMark()#----------------------------------------------------------------------

def onBar(self, bar, nWindow=20):"""新增K线数据,K线播放模式

nWindow : 最大数据窗口"""

#是否需要更新K线

newBar = False if len(self.datas) > 0 and bar.datetime == self.datas[-1].datetime elseTrue

nrecords= len(self.datas) if newBar else len(self.datas) - 1bar.openInterest=np.random.randint(0,3) if bar.openInterest == np.inf or bar.openInterest == -np.inf elsebar.openInterest

recordVol= (nrecords, bar.volume, 0, 0, bar.volume) if bar.close < bar.open else(

nrecords, 0, bar.volume, 0, bar.volume)if newBar andany(self.datas):

self.datas.resize(nrecords+ 1, refcheck=0)

self.listBar.resize(nrecords+ 1, refcheck=0)

self.listVol.resize(nrecords+ 1, refcheck=0)elifany(self.datas):

self.listLow.pop()

self.listHigh.pop()

self.listOpenInterest.pop()ifany(self.datas):

self.datas[-1] =(bar.datetime, bar.open, bar.close, bar.low, bar.high, bar.volume, bar.openInterest)

self.listBar[-1] =(nrecords, bar.open, bar.close, bar.low, bar.high)

self.listVol[-1] =recordVolelse:

self.datas=np.rec.array(

[(datetime, bar.open, bar.close, bar.low, bar.high, bar.volume, bar.openInterest)], \

names=('datetime', 'open', 'close', 'low', 'high', 'volume', 'openInterest'))

self.listBar=np.rec.array([(nrecords, bar.open, bar.close, bar.low, bar.high)], \

names=('datetime', 'open', 'close', 'low', 'high'))

self.listVol= np.rec.array([recordVol], names=('datetime', 'open', 'close', 'low', 'high'))

self.resignData(self.datas)

self.axisTime.update_xdict({nrecords: bar.datetime})

self.listLow.append(bar.low)

self.listHigh.append(bar.high)

self.listOpenInterest.append(bar.openInterest)#if newBar:

#xMax = nrecords + 1

#xMin = max(0, xMax - self.countK) # 最小显示区间

#self.index=int(xMax+xMin)/2

#if self.pwKL.getViewBox().mousePress == True:

#print("sssssssssss")

#if self.pwKL.getViewBox().mousePress == False: ##self.mousePress==false,不在执行刷新操作

xMax= self.index +self.countK

xMin= self.index -self.countK#xMin=(0,xMin)

if xMin<0:

xMin=0if notnewBar:

self.updateAll()

self.plotAll(False, xMin, xMax)

self.crosshair.signal.emit((None, None))#----------------------------------------------------------------------

defloadData(self, datas):"""载入pandas.DataFrame数据

datas : 数据格式,cols : datetime, open, close, low, high"""

#设置中心点时间

self.index =0#绑定数据,更新横坐标映射,更新Y轴自适应函数,更新十字光标映射

datas['time_int'] =np.array(range(len(datas.index)))

self.datas= datas[['open', 'close', 'low', 'high', 'volume', 'openInterest']].to_records()

self.axisTime.xdict={}

xdict=dict(enumerate(datas.index.tolist()))

self.axisTime.update_xdict(xdict)

self.resignData(self.datas)#更新画图用到的数据

self.listBar = datas[['time_int', 'open', 'close', 'low', 'high']].to_records(False)

self.listHigh= list(datas['high'])

self.listLow= list(datas['low'])

self.listOpenInterest= list(datas['openInterest'])#成交量颜色和涨跌同步,K线方向由涨跌决定

datas0 =pd.DataFrame()

datas0['open'] = datas.apply(lambda x: 0 if x['close'] >= x['open'] else x['volume'], axis=1)

datas0['close'] = datas.apply(lambda x: 0 if x['close'] < x['open'] else x['volume'], axis=1)

datas0['low'] = datas0['open']

datas0['high'] = datas0['close']

datas0['time_int'] =np.array(range(len(datas.index)))

self.listVol= datas0[['time_int', 'open', 'close', 'low', 'high']].to_records(False)#调用画图函数

self.plotAll(True, 0, len(self.datas))defloadDataBar(self, datas):"""载入pandas.DataFrame数据

datas : 数据格式,'symbol','vtSymbol','exchange','open','high','low','close','date','time1','datetime','volume','openInterest'"""

print(datas)

self.index=0#绑定数据,更新横坐标映射,更新Y轴自适应函数,更新十字光标映射

datas['time_int'] =np.array(range(len(datas.index)))

self.datas= datas[['datetime', 'open', 'close', 'low', 'high', 'volume', 'openInterest']].to_records(False)#self.datas = datas[['symbol','vtSymbol','exchange','open','high','low','close','date','time1','datetime','volume','openInterest']].to_records()

self.axisTime.xdict ={}#xdict = dict(enumerate(datas.index.tolist()))

xdict = dict(enumerate(datas['datetime'].tolist()))

self.axisTime.update_xdict(xdict)

self.resignData(self.datas)#更新画图用到的数据

self.listBar = datas[['time_int', 'open', 'close', 'low', 'high']].to_records(False)

self.listHigh= list(datas['high'])

self.listLow= list(datas['low'])

self.listOpenInterest= list(datas['openInterest'])#成交量颜色和涨跌同步,K线方向由涨跌决定

datas0 =pd.DataFrame()

datas0['open'] = datas.apply(lambda x: 0 if x['close'] >= x['open'] else x['volume'], axis=1)

datas0['close'] = datas.apply(lambda x: 0 if x['close'] < x['open'] else x['volume'], axis=1)

datas0['low'] = datas0['open']

datas0['high'] = datas0['close']

datas0['time_int'] =np.array(range(len(datas.index)))

self.listVol= datas0[['time_int', 'open', 'close', 'low', 'high']].to_records(False)#调用画图函数

self.plotAll(True, 0, len(self.datas))##VtBarData 结构

defloadDataBarArray(self, record):

txtData= pd.DataFrame.from_records(record, index="datetime")#txtData = txtData.rename(columns = {0:'symbol', 1:"vtSymbol",2:"exchange",3:"open",4:"high",5:"low",6:"close",7:"date",8:"time",9:"datetime",10:"volume",11:"openInterest"})

self.loadData(txtData)#########################################################################功能测试########################################################################

importsysif __name__ == '__main__':

app=QApplication(sys.argv)#界面设置

cfgfile = QtCore.QFile('css.qss')

cfgfile.open(QtCore.QFile.ReadOnly)

styleSheet=cfgfile.readAll()

styleSheet= unicode(styleSheet, encoding='utf8')

app.setStyleSheet(styleSheet)#K线界面

#ui = KLineWidget()

#ui.show()

#ui.KLtitle.setText('rb1701',size='20pt')

#ui.loadData(pd.DataFrame.from_csv('data.csv'))

ui= KLineWidget(name="opt")

ui.show()

ui.KLtitle.setText('rb1701', size='20pt')#txtData = pd.DataFrame.from_csv('D:/data/day/rb1101.txt',header=None,index_col=7)

txtData = pd.DataFrame.from_csv('E:/Data/day/rb1101.txt', header=None, index_col=7)

txtData=txtData.rename(

columns={0: 'symbol', 1: "vtSymbol", 2: "exchange", 3: "open", 4: "high", 5: "low", 6: "close", 7: "date",8: "time", 9: "datetime", 10: "volume", 11: "openInterest"})

ui.loadDataBar(txtData)

app.exec_()

python kline_python kline相关推荐

  1. python kline_Python pyecharts package v0.3.1, pyecharts.charts.kline module source code :: PyDoc.net

    #!/usr/bin/env python # coding=utf-8 from pyecharts.chart import Chart from pyecharts.option import ...

  2. python画k线图_小白学Python(14)——pyecharts 绘制K线图 Kline/Candlestick

    Kline-基本示例 from pyecharts import options as opts from pyecharts.charts import Kline data = [ [2320.2 ...

  3. python pyqtgraph绘制股票kline图类封装(tcy)

    用途:绘制股票kline图 说明: 绘制基本的股票kline图及相关指标图如ma移动平均线等,绘制其他指标只需传入相关数据及线的颜色即可. 绘制鼠标移动显示交易时间及open,high,low,clo ...

  4. python kline_一篇文章教你学会用kline获取量化数据

    阅读原文:http://t.cn/RicAPbx KLineHistory -获取k线数据 概述 获取K线数据类,该类可以通过调用IStatisticsGroup类的kLineHistory方法获取, ...

  5. python pyecharts 画图修改kline颜色,自定义MarkPointOpts

    markpoint_opts=opts.MarkPointOpts(data=[# opts.MarkPointItem(type_="max", name="最大值&q ...

  6. 赠书 | Python 预测股票价格,竟然这么简单

    作为一种技术手段,预测在金融.证券领域的应用非常广泛,尤其是对股票价格的预测.我们介绍一下获得股票数据的方法,并基于此对数据进行预处理,接着使用数据分析方法,建立基础特征,进一步构建预测模型,且基于新 ...

  7. python实用性函数分享_分享|3个开源的 Python Shell

    Python是一个高级.通用.结构化且强大的开源编程语言,广泛用于各种编程工作.它拥有一个全动态类型系统和自动内存管理,与Scheme,Ruby,Perl和Tcl的十分相似,避免编译型语言的许多复杂地 ...

  8. python接口 同花顺_这是真的么 | 学会了用Python预测股票价格

    文章来源于微信公众号:机器学习与python实战 原文链接:请点击 文章仅用于学习交流,如有侵权请联系删除 作为一种技术手段,预测在金融.证券领域的应用非常广泛,尤其是对股票价格的预测.我们介绍一下获 ...

  9. python 仪表盘-python仪表盘

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! data_pair=], # 系列数据项,格式为 radius=70%, # 仪 ...

最新文章

  1. cmd系统命令不识别
  2. Swoole源代码学习记录(十五)——Timer模块分析
  3. pb 执行存储过程带参数_数据库存储过程
  4. WPS演示中万花筒效果的实现
  5. 利用注释及自定义加密免杀Webshell
  6. Java big file debug - random access
  7. leetcode面试题 10.02. 变位词组
  8. 查看及修改MYSQL最大连接数
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的超市订单管理系统
  10. 机器学习 数据间的定义_定义数据科学,机器学习和人工智能
  11. 易语言5.4一键破解工具
  12. 顶岗实习周记计算机专业40篇,计算机顶岗实习周记20篇
  13. wekan 工具配置
  14. Linux CFS调度器之唤醒WAKE_AFFINE 机制--Linux进程的管理与调度(三十一)
  15. 2016年腾讯实习生校园招聘-电面
  16. 用Typora+PicGo搞定多个平台发文和微信公众号排版
  17. foxmail怎么设置服务器才能登陆网易企业邮箱
  18. intellij idea快速切换大小写
  19. 【CSS】492- 无外链的CSS开发策略
  20. hackthebox-Tracks-Beginner_Track-Lame

热门文章

  1. Final cut pro x motion5 compressor破解下载地址
  2. 客户自己下单软件|移讯云网上手机订货管理软件
  3. 用u盘做启动盘安装系统后如何删除PE系统
  4. 【华为OD机试模拟题】用 C++ 实现 - 航天器(2023.Q1)
  5. 【FPGA】【Verilog】【基础模块】状态机
  6. XJTU大计基作业-1(第7周)
  7. Jquery 控制disabled和readonly
  8. 实战:又到一年淘宝清仓时 给你五个活动方案参考
  9. SEO教程:免费分享SEO外链建设方法不可错过
  10. 记第一次topcoderSRM赛(2011,09,10)Jie.Qin'birthday