Python交互K線工具 K線核心功能+指標切換


Python交互K線工具 K線核心功能+指標切換

aiqtt 團隊量化研究,用vn.py回測和研究策略。基於vnpy開源代碼,剛開始接觸pyqt,開發界面還是很痛苦,找了很多案例參考,但並不能完全滿足我們自己對於檢查自己的交易邏輯的需求,只能參考網上的案例自己開發
代碼較多,大家可以直接到GitHub下載開源源碼查看
歡迎加入QQ交流群: 538665416(免費提供,期貨,期權數據)
團隊界面需求:
  1. 界面加載k線,
  2. 鼠標滾輪縮放,鍵盤縮放跳轉
  3. 十字光標 顯示K線詳細信息
  4. 縮放自適應Y軸坐標
  5. 回測完以后加載買賣開平倉位置有箭頭標記,並且通過鍵盤可以在標記之間跳轉
  6. 界面切換操作周期
  7. 界面右鍵可以切換指標  
  8. 分享部分核心代碼:
    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(免費提供,期貨,期權數據)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM