自适应均线系统 python_Python交互K线工具(K线核心功能+指标切换)

右键菜单加载指标代码:

###加载指标

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)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值