右键菜单加载指标代码:
###加载指标
def contextMenuEvent(self,ev):
"""打开指标窗口"""
CustomMenu(self.parent)
IndicatorsFunManage.py代码
# 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())
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)
代码较多,大家可以直接到GitHubaiqtt (aiqtt)# ----------------------------------------------------------------------
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)