# encoding: UTF-8 import sys,os import qtpy import pyqtgraph as pg import datetime as dt import numpy as np import traceback #from pyqtgraph.Qt import QtGui, QtCore from qtpy import QtGui, QtCore from pyqtgraph.Point import Point ######################################################################## # 十字光标支持 ######################################################################## class Crosshair(QtCore.QObject): """ 此类给pg.PlotWidget()添加crossHair功能,PlotWidget实例需要初始化时传入 """ signal = QtCore.Signal(type(tuple([]))) signalInfo = QtCore.Signal(float,float) #---------------------------------------------------------------------- def __init__(self,parent,master): """Constructor""" self.__view = parent self.master = master super(Crosshair, self).__init__() self.xAxis = 0 self.yAxis = 0 self.datas = None self.yAxises = [0 for i in range(3)] self.leftX = [0 for i in range(3)] self.showHLine = [False for i in range(3)] self.textPrices = [pg.TextItem('',anchor=(1,1)) for i in range(3)] self.views = [parent.centralWidget.getItem(i+1,0) for i in range(3)] self.rects = [self.views[i].sceneBoundingRect() for i in range(3)] self.vLines = [pg.InfiniteLine(angle=90, movable=False) for i in range(3)] self.hLines = [pg.InfiniteLine(angle=0, movable=False) for i in range(3)] #mid 在y轴动态跟随最新价显示最新价和最新时间 self.__textDate = pg.TextItem('date',anchor=(1,1)) self.__textInfo = pg.TextItem('lastBarInfo') self.__textSig = pg.TextItem('lastSigInfo',anchor=(1,0)) self.__textSubSig = pg.TextItem('lastSubSigInfo',anchor=(1,0)) self.__textVolume = pg.TextItem('lastBarVolume',anchor=(1,0)) self.__textDate.setZValue(2) self.__textInfo.setZValue(2) self.__textSig.setZValue(2) self.__textSubSig.setZValue(2) self.__textVolume.setZValue(2) self.__textInfo.border = pg.mkPen(color=(230, 255, 0, 255), width=1.2) for i in range(3): self.textPrices[i].setZValue(2) self.vLines[i].setPos(0) self.hLines[i].setPos(0) self.vLines[i].setZValue(0) self.hLines[i].setZValue(0) self.views[i].addItem(self.vLines[i]) self.views[i].addItem(self.hLines[i]) self.views[i].addItem(self.textPrices[i]) self.views[0].addItem(self.__textInfo, ignoreBounds=True) self.views[0].addItem(self.__textSig, ignoreBounds=True) self.views[1].addItem(self.__textVolume, ignoreBounds=True) self.views[2].addItem(self.__textDate, ignoreBounds=True) self.views[2].addItem(self.__textSubSig, ignoreBounds=True) self.proxy = pg.SignalProxy(self.__view.scene().sigMouseMoved, rateLimit=360, slot=self.__mouseMoved) # 跨线程刷新界面支持 self.signal.connect(self.update) self.signalInfo.connect(self.plotInfo) #---------------------------------------------------------------------- def update(self,pos): """刷新界面显示""" xAxis,yAxis = pos xAxis,yAxis = (self.xAxis,self.yAxis) if xAxis is None else (xAxis,yAxis) self.moveTo(xAxis,yAxis) #---------------------------------------------------------------------- def __mouseMoved(self,evt): """鼠标移动回调""" pos = evt[0] self.rects = [self.views[i].sceneBoundingRect() for i in range(3)] for i in range(3): self.showHLine[i] = False if self.rects[i].contains(pos): mousePoint = self.views[i].vb.mapSceneToView(pos) xAxis = mousePoint.x() yAxis = mousePoint.y() self.yAxises[i] = yAxis self.showHLine[i] = True self.moveTo(xAxis,yAxis) #---------------------------------------------------------------------- def moveTo(self,xAxis,yAxis): xAxis,yAxis = (self.xAxis,self.yAxis) if xAxis is None else (int(xAxis),yAxis) self.rects = [self.views[i].sceneBoundingRect() for i in range(3)] if not xAxis or not yAxis: return self.xAxis = xAxis self.yAxis = yAxis self.vhLinesSetXY(xAxis,yAxis) self.plotInfo(xAxis,yAxis) self.master.volume.update() #---------------------------------------------------------------------- def vhLinesSetXY(self,xAxis,yAxis): """水平和竖线位置设置""" for i in range(3): self.vLines[i].setPos(xAxis) if self.showHLine[i]: self.hLines[i].setPos(yAxis if i==0 else self.yAxises[i]) self.hLines[i].show() else: self.hLines[i].hide() #---------------------------------------------------------------------- def plotInfo(self,xAxis,yAxis): """ 被嵌入的plotWidget在需要的时候通过调用此方法显示K线信息 """ if self.datas is None: return try: # 获取K线数据 data = self.datas[xAxis] lastdata = self.datas[xAxis-1] tickDatetime = data['datetime'] openPrice = data['open'] closePrice = data['close'] lowPrice = data['low'] highPrice = data['high'] volume = int(data['volume']) openInterest = int(data['openInterest']) preClosePrice = lastdata['close'] tradePrice = abs(self.master.listSig[xAxis]) except Exception as e: return if(isinstance(tickDatetime,dt.datetime)): datetimeText = dt.datetime.strftime(tickDatetime,'%Y-%m-%d %H:%M:%S') dateText = dt.datetime.strftime(tickDatetime,'%Y-%m-%d') timeText = dt.datetime.strftime(tickDatetime,'%H:%M:%S') else: datetimeText = "" dateText = "" timeText = "" # 显示所有的主图技术指标 html = u'<div style="text-align: right">' for sig in self.master.sigData: val = self.master.sigData[sig][xAxis] col = self.master.sigColor[sig] html+= u'<span style="color: %s; font-size: 18px;"> %s:%.2f</span>' %(col,sig,val) html+=u'</div>' self.__textSig.setHtml(html) # 显示所有的主图技术指标 html = u'<div style="text-align: right">' for sig in self.master.subSigData: val = self.master.subSigData[sig][xAxis] col = self.master.subSigColor[sig] html+= u'<span style="color: %s; font-size: 18px;"> %s:%.2f</span>' %(col,sig,val) html+=u'</div>' self.__textSubSig.setHtml(html) # 和上一个收盘价比较,决定K线信息的字符颜色 cOpen = 'red' if openPrice > preClosePrice else 'green' cClose = 'red' if closePrice > preClosePrice else 'green' cHigh = 'red' if highPrice > preClosePrice else 'green' cLow = 'red' if lowPrice > preClosePrice else 'green' self.__textInfo.setHtml( u'<div style="text-align: center; background-color:#000">\ <span style="color: white; font-size: 16px;">日期</span><br>\ <span style="color: yellow; font-size: 16px;">%s</span><br>\ <span style="color: white; font-size: 16px;">时间</span><br>\ <span style="color: yellow; font-size: 16px;">%s</span><br>\ <span style="color: white; font-size: 16px;">价格</span><br>\ <span style="color: %s; font-size: 16px;">(开) %.3f</span><br>\ <span style="color: %s; font-size: 16px;">(高) %.3f</span><br>\ <span style="color: %s; font-size: 16px;">(低) %.3f</span><br>\ <span style="color: %s; font-size: 16px;">(收) %.3f</span><br>\ <span style="color: white; font-size: 16px;">成交量</span><br>\ <span style="color: yellow; font-size: 16px;">(量) %d</span><br>\ <span style="color: white; font-size: 16px;">成交价</span><br>\ <span style="color: yellow; font-size: 16px;">(价) %.3f</span><br>\ </div>'\ % (dateText,timeText,cOpen,openPrice,cHigh,highPrice,\ cLow,lowPrice,cClose,closePrice,volume,tradePrice)) self.__textDate.setHtml( '<div style="text-align: center">\ <span style="color: yellow; font-size: 18px;">%s</span>\ </div>'\ % (datetimeText)) self.__textVolume.setHtml( '<div style="text-align: right">\ <span style="color: white; font-size: 18px;">VOL : %.3f</span>\ </div>'\ % (volume)) # 坐标轴宽度 rightAxisWidth = self.views[0].getAxis('right').width() bottomAxisHeight = self.views[2].getAxis('bottom').height() offset = QtCore.QPointF(rightAxisWidth,bottomAxisHeight) # 各个顶点 tl = [self.views[i].vb.mapSceneToView(self.rects[i].topLeft()) for i in range(3)] br = [self.views[i].vb.mapSceneToView(self.rects[i].bottomRight()-offset) for i in range(3)] # 显示价格 for i in range(3): if self.showHLine[i]: self.textPrices[i].setHtml( '<div style="text-align: right">\ <span style="color: yellow; font-size: 18px;">\ %0.3f\ </span>\ </div>'\ % (yAxis if i==0 else self.yAxises[i])) self.textPrices[i].setPos(br[i].x(),yAxis if i==0 else self.yAxises[i]) self.textPrices[i].show() else: self.textPrices[i].hide() # 设置坐标 self.__textInfo.setPos(tl[0]) self.__textSig.setPos(br[0].x(),tl[0].y()) self.__textSubSig.setPos(br[2].x(),tl[2].y()) self.__textVolume.setPos(br[1].x(),tl[1].y()) # 修改对称方式防止遮挡 self.__textDate.anchor = Point((1,1)) if xAxis > self.master.index else Point((0,1)) self.__textDate.setPos(xAxis,br[2].y())