Python交互K線工具 K線核心功能+指標切換
aiqtt
團隊量化研究,用vn.py回測和研究策略。基於vnpy開源代碼,剛開始接觸pyqt,開發界面還是很痛苦,找了很多案例參考,但並不能完全滿足我們自己對於檢查自己的交易邏輯的需求,只能參考網上的案例自己開發
代碼較多,大家可以直接到GitHub下載開源源碼查看
歡迎加入QQ交流群: 538665416(免費提供,期貨,期權數據)
團隊界面需求:
-
界面加載k線,
-
鼠標滾輪縮放,鍵盤縮放跳轉
-
十字光標 顯示K線詳細信息
-
縮放自適應Y軸坐標
-
回測完以后加載買賣開平倉位置有箭頭標記,並且通過鍵盤可以在標記之間跳轉
- 界面切換操作周期
-
界面右鍵可以切換指標
-
分享部分核心代碼:K線展示的核心功能使用pyqtgraph實現,根據需求實現部分跟新
Kline對象代碼: ######################################################################## # K線圖形對象 ######################################################################## class CandlestickItem(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.4 self.offset = 0 self.low = 0 self.high = 1 self.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線 if redraw: self.pictures = [] elif self.pictures: self.pictures.pop() w = 0.4 bPen = 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) in data: 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 # 手動重畫 # ---------------------------------------------------------------------- def update(self): if not self.scene() is None: self.scene().update() # 自動重畫 # ---------------------------------------------------------------------- def paint(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 in self.pictures[xmin:xmax]] # 定義邊界 # ---------------------------------------------------------------------- def boundingRect(self): return QtCore.QRectF(0, self.low, len(self.pictures), (self.high - self.low)) 鍵盤鼠標功能代碼: ######################################################################## # 鍵盤鼠標功能 ######################################################################## class KeyWraper(QtWidgets.QWidget): """鍵盤鼠標功能支持的元類""" # 初始化 # ---------------------------------------------------------------------- def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) # 重載方法keyPressEvent(self,event),即按鍵按下事件方法 # ---------------------------------------------------------------------- def keyPressEvent(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),即鼠標點擊事件方法 # ---------------------------------------------------------------------- def mousePressEvent(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),即鼠標點擊事件方法 # ---------------------------------------------------------------------- def mouseReleaseEvent(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),即滾輪事件方法 # ---------------------------------------------------------------------- def wheelEvent(self, event): if event.delta() > 0: self.onUp() else: self.onDown() # 重載方法dragMoveEvent(self,event),即拖動事件方法 # ---------------------------------------------------------------------- def paintEvent(self, event): self.onPaint() # PgDown鍵 # ---------------------------------------------------------------------- def onNxt(self): pass # PgUp鍵 # ---------------------------------------------------------------------- def onPre(self): pass # 向上鍵和滾輪向上 # ---------------------------------------------------------------------- def onUp(self): pass # 向下鍵和滾輪向下 # ---------------------------------------------------------------------- def onDown(self): pass # 向左鍵 # ---------------------------------------------------------------------- def onLeft(self): pass # 向右鍵 # ---------------------------------------------------------------------- def onRight(self): pass # 鼠標左單擊 # ---------------------------------------------------------------------- def onLClick(self, pos): pass # 鼠標右單擊 # ---------------------------------------------------------------------- def onRClick(self, pos): pass # 鼠標左釋放 # ---------------------------------------------------------------------- def onLRelease(self, pos): pass # 鼠標右釋放 # ---------------------------------------------------------------------- def onRRelease(self, pos): pass # 畫圖 # ---------------------------------------------------------------------- def onPaint(self): pass ######################################################################## # 選擇縮放功能支持 ######################################################################## class CustomViewBox(pg.ViewBox): # ---------------------------------------------------------------------- def __init__(self, parent, *args, **kwds): pg.ViewBox.__init__(self, *args, **kwds) self.parent = parent # 拖動放大模式 # self.setMouseMode(self.RectMode) ## 右鍵 # ---------------------------------------------------------------------- def mouseClickEvent(self, ev): if ev.button() == QtCore.Qt.RightButton: self.contextMenuEvent(ev) # 右鍵菜單 # if ev.button()==QtCore.Qt.LeftButton: # self.autoRange()#右鍵自適應 # 重載方法mousePressEvent(self,event),即鼠標點擊事件方法 # ---------------------------------------------------------------------- def mousePressEvent(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.countK if xMin < 0: xMin = 0 # self.parent.plotAll(False, xMin, xMax) #注釋原因:拖動事件不需要先繪制圖形界面 pg.ViewBox.mouseDragEvent(self, ev, axis) # ## 重載方法resizeEvent(self, ev) def resizeEvent(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() ###加載指標 def contextMenuEvent(self,ev): """打開指標窗口""" CustomMenu(self.parent) ######################################################################## # 時間序列,橫坐標支持 ######################################################################## class MyStringAxis(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) # 更新坐標映射表 # ---------------------------------------------------------------------- def update_xdict(self, xdict): self.xdict.update(xdict) self.x_values = np.asarray(self.xdict.keys()) self.x_strings = self.xdict.values() # 將原始橫坐標轉換為時間字符串,第一個坐標包含日期 # ---------------------------------------------------------------------- def tickStrings(self, values, scale, spacing): strings = [] for v in values: vs = v * scale if vs in self.x_values: vstr = self.x_strings[np.abs(self.x_values - vs).argmin()] if (isinstance(vstr, (str))): vstr = vstr else: vstr = vstr.strftime('%Y-%m-%d %H:%M:%S') else: vstr = "" strings.append(vstr) return strings
右鍵菜單加載指標代碼:
###加載指標
def contextMenuEvent(self,ev):
"""打開指標窗口"""
CustomMenu(self.parent)# encoding: UTF-8 from vnpy.trader.uiQt import QtGui, QtWidgets, QtCore, BASIC_FONT from qtpy.QtCore import Qt,QRect from qtpy.QtWidgets import QApplication, QWidget,QPushButton,QMenu from qtpy.QtGui import QPainter, QPainterPath, QPen, QColor, QPixmap, QIcon, QBrush, QCursor from vnpy.trader import vtText from vnpy.event import Event import qdarkstyle #Qt黑色主題 from vnpy.trader.IndicatorsFun.indicatorsManage import IndicatorsFunManage import sys class CustomMenu( QtWidgets.QPushButton): """合約管理組件""" signal = QtCore.Signal(type(Event())) # ---------------------------------------------------------------------- def __init__(self,parent): """Constructor""" super(CustomMenu, self).__init__() self.parent=parent # self.initUi() self.initMenu() #----------------------------------------------------------------------- def initMenu(self): self.setStyleSheet("QMenu{background:purple;}" "QMenu{border:1px solid lightgray;}" "QMenu{border-color:green;}" "QMenu::item{padding:0px 20px 0px 15px;}" "QMenu::item{height:30px;}" "QMenu::item{color:blue;}" "QMenu::item{background:white;}" "QMenu::item{margin:1px 0px 0px 0px;}" "QMenu::item:selected:enabled{background:lightgray;}" "QMenu::item:selected:enabled{color:white;}" "QMenu::item:selected:!enabled{background:transparent;}" "QMenu::separator{height:50px;}" "QMenu::separator{width:1px;}" "QMenu::separator{background:white;}" "QMenu::separator{margin:1px 1px 1px 1px;}" "QMenu#menu{background:white;}" "QMenu#menu{border:1px solid lightgray;}" "QMenu#menu::item{padding:0px 20px 0px 15px;}" "QMenu#menu::item{height:15px;}" "QMenu#menu::item:selected:enabled{background:lightgray;}" "QMenu#menu::item:selected:enabled{color:white;}" "QMenu#menu::item:selected:!enabled{background:transparent;}" "QMenu#menu::separator{height:1px;}" "QMenu#menu::separator{background:lightgray;}" "QMenu#menu::separator{margin:2px 0px 2px 0px;}" "QMenu#menu::indicator {padding:5px;}" ) self.color = QColor(Qt.gray) self.opacity = 1.0 ''''''' 創建右鍵菜單 ''' # 必須將ContextMenuPolicy設置為Qt.CustomContextMenu # 否則無法使用customContextMenuRequested信號 self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showContextMenu) # 創建QMenu self.contextMenu = QMenu(self) self.trendMenu=self.contextMenu.addMenu(u"趨勢分析指標") self.swingMenu = self.contextMenu.addMenu(u"擺動分析") self.amountMenu = self.contextMenu.addMenu(u"量倉分析") # 添加二級菜單 #趨勢分析指標 self.actionSAR= self.trendMenu.addAction(u'SAR') self.actionSAR.triggered.connect(lambda: self.parent.initIndicator(u"SAR")) self.actionBOLL = self.trendMenu.addAction(u'BOLL') self.actionBOLL.triggered.connect(lambda: self.parent.initIndicator(u"BOLL")) self.actionMA = self.trendMenu.addAction(u'MA') self.actionMA.triggered.connect(lambda: self.parent.initIndicator(u"MA")) #擺動分析 self.actionCCI = self.swingMenu.addAction(u'CCI') self.actionCCI.triggered.connect(lambda: self.parent.initIndicator(u"CCI")) self.actionROC = self.swingMenu.addAction(u'ROC') self.actionROC.triggered.connect(lambda: self.parent.initIndicator(u"ROC")) ##量倉分析 self.actionOPI = self.amountMenu.addAction(u'OPI') self.actionOPI.triggered.connect(lambda: self.parent.initIndicator(u"OPI")) ##成交量分析 self.actionVOL = self.amountMenu.addAction(u'CJL') self.actionVOL.triggered.connect(lambda: self.parent.initIndicator(u"CJL")) self.contextMenu.exec_(QCursor.pos()) # 在鼠標位置顯示 #添加二級菜單 def showContextMenu(self, pos): ''''' 右鍵點擊時調用的函數 ''' # 菜單顯示前,將它移動到鼠標點擊的位置 # self.contextMenu.move(self.pos() + pos) self.contextMenu.show() self.contextMenu.exec_(QCursor.pos())
# encoding: UTF-8 from vnpy.trader.vtConstant import (EMPTY_STRING, EMPTY_UNICODE, EMPTY_FLOAT, EMPTY_INT) from vnpy.trader.vtFunction import getJsonPath,getTempPath import numpy as np import pandas as pd import json import talib from vnpy.trader.indicator.SAR import * import pyqtgraph as pg import os import importlib import traceback from .algo import INDICATORS_CLASS,sarAlgo,bollAlgo ###################切換指標########################## class IndicatorsFunManage(object): settingFileName = 'Indicators_setting.json' settingfilePath = getJsonPath(settingFileName, __file__) def __init__(self, parent): self.indicators_seeting=None # 指標配置文件 self.parent = parent self.indicatorsFunc = {} # 添加指標 # 讀取本地指標配置文件 with open(self.settingfilePath) as f: self.indicators_seeting = json.load(f) def RemoveIndicators(self,name): if self.indicatorsFunc.has_key(name): removeFunc = self.indicatorsFunc[name] removeFunc.remove() def getYRange(self,xMin,xMax,location): if self.indicatorsFunc: for indicators in self.indicatorsFunc.values(): if indicators.base.figure == location: return indicators.getYRange(xMin, xMax) return 0,1 def addIndicators(self,name): if self.indicatorsFunc.has_key(name): return if not (self.indicatorsFunc.has_key(name)): indicatorsInfo = self.indicators_seeting[name] figure =indicatorsInfo["location"] if self.indicatorsFunc: for indicators in self.indicatorsFunc.values(): if indicators.base.figure == figure: indicators.remove() del self.indicatorsFunc[indicators.base.name] break indicator = self.startFun(indicatorsInfo, name) if indicator: self.indicatorsFunc[name] = indicator indicator.addIndicators() def updateIndicators(self): if self.indicatorsFunc: for indicators in self.indicatorsFunc.values(): indicators.updateIndicators() def getIndicatorsHtml(self,figure,index): if self.indicatorsFunc: for indicators in self.indicatorsFunc.values(): if indicators.base.figure == figure: html = indicators.getIndicatorsHtml(index) return html def startFun(self,indicatorsInfo,name): """載入算法""" try: className = indicatorsInfo["className"] except Exception, e: print (u'載入指標算法出錯:%s' % e) # 獲取算法類 alogClass = INDICATORS_CLASS.get(className, None) return self.callIndicatorsFunc(alogClass, self.parent, indicatorsInfo, name) if not alogClass: print(u'找不到指標算法類:%s' % className) return None # ---------------------------------------------------------------------- def callIndicatorsFunc(self, func, parent, indicatorsInfo, name): """調用策略的函數,若觸發異常則捕捉""" try: if parent: return func(parent, indicatorsInfo, name) #self.indicatorsFunc[name] = self.func except Exception: # 停止類,修改狀態為未初始化 print(u'算法%s觸發異常已停止', traceback.format_exc())
指標配置文件:
{ "SAR":{"className":"sarAlgo","location":"mainfigure"}, "BOLL":{"className":"bollAlgo", "location":"mainfigure","param":{"N":20,"M":20,"P":2}}, "CCI":{"className":"cciAlgo", "location":"vicefigure2","param":{"N":21}}, "MA":{"className":"maAlgo", "location":"mainfigure","param":{"N1":3,"N2":5,"N3":8,"N4":13,"N5":21,"N6":34,"algo":"EMA"}}, "OPI":{"className":"opiAlgo", "location":"vicefigure2"}, "CJL":{"className":"cjlAlgo", "location":"vicefigure1"}, "ROC":{"className":"rocAlgo", "location":"vicefigure1","param":{"N":10}} }
指標函數:
布林通道指標;
# encoding: UTF-8 import numpy as np import pandas as pd from vtIndictors import IndicatorParent import pyqtgraph as pg import talib ####################布林通道計算#################################### class bollAlgo(IndicatorParent): setting_info = None def __init__(self, parent, indicatorsInfo, name): IndicatorParent.__init__(self,parent) self.parent=parent self.curveOI1 = None self.curveOI2 = None self.curveOI3 = None self.upperline = [] self.midline = [] self.downline = [] self.indictorname = name self.setting_info = indicatorsInfo self.figure = self.setting_info["location"] self.plotItem = self.plotItems[self.figure] def addIndicators(self): hourcloseArray = np.array(self.parent.listClose) N = self.setting_info["param"]["N"] M= self.setting_info["param"]["M"] P = self.setting_info["param"]["P"] self.hourBollData_up, self.hourBollData_mid, self.hourBollData_low = self.boll( hourcloseArray, N,M, P, True) self.addUpper(self.hourBollData_up) self.addMid(self.hourBollData_mid) self.addDown(self.hourBollData_low) self.setIndicatorsData() def addUpper(self, up): if self.curveOI1: self.plotItem.removeItem(self.curveOI1) self.upperline = up self.curveOI1 = pg.PlotDataItem() self.curveOI1.setData(y=self.upperline,pen="y") self.plotItem.addItem(self.curveOI1) def addMid(self, mid): if self.curveOI2: self.plotItem.removeItem(self.curveOI2) self.midline = mid self.curveOI2 = pg.PlotDataItem() self.curveOI2.setData(y=self.midline,pen="w") self.plotItem.addItem(self.curveOI2) def addDown(self, down): if self.curveOI3: self.plotItem.removeItem(self.curveOI3) self.downline = down self.curveOI3 = pg.PlotDataItem() self.curveOI3.setData(y=self.downline,pen="m") self.plotItem.addItem(self.curveOI3) # ---------------------------------------------------------------------- def sma(self, npArray, n, array=False): """簡單均線""" result = talib.SMA(npArray, n) if array: return result return result[-1] # ---------------------------------------------------------------------- def std(self, npArray, n, array=False): """標准差""" result = talib.STDDEV(npArray, n) if array: return result return result[-1] # ---------------------------------------------------------------------- def boll(self, npArray, n,m, dev, array=False): """布林通道""" mid = self.sma(npArray, n, array) std = self.std(npArray, m, array) up = mid + std * dev down = mid - std * dev return up, mid, down def updateIndicators(self): hourcloseArray = np.array(self.parent.listClose) N = self.setting_info["param"]["N"] M = self.setting_info["param"]["M"] P = self.setting_info["param"]["P"] up, mid,low = self.boll( hourcloseArray, N, M, P, True) self.curveOI1.setData(y=up,pen="y") self.curveOI2.setData(y=mid, pen="w") self.curveOI3.setData(y=low, pen="m") self.plotItem.addItem(self.curveOI1) self.plotItem.addItem(self.curveOI2) self.plotItem.addItem(self.curveOI3) self.base.indictatorsDatas[0]=up self.base.indictatorsDatas[1] = mid self.base.indictatorsDatas[2] = low self.base.indicatorsElements.append(self.curveOI1) self.base.indicatorsElements.append(self.curveOI2) self.base.indicatorsElements.append(self.curveOI3) def setIndicatorsData(self): #保存當前指標 self.base.name= self.indictorname self.base.className=self.setting_info["className"] self.base.plotItem=self.plotItem self.base.figure=self.figure self.base.indicatorsElements.append(self.curveOI1) self.base.indicatorsElements.append(self.curveOI2) self.base.indicatorsElements.append(self.curveOI3) self.base.indictatorsDatas.append(self.upperline) self.base.indictatorsDatas.append(self.midline) self.base.indictatorsDatas.append(self.downline) def getIndicatorsHtml(self,index): if len(self.base.indictatorsDatas)>0: if len(self.base.indictatorsDatas[0])>0: self.up=self.base.indictatorsDatas[0] self.mid=self.base.indictatorsDatas[1] self.down = self.base.indictatorsDatas[2] index = min(index, len(self.up) - 1) self.indicators_html = "BOLL:up=" + str(self.up[index]) + ",mid=" +str( self.mid[index]) + ",low=" +str(self.down[index]) return self.indicators_html def remove(self): for i in self.base.indicatorsElements: self.base.plotItem.removeItem(i) self.curveOI1 = None self.curveOI2 = None self.curveOI3 = None self.upperline = [] self.midline = [] self.downline = [] self.indicators_html="" self.name=""
周期切換代碼;
def initMenu(self): """初始化菜單""" # 創建菜單 menubar = self.menuBar() self.cycle = ["1min", "3min", "5min", "15min", "30min", "1H", "day"] n = 0 for item in self.cycle: action = QtWidgets.QAction(item, self) menubar.addAction(action) try: action.triggered[()].connect( lambda item=item: self.cycleAction(item))#一個空元組用於指定觸發的信號。如果沒有這樣做,觸發信號將在默認情況下發送一個布爾值,這將阻塞lambda的項目參數。 finally: pass
載入K線數據接口,使用pandas.DataFrame格式,支持全部載入和實時載入
#---------------------------------------------------------------------- def onBar(self, bar, nWindow = 20): """ 新增K線數據,K線播放模式 nWindow : 最大數據窗口 """ #---------------------------------------------------------------------- def loadData(self, datas): """ 載入pandas.DataFrame數據 datas : 數據格式,cols : datetime, open, close, low, high, volume, openInterest """
展示策略的技術指標和開平倉標記,開平倉標記通過listSig傳入
# ---------------------------------------------------------------------- def addSig(self, sig): """新增信號圖""" if sig in self.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()) # ---------------------------------------------------------------------- def showSig(self, datas): """刷新信號圖""" for sig in self.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] # ---------------------------------------------------------------------- def plotMark(self): """顯示開平倉信號""" # 檢查是否有數據 if len(self.datas) == 0: return for arrow in self.arrows: self.pwKL.removeItem(arrow) # 畫買賣信號 for i in range(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)
代碼較多,大家可以直接到GitHub下載開源源碼查看歡迎加入QQ交流群: 538665416(免費提供,期貨,期權數據)
