增加TICK_MODE和BAR_MODE,支持回测。

This commit is contained in:
msincenselee 2016-09-30 08:50:24 +08:00
parent c9fcaadab3
commit dec9cd0299

View File

@ -39,6 +39,12 @@ class CtaLineBar(object):
"""
# 区别:
# -使用tick模式时当tick到达后最新一个lineBar[-1]是当前的正在拟合的bar不断累积tick传统按照OnBar来计算的话是使用LineBar[-2]。
# -使用bar模式时当一个bar到达时lineBar[-1]是当前生成出来的Bar,不再更新
TICK_MODE = 'tick'
BAR_MODE = 'bar'
# 参数列表,保存了参数的名称
paramList = ['vtSymbol']
@ -52,6 +58,8 @@ class CtaLineBar(object):
self.paramList.append('inputPreLen')
self.paramList.append('inputEma1Len')
self.paramList.append('inputEma2Len')
self.paramList.append('inputMa1Len')
self.paramList.append('inputMa2Len')
self.paramList.append('inputDmiLen')
self.paramList.append('inputDmiMax')
self.paramList.append('inputAtr1Len')
@ -75,10 +83,16 @@ class CtaLineBar(object):
# 输入参数
self.name = u'LineBar'
self.mode = self.TICK_MODE
self.barTimeInterval = 300
self.inputPreLen = EMPTY_INT #1
self.inputMa1Len = EMPTY_INT # 60
self.inputMa2Len = EMPTY_INT # 240
self.inputEma1Len = EMPTY_INT # 13
self.inputEma2Len = EMPTY_INT # 21
@ -115,10 +129,14 @@ class CtaLineBar(object):
self.preHigh = [] # K线的前inputPreLen的的最高
self.preLow = [] # K线的前inputPreLen的的最低
self.lineEma1 = [] # K线的EMA1均线周期是InputEmaLen1包含当前bar
self.lineMa1 = [] # K线的MA1均线周期是InputMaLen1不包含当前bar
self.lineMa2 = [] # K线的MA2均线周期是InputMaLen2不包含当前bar
self.lineEma1 = [] # K线的EMA1均线周期是InputEmaLen1不包含当前bar
self.lineEma1MtmRate = [] # K线的EMA1均线 的momentum(3) 动能
self.lineEma2 = [] # K线的EMA2均线周期是InputEmaLen2包含当前bar
self.lineEma2 = [] # K线的EMA2均线周期是InputEmaLen2包含当前bar
self.lineEma2MtmRate = [] # K线的EMA2均线 的momentum(3) 动能
# K线的DMI( PdiMdiADXAdxr) 计算数据
@ -202,6 +220,10 @@ class CtaLineBar(object):
d[key] = setting[key]
def setMode(self,mode):
"""Tick/Bar模式"""
self.mode = mode
def onTick(self, tick):
"""行情更新
:type tick: object
@ -247,6 +269,7 @@ class CtaLineBar(object):
"""OnBar事件"""
# 计算相关数据
self.__recountPreHighLow()
self.__recountMa()
self.__recountEma()
self.__recountDmi()
self.__recountAtr()
@ -261,14 +284,25 @@ class CtaLineBar(object):
def displayLastBar(self):
"""显示最后一个Bar的信息"""
msg = self.name
msg = u'['+self.name+u']'
if self.mode == self.TICK_MODE:
displayBar = self.lineBar[-2]
else:
displayBar = self.lineBar[-1]
if len(self.lineBar) < 2:
return msg
msg = msg + u'{0} o:{1};h{2};l:{3};c:{4},v:{5}'.\
format(self.lineBar[-2].datetime, self.lineBar[-2].open, self.lineBar[-2].high,
self.lineBar[-2].low, self.lineBar[-2].close, self.lineBar[-2].volume)
format(displayBar.datetime, displayBar.open, displayBar.high,
displayBar.low, displayBar.close, displayBar.volume)
if self.inputMa1Len > 0 and len(self.lineMa1) > 0:
msg = msg + u',MA({0}):{1}'.format(self.inputMa1Len, self.lineMa1[-1])
if self.inputMa2Len > 0 and len(self.lineMa2) > 0:
msg = msg + u',MA({0}):{1}'.format(self.inputMa2Len, self.lineMa2[-1])
if self.inputEma1Len > 0 and len(self.lineEma1) > 0:
msg = msg + u',EMA({0}):{1}'.format(self.inputEma1Len, self.lineEma1[-1])
@ -469,7 +503,12 @@ class CtaLineBar(object):
preHigh = EMPTY_FLOAT
preLow = EMPTY_FLOAT
for i in range(len(self.lineBar)-2, len(self.lineBar)-2-self.inputPreLen, -1):
if self.mode == self.TICK_MODE:
idx = 2
else:
idx = 1
for i in range(len(self.lineBar)-idx, len(self.lineBar)-idx-self.inputPreLen, -1):
if self.lineBar[i].high > preHigh or preHigh == EMPTY_FLOAT:
preHigh = self.lineBar[i].high # 前InputPreLen周期高点
@ -488,8 +527,61 @@ class CtaLineBar(object):
self.preLow.append(preLow)
#----------------------------------------------------------------------
def __recountMa(self):
"""计算K线的MA1 和MA2"""
l = len(self.lineBar)
# 1、lineBar满足长度才执行计算
if len(self.lineBar) < max(7, self.inputMa1Len, self.inputMa2Len)+2:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算MA需要{1}'.
format(len(self.lineBar), max(7, self.inputMa1Len, self.inputMa2Len)+2))
return
# 计算第一条MA均线
if self.inputMa1Len > 0:
if self.inputMa1Len > l:
ma1Len = l
else:
ma1Len = self.inputMa1Len
# 3、获取前InputN周期(不包含当前周期的K线
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-ma1Len - 1:-1]]
else:
listClose=[x.close for x in self.lineBar[-ma1Len:]]
barMa1 = ta.MA(numpy.array(listClose, dtype=float), ma1Len)[-1]
barMa1 = round(float(barMa1), 3)
if len(self.lineMa1) > self.inputMa1Len*8:
del self.lineMa1[0]
self.lineMa1.append(barMa1)
# 计算第二条MA均线
if self.inputMa2Len > 0:
if self.inputMa2Len > l:
ma2Len = l
else:
ma2Len = self.inputMa2Len
# 3、获取前InputN周期(不包含当前周期的K线
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-ma2Len - 1:-1]]
else:
listClose=[x.close for x in self.lineBar[-ma2Len:]]
barMa2 = ta.MA(numpy.array(listClose, dtype=float), ma2Len)[-1]
barMa2 = round(float(barMa2), 3)
if len(self.lineMa2) > self.inputMa2Len*8:
del self.lineMa2[0]
self.lineMa2.append(barMa2)
#----------------------------------------------------------------------
def __recountEma(self):
"""计算K线的EMA1 和EMA2"""
l = len(self.lineBar)
@ -508,8 +600,11 @@ class CtaLineBar(object):
else:
ema1Len = self.inputEma1Len
# 3、获取前InputN周期(不包含当前周期)的自适应均线
# 3、获取前InputN周期(不包含当前周期的K线
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-ema1Len - 1:-1]]
else:
listClose=[x.close for x in self.lineBar[-ema1Len:]]
barEma1 = ta.EMA(numpy.array(listClose, dtype=float), ema1Len)[-1]
@ -528,7 +623,11 @@ class CtaLineBar(object):
ema2Len = self.inputEma2Len
# 3、获取前InputN周期(不包含当前周期)的自适应均线
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-ema2Len - 1:-1]]
else:
listClose=[x.close for x in self.lineBar[-ema2Len:]]
barEma2 = ta.EMA(numpy.array(listClose, dtype=float), ema2Len)[-1]
barEma2 = round(float(barEma2), 3)
@ -555,7 +654,12 @@ class CtaLineBar(object):
barPdm = EMPTY_FLOAT # InputP周期内的做多价差之和
barMdm = EMPTY_FLOAT # InputP周期内的做空价差之和
for i in range(len(self.lineBar)-2, len(self.lineBar)-2-self.inputDmiLen, -1): # 周期 inputDmiLen
if self.mode == self.TICK_MODE:
idx = 2
else:
idx = 1
for i in range(len(self.lineBar)-idx, len(self.lineBar)-idx-self.inputDmiLen, -1): # 周期 inputDmiLen
# 3.1、计算TR1
# 当前周期最高与最低的价差
@ -686,6 +790,11 @@ class CtaLineBar(object):
format(len(self.lineBar), maxAtrLen+1))
return
if self.mode == self.TICK_MODE:
idx = 2
else:
idx = 1
# 首次计算
if (self.inputAtr1Len > 0 and len(self.lineAtr1) < 1) \
or (self.inputAtr2Len > 0 and len(self.lineAtr2) < 1) \
@ -697,7 +806,8 @@ class CtaLineBar(object):
barTr3 = EMPTY_FLOAT # 获取inputAtr3Len周期内的价差最大值之和
j = 0
for i in range(len(self.lineBar)-2, len(self.lineBar)-2-maxAtrLen, -1): # 周期 inputP
for i in range(len(self.lineBar)-idx, len(self.lineBar)-idx-maxAtrLen, -1): # 周期 inputP
# 3.1、计算TR
# 当前周期最高与最低的价差
@ -721,11 +831,11 @@ class CtaLineBar(object):
else: # 只计算一个
# 当前周期最高与最低的价差
high_low_spread = self.lineBar[-2].high - self.lineBar[-2].low
high_low_spread = self.lineBar[0-idx].high - self.lineBar[0-idx].low
# 当前周期最高与昨收价的价差
high_preclose_spread = abs(self.lineBar[-2].high - self.lineBar[-3].close)
high_preclose_spread = abs(self.lineBar[0-idx].high - self.lineBar[-1-idx].close)
# 当前周期最低与昨收价的价差
low_preclose_spread = abs(self.lineBar[-2].low - self.lineBar[-3].close)
low_preclose_spread = abs(self.lineBar[0-idx].low - self.lineBar[-1-idx].close)
# 最大价差
barTr1 = max(high_low_spread, high_preclose_spread, low_preclose_spread)
@ -777,7 +887,10 @@ class CtaLineBar(object):
format(len(self.lineBar), self.inputVolLen+1))
return
if self.mode == self.TICK_MODE:
listVol = [x.volume for x in self.lineBar[-self.inputVolLen-1: -1]]
else:
listVol = [x.volume for x in self.lineBar[-self.inputVolLen:]]
sumVol = ta.SUM(numpy.array(listVol, dtype=float), timeperiod=self.inputVolLen)[-1]
@ -801,7 +914,11 @@ class CtaLineBar(object):
# 计算第1根RSI曲线
# 3、inputRsi1Len(包含当前周期)的相对强弱
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-self.inputRsi1Len - 2:-1]]
else:
listClose=[x.close for x in self.lineBar[-self.inputRsi1Len-1:]]
barRsi = ta.RSI(numpy.array(listClose, dtype=float), self.inputRsi1Len)[-1]
barRsi = round(float(barRsi), 3)
@ -846,7 +963,11 @@ class CtaLineBar(object):
if len(self.lineBar) < self.inputRsi2Len+2:
return
listClose=[x.close for x in self.lineBar[-self.inputRsi2Len - 2:]]
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-self.inputRsi2Len - 2:-1]]
else:
listClose=[x.close for x in self.lineBar[-self.inputRsi2Len - 1:]]
barRsi = ta.RSI(numpy.array(listClose, dtype=float), self.inputRsi2Len)[-1]
barRsi = round(float(barRsi), 3)
@ -876,14 +997,20 @@ class CtaLineBar(object):
format(len(self.lineBar), self.inputCmiLen))
return
listClose =[x.close for x in self.lineBar[-self.inputCmiLen:-1]]
if self.mode == self.TICK_MODE:
listClose =[x.close for x in self.lineBar[-self.inputCmiLen-1:-1]]
idx = 2
else:
listClose =[x.close for x in self.lineBar[-self.inputCmiLen:]]
idx = 1
hhv = max(listClose)
llv = min(listClose)
if hhv==llv:
cmi = 100
else:
cmi = abs(self.lineBar[-1].close-self.lineBar[-2].close)*100/(hhv-llv)
cmi = abs(self.lineBar[0-idx].close-self.lineBar[-1-idx].close)*100/(hhv-llv)
cmi = round(cmi, 2)
@ -909,7 +1036,10 @@ class CtaLineBar(object):
bollLen = self.inputBollLen
# 不包含当前最新的Bar
if self.mode == self.TICK_MODE:
listClose=[x.close for x in self.lineBar[-bollLen - 1:-1]]
else:
listClose=[x.close for x in self.lineBar[-bollLen :]]
#
upper, middle, lower = ta.BBANDS(numpy.array(listClose, dtype=float),
timeperiod=bollLen, nbdevup=self.inputBollStdRate,
@ -950,7 +1080,11 @@ class CtaLineBar(object):
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算KDJ需要{1}'.format(len(self.lineBar), self.inputKdjLen+1))
return
listClose =[x.close for x in self.lineBar[-self.inputKdjLen:-1]]
if self.mode == self.TICK_MODE:
listClose =[x.close for x in self.lineBar[-self.inputKdjLen-1:-1]]
else:
listClose =[x.close for x in self.lineBar[-self.inputKdjLen:]]
hhv = max(listClose)
llv = min(listClose)
@ -996,8 +1130,8 @@ class CtaLineBar(object):
差离值DIF的计算 DIF = EMA12 - EMA26即为talib-MACD返回值macd
根据差离值计算其9日的EMA即离差平均值是所求的DEA值
今日DEA = 前一日DEA X 8/10 + 今日DIF X 2/10即为talib-MACD返回值signal
DIF与它自己的移动平均之间差距的大小一般BAR=DIF-DEA)2即为MACD柱状图
但是talib中MACD的计算是bar = (dif-dea)1
DIF与它自己的移动平均之间差距的大小一般BAR=DIF-DEA)*2即为MACD柱状图
但是talib中MACD的计算是bar = (dif-dea)*1
"""
@ -1005,17 +1139,26 @@ class CtaLineBar(object):
if self.inputMacdSlowPeriodLen <= EMPTY_INT: return
if self.inputMacdSignalPeriodLen <= EMPTY_INT: return
maxLen = max(self.inputMacdFastPeriodLen,self.inputMacdSlowPeriodLen)+self.inputMacdSignalPeriodLen
maxLen = max(self.inputMacdFastPeriodLen,self.inputMacdSlowPeriodLen)+self.inputMacdSignalPeriodLen+1
maxLen = maxLen * 3 # 注数据长度需要足够才能准确。测试过3倍长度才可以与国内的文华等软件一致
if len(self.lineBar) < maxLen:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算MACD需要{1}'.format(len(self.lineBar), maxLen))
return
if self.mode == self.TICK_MODE:
listClose =[x.close for x in self.lineBar[-maxLen:-1]]
else:
listClose =[x.close for x in self.lineBar[-maxLen-1:]]
dif, dea, macd = ta.MACD(numpy.array(listClose, dtype=float), fastperiod=self.inputMacdFastPeriodLen,
slowperiod=self.inputMacdSlowPeriodLen, signalperiod=self.inputMacdSignalPeriodLen)
#dif, dea, macd = ta.MACDEXT(numpy.array(listClose, dtype=float),
# fastperiod=self.inputMacdFastPeriodLen, fastmatype=1,
# slowperiod=self.inputMacdSlowPeriodLen, slowmatype=1,
# signalperiod=self.inputMacdSignalPeriodLen, signalmatype=1)
if len(self.lineDif) > maxLen:
del self.lineDif[0]
@ -1027,7 +1170,7 @@ class CtaLineBar(object):
if len(self.lineMacd) > maxLen:
del self.lineMacd[0]
self.lineMacd.append(macd[-1]*2)
self.lineMacd.append(macd[-1]*2) # 国内一般是2倍
# ----------------------------------------------------------------------
def writeCtaLog(self, content):