增加周线,修复MinuteBar的第2根Bar的bug

This commit is contained in:
msincenselee 2019-03-21 10:55:13 +08:00
parent 335aee7fc7
commit 42323087ee

View File

@ -25,6 +25,7 @@ PERIOD_SECOND = 'second' # 秒级别周期
PERIOD_MINUTE = 'minute' # 分钟级别周期 PERIOD_MINUTE = 'minute' # 分钟级别周期
PERIOD_HOUR = 'hour' # 小时级别周期 PERIOD_HOUR = 'hour' # 小时级别周期
PERIOD_DAY = 'day' # 日级别周期 PERIOD_DAY = 'day' # 日级别周期
PERIOD_WEEK = 'week' # 日级别周期
AREA_LONG_A = 'LONG_A' AREA_LONG_A = 'LONG_A'
AREA_LONG_B = 'LONG_B' AREA_LONG_B = 'LONG_B'
@ -242,6 +243,9 @@ class CtaLineBar(object):
self.paramList.append('inputSarAfLimit') self.paramList.append('inputSarAfLimit')
self.paramList.append('inputGoldenN') self.paramList.append('inputGoldenN')
self.paramList.append('activate_boll_ma_area') self.paramList.append('activate_boll_ma_area')
self.paramList.append('inputBiasLen')
self.paramList.append('inputBias2Len')
self.paramList.append('inputBias3Len')
self.paramList.append('is_7x24') self.paramList.append('is_7x24')
@ -540,6 +544,20 @@ class CtaLineBar(object):
self.cur_area = None self.cur_area = None
self.pre_area = None self.pre_area = None
# BIAS
self.inputBiasLen = EMPTY_INT
self.inputBias2Len = EMPTY_INT
self.inputBias3Len = EMPTY_INT
self.lineBias = [] # BIAS1
self.lineBias2 = [] # BIAS2
self.lineBias3 = [] # BIAS3
self.lastBias = EMPTY_FLOAT # bar内计算时最后一个未关闭的bar的实时BIAS1值
self.lastBias2 = EMPTY_FLOAT # bar内计算时最后一个未关闭的bar的实时BIAS2值
self.lastBias3 = EMPTY_FLOAT # bar内计算时最后一个未关闭的bar的实时BIAS3值
self._rt_Bias = None
self._rt_Bias2 = None
self._rt_Bias3 = None
# 存为Bar文件For TradeBlazer WJ # 存为Bar文件For TradeBlazer WJ
# filename = u'../TestLogs/rb1801_{}_Min.csv'.format(datetime.now().strftime('%m%d_%H%M')) # filename = u'../TestLogs/rb1801_{}_Min.csv'.format(datetime.now().strftime('%m%d_%H%M'))
# self.min1File = open(filename, mode='w') # self.min1File = open(filename, mode='w')
@ -595,6 +613,7 @@ class CtaLineBar(object):
def addBar(self, bar, bar_is_completed=False, bar_freq=1): def addBar(self, bar, bar_is_completed=False, bar_freq=1):
""" """
予以外部初始化程序增加bar 予以外部初始化程序增加bar
予以外部初始化程序增加bar
:param bar: :param bar:
:param bar_is_completed: 插入的bar其周期与K线周期一致就设为True :param bar_is_completed: 插入的bar其周期与K线周期一致就设为True
@ -714,6 +733,7 @@ class CtaLineBar(object):
self.__recountSar() self.__recountSar()
self.__recountGoldenSection() self.__recountGoldenSection()
self.__recountArea(bar) self.__recountArea(bar)
self.__recountBias()
self.export_to_csv(bar) self.export_to_csv(bar)
# 实时计算 # 实时计算
@ -851,18 +871,20 @@ class CtaLineBar(object):
if (self.inputBollLen > 0 or self.inputBollTBLen > 0) and len(self.lineUpperBand) > 0: if (self.inputBollLen > 0 or self.inputBollTBLen > 0) and len(self.lineUpperBand) > 0:
msg = msg + u',Boll({}):std:{},mid:{},up:{},low:{},Atan:[mid:{},up:{},low:{}]'. \ msg = msg + u',Boll({}):std:{},mid:{},up:{},low:{},Atan:[mid:{},up:{},low:{}]'. \
format(self.inputBollLen, round(self.lineUpperBand[-1], self.round_n), format(self.inputBollLen, round(self.lineBollStd[-1], self.round_n),
round(self.lineMiddleBand[-1], self.round_n), round(self.lineLowerBand[-1], self.round_n), round(self.lineMiddleBand[-1], self.round_n),
round(self.lineBollStd[-1], self.round_n), round(self.lineUpperBand[-1], self.round_n),
round(self.lineLowerBand[-1], self.round_n),
round(self.lineMiddleBandAtan[-1], 2) if len(self.lineMiddleBandAtan) > 0 else 0, round(self.lineMiddleBandAtan[-1], 2) if len(self.lineMiddleBandAtan) > 0 else 0,
round(self.lineUpperBandAtan[-1], 2) if len(self.lineUpperBandAtan) > 0 else 0, round(self.lineUpperBandAtan[-1], 2) if len(self.lineUpperBandAtan) > 0 else 0,
round(self.lineLowerBandAtan[-1], 2) if len(self.lineLowerBandAtan) > 0 else 0) round(self.lineLowerBandAtan[-1], 2) if len(self.lineLowerBandAtan) > 0 else 0)
if (self.inputBoll2Len > 0 or self.inputBoll2TBLen > 0) and len(self.lineUpperBand) > 0: if (self.inputBoll2Len > 0 or self.inputBoll2TBLen > 0) and len(self.lineUpperBand) > 0:
msg = msg + u',Boll2({0}):std:{4},m:{2},u:{1},l:{3}'. \ msg = msg + u',Boll2({}):std:{},m:{},u:{},l:{}'. \
format(self.inputBoll2Len, round(self.lineUpperBand2[-1], self.round_n), format(self.inputBoll2Len, round(self.lineBollStd[-1], self.round_n),
round(self.lineMiddleBand2[-1], self.round_n), round(self.lineLowerBand2[-1], self.round_n), round(self.lineMiddleBand2[-1], self.round_n),
round(self.lineBollStd[-1], self.round_n)) round(self.lineUpperBand2[-1], self.round_n),
round(self.lineLowerBand2[-1], self.round_n))
if self.inputMacdFastPeriodLen > 0 and len(self.lineDif) > 0: if self.inputMacdFastPeriodLen > 0 and len(self.lineDif) > 0:
msg = msg + u',MACD({0},{1},{2}):Dif:{3},Dea{4},Macd:{5}'. \ msg = msg + u',MACD({0},{1},{2}):Dif:{3},Dea{4},Macd:{5}'. \
@ -914,6 +936,19 @@ class CtaLineBar(object):
self.sar_count) self.sar_count)
if self.activate_boll_ma_area: if self.activate_boll_ma_area:
msg = msg + 'Area:{}'.format(self.cur_area) msg = msg + 'Area:{}'.format(self.cur_area)
if self.inputBiasLen > 0 and len(self.lineBias) > 0:
msg = msg + u',Bias({}):{}]'. \
format(self.inputBiasLen, round(self.lineBias[-1], self.round_n))
if self.inputBias2Len > 0 and len(self.lineBias2) > 0:
msg = msg + u',Bias2({}):{}]'. \
format(self.inputBias2Len, round(self.lineBias2[-1], self.round_n))
if self.inputBias3Len > 0 and len(self.lineBias3) > 0:
msg = msg + u',Bias3({}):{}]'. \
format(self.inputBias3Len, round(self.lineBias3[-1], self.round_n))
return msg return msg
def firstTick(self, tick): def firstTick(self, tick):
@ -3539,10 +3574,7 @@ class CtaLineBar(object):
:param:direction检查是否有顶背离检查是否有底背离 :param:direction检查是否有顶背离检查是否有底背离
:return: :return:
""" """
if len(self.lineSkTop) < 2 or len(self.lineSkButtom) < 2 : if len(self.lineSkTop) < 2 or len(self.lineSkButtom) < 2 or self._rt_SK is None or self._rt_SD is None:
return False
if runtime:
if self._rt_SK is None or self._rt_SD is None:
return False return False
t1 = self.lineSkTop[-1] t1 = self.lineSkTop[-1]
@ -3983,6 +4015,168 @@ class CtaLineBar(object):
self.cur_area = new_area self.cur_area = new_area
self.pre_area = last_area self.pre_area = last_area
def __recountBias(self):
"""乖离率"""
# BIAS1 : (CLOSE-MA(CLOSE,L1))/MA(CLOSE,L1)*100;
if not (self.inputBiasLen > EMPTY_INT or self.inputBias2Len > EMPTY_INT or
self.inputBias3Len > EMPTY_INT): # 不计算
return
l = len(self.lineBar)
if self.inputBiasLen > EMPTY_INT:
if l < min(6, self.inputBiasLen) + 1:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算Bias需要{1}'.
format(len(self.lineBar), min(14, self.inputBiasLen) + 1))
else:
if l < self.inputBiasLen + 2:
BiasLen = l - 1
else:
BiasLen = self.inputBiasLen
# 不包含当前最新的Bar
if self.mode == self.TICK_MODE:
listClose = [x.close for x in self.lineBar[-BiasLen-1:-1]]
else:
listClose = [x.close for x in self.lineBar[-BiasLen:]]
if len(self.lineBias) > self.inputBiasLen * 8:
del self.lineBias[0]
# 计算BIAS
m = np.mean(listClose)
bias = (listClose[-1] - m) / m * 100
self.lineBias.append(bias) # 中轨
self.lastBias = bias
l = len(self.lineBar)
if self.inputBias2Len > EMPTY_INT:
if l < min(6, self.inputBias2Len) + 1:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算Bias2需要{1}'.
format(len(self.lineBar), min(14, self.inputBias2Len) + 1))
else:
if l < self.inputBias2Len + 2:
Bias2Len = l - 1
else:
Bias2Len = self.inputBias2Len
# 不包含当前最新的Bar
if self.mode == self.TICK_MODE:
listClose = [x.close for x in self.lineBar[-Bias2Len-1:-1]]
else:
listClose = [x.close for x in self.lineBar[-Bias2Len:]]
if len(self.lineBias2) > self.inputBias2Len * 8:
del self.lineBias2[0]
# 计算BIAS2
m = np.mean(listClose)
bias2 = (listClose[-1] - m) / m * 100
self.lineBias2.append(bias2) # 中轨
self.lastBias2 = bias2
l = len(self.lineBar)
if self.inputBias3Len > EMPTY_INT:
if l < min(6, self.inputBias3Len) + 1:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算Bias3需要{1}'.
format(len(self.lineBar), min(14, self.inputBias3Len) + 1))
else:
if l < self.inputBias3Len + 2:
Bias3Len = l - 1
else:
Bias3Len = self.inputBias3Len
# 不包含当前最新的Bar
if self.mode == self.TICK_MODE:
listClose = [x.close for x in self.lineBar[-Bias3Len-1:-1]]
else:
listClose = [x.close for x in self.lineBar[-Bias3Len:]]
if len(self.lineBias3) > self.inputBias3Len * 8:
del self.lineBias3[0]
# 计算BIAS3
m = np.mean(listClose)
bias3 = (listClose[-1] - m) / m * 100
self.lineBias3.append(bias3) # 中轨
self.lastBias3 = bias3
def rt_countBias(self):
"""实时计算乖离率"""
if not (self.inputBiasLen > EMPTY_INT or self.inputBias2Len or self.inputBias3Len > EMPTY_INT): # 不计算
return
close_len = len(self.lineClose)
if self.inputBiasLen > EMPTY_INT:
if close_len < min(6, self.inputBiasLen) + 1:
return
else:
if close_len < self.inputBiasLen + 2:
biasLen = close_len - 1
else:
biasLen = self.inputBiasLen
listClose = [x.close for x in self.lineBar[-biasLen:]]
# 计算BIAS
m = np.mean(listClose)
self._rt_Bias = (listClose[-1] - m) / m * 100
if self.inputBias2Len > EMPTY_INT:
if close_len < min(6, self.inputBias2Len) + 1:
return
else:
if close_len < self.inputBias2Len + 2:
biasLen = close_len - 1
else:
biasLen = self.inputBias2Len
listClose = [x.close for x in self.lineBar[-biasLen:]]
# 计算BIAS
m = np.mean(listClose)
self._rt_Bias2 = (listClose[-1] - m) / m * 100
if self.inputBias3Len > EMPTY_INT:
if close_len < min(6, self.inputBias3Len) + 1:
return
else:
if close_len < self.inputBias3Len + 2:
biasLen = close_len - 1
else:
biasLen = self.inputBias3Len
listClose = [x.close for x in self.lineBar[-biasLen:]]
# 计算BIAS
m = np.mean(listClose)
self._rt_Bias3 = (listClose[-1] - m) / m * 100
def getRuntimeBias(self):
"""获取实时BIAS计算值"""
if self.rt_countBias in self.rt_funcs:
return self._rt_Bias, self._rt_Bias2, self._rt_Bias3
else:
self.writeCtaLog(u'getRuntimeBias(),添加rt_countBias到实时函数中')
self.rt_funcs.add(self.rt_countBias)
self.rt_countBias()
return self._rt_Bias, self._rt_Bias2, self._rt_Bias3
@property
def rt_Bias(self):
self.check_rt_funcs(self.rt_countBias)
return self._rt_Bias
@property
def rt_Bias2(self):
self.check_rt_funcs(self.rt_countBias)
return self._rt_Bias2
@property
def rt_Bias3(self):
self.check_rt_funcs(self.rt_countBias)
return self._rt_Bias3
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
def writeCtaLog(self, content): def writeCtaLog(self, content):
"""记录CTA日志""" """记录CTA日志"""
@ -4046,8 +4240,9 @@ class CtaLineBar(object):
dt_index = dict_fieldnames.index('datetime') dt_index = dict_fieldnames.index('datetime')
last_dt = self.get_csv_last_dt(file_name=file_name, dt_index=dt_index, last_dt = self.get_csv_last_dt(file_name=file_name, dt_index=dt_index,
line_length=sys.getsizeof(dict_data) / 8 + 1) line_length=sys.getsizeof(dict_data) / 8 + 1)
if last_dt is not None and dt <= last_dt: if last_dt is not None and dt < last_dt:
print(u'新增数据时间{}比最后一条记录时间{}早,不插入'.format(dt, last_dt)) print(u'新增数据时间{}比最后一条记录时间{}早,不插入'.format(dt, last_dt))
return return
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile: with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
@ -4269,6 +4464,11 @@ class CtaMinuteBar(CtaLineBar):
if bar_is_completed: if bar_is_completed:
# self.m1_bars_count = 0 # self.m1_bars_count = 0
self.onBar(bar) self.onBar(bar)
# 计算当前加入的 bar的1分钟属于当日的第几个1分钟
minutes_passed = (bar.datetime - datetime.strptime(bar.datetime.strftime('%Y-%m-%d'),
'%Y-%m-%d')).total_seconds() / 60
# 计算当前的bar属于当日的第几个bar
self.bars_count = int(minutes_passed / self.barTimeInterval)
return return
# 与最后一个BAR的时间比对判断是否超过K线的周期 # 与最后一个BAR的时间比对判断是否超过K线的周期
@ -4398,9 +4598,9 @@ class CtaMinuteBar(CtaLineBar):
# 不在同一交易日推入新bar # 不在同一交易日推入新bar
if self.curTradingDay != tick.tradingDay: if self.curTradingDay != tick.tradingDay:
self.writeCtaLog('{} drawLineBar() new_bar,{} curTradingDay:{},tick.tradingDay:{} bars_count={}' #self.writeCtaLog('{} drawLineBar() new_bar,{} curTradingDay:{},tick.tradingDay:{} bars_count={}'
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), self.curTradingDay, # .format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), self.curTradingDay,
tick.tradingDay, self.bars_count)) # tick.tradingDay, self.bars_count))
is_new_bar = True is_new_bar = True
self.curTradingDay = tick.tradingDay self.curTradingDay = tick.tradingDay
@ -4411,8 +4611,8 @@ class CtaMinuteBar(CtaLineBar):
if bars_passed != self.bars_count: if bars_passed != self.bars_count:
is_new_bar = True is_new_bar = True
self.bars_count = bars_passed self.bars_count = bars_passed
self.writeCtaLog('{} drawLineBar() new_bar,{} bars_count={}' #self.writeCtaLog('{} drawLineBar() new_bar,{} bars_count={}'
.format(self.name, tick.datetime, self.bars_count)) # .format(self.name, tick.datetime, self.bars_count))
self.last_minute = tick.datetime.minute self.last_minute = tick.datetime.minute
@ -4672,9 +4872,9 @@ class CtaHourBar(CtaLineBar):
tick.time = tick.datetime.strftime('%H:%M:%S') tick.time = tick.datetime.strftime('%H:%M:%S')
self.last_minute = tick.datetime.minute self.last_minute = tick.datetime.minute
self.curTradingDay = tick.tradingDay self.curTradingDay = tick.tradingDay
self.writeCtaLog('{} drawLineBar() new_bar,{} curTradingDay:{},tick.tradingDay:{}' #self.writeCtaLog('{} drawLineBar() new_bar,{} curTradingDay:{},tick.tradingDay:{}'
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), self.curTradingDay, # .format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), self.curTradingDay,
tick.tradingDay)) # tick.tradingDay))
else: else:
# 同一交易日,看分钟是否一致 # 同一交易日,看分钟是否一致
@ -4685,10 +4885,10 @@ class CtaHourBar(CtaLineBar):
if self.is_7x24: if self.is_7x24:
# 数字货币,用前后时间间隔 # 数字货币,用前后时间间隔
if (tick.datetime - lastBar.datetime).total_seconds() >= 3600 * self.barTimeInterval: if (tick.datetime - lastBar.datetime).total_seconds() >= 3600 * self.barTimeInterval:
self.writeCtaLog('{} drawLineBar() new_bar,{} - {} > 3600 * {} ' #self.writeCtaLog('{} drawLineBar() new_bar,{} - {} > 3600 * {} '
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), # .format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"),
lastBar.datetime.strftime("%Y-%m-%d %H:%M:%S"), # lastBar.datetime.strftime("%Y-%m-%d %H:%M:%S"),
self.barTimeInterval)) # self.barTimeInterval))
is_new_bar = True is_new_bar = True
# 去除分钟和秒数 # 去除分钟和秒数
tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:00:00'), '%Y-%m-%d %H:%M:%S') tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:00:00'), '%Y-%m-%d %H:%M:%S')
@ -4700,10 +4900,10 @@ class CtaHourBar(CtaLineBar):
else: else:
# 国内期货,用bar累加 # 国内期货,用bar累加
if self.m1_bars_count > 60 * self.barTimeInterval: if self.m1_bars_count > 60 * self.barTimeInterval:
self.writeCtaLog('{} drawLineBar() new_bar,{} {} > 60 * {} ' #self.writeCtaLog('{} drawLineBar() new_bar,{} {} > 60 * {} '
.format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"), # .format(self.name, tick.datetime.strftime("%Y-%m-%d %H:%M:%S"),
self.m1_bars_count, # self.m1_bars_count,
self.barTimeInterval)) # self.barTimeInterval))
is_new_bar = True is_new_bar = True
# 去除秒数 # 去除秒数
tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:%M:00'), '%Y-%m-%d %H:%M:%S') tick.datetime = datetime.strptime(tick.datetime.strftime('%Y-%m-%d %H:%M:00'), '%Y-%m-%d %H:%M:%S')
@ -4958,6 +5158,277 @@ class CtaDayBar(CtaLineBar):
self.lastTick = tick self.lastTick = tick
class CtaWeekBar(CtaLineBar):
"""
周线级别K线
"""
def __init__(self, strategy, onBarFunc, setting=None):
self.had_night_market = False # 是否有夜市
if 'period' in setting:
del setting['period']
if 'barTimeInterval' in setting:
del setting['barTimeInterval']
super(CtaWeekBar, self).__init__(strategy, onBarFunc, setting)
# 使用周一作为周线时间
self.use_monday = False
# 开始的小时/分钟/秒
self.bar_start_hour_dt = '21:00:00'
if self.is_7x24:
# 数字货币,使用周一的开始时间
self.use_monday = True
self.bar_start_hour_dt = '00:00:00'
else:
# 判断是否期货
if self.shortSymbol is not None:
if len(self.shortSymbol)<=4:
from vnpy.trader.vtFunction import getShortSymbol
# 是期货
if getShortSymbol(self.shortSymbol) in MARKET_DAY_ONLY:
# 日盘期货
self.use_monday = True
if getShortSymbol(self.shortSymbol) in MARKET_ZJ:
# 中金所
self.bar_start_hour_dt = '09:15:00'
else:
# 其他日盘期货
self.bar_start_hour_dt = '09:00:00'
else:
# 夜盘期货
self.use_monday = False
self.bar_start_hour_dt = '21:00:00'
else:
# 可能是股票
self.use_monday = True
self.bar_start_hour_dt = '09:30:00'
else:
# 可能是股票
self.use_monday = True
self.bar_start_hour_dt = '09:30:00'
def init_properties(self):
"""
初始化内部变量
:return:
"""
#self.paramList.append('barTimeInterval')
#self.paramList.append('period')
self.paramList.append('inputPreLen')
self.paramList.append('inputEma1Len')
self.paramList.append('inputEma2Len')
self.paramList.append('inputEma3Len')
self.paramList.append('inputMa1Len')
self.paramList.append('inputMa2Len')
self.paramList.append('inputMa3Len')
self.paramList.append('inputDmiLen')
self.paramList.append('inputDmiMax')
self.paramList.append('inputAtr1Len')
self.paramList.append('inputAtr2Len')
self.paramList.append('inputAtr3Len')
self.paramList.append('inputVolLen')
self.paramList.append('inputRsi1Len')
self.paramList.append('inputRsi2Len')
self.paramList.append('inputCmiLen')
self.paramList.append('inputBollLen')
self.paramList.append('inputBollTBLen')
self.paramList.append('inputBollStdRate')
self.paramList.append('inputBoll2Len')
self.paramList.append('inputBoll2TBLen')
self.paramList.append('inputBoll2StdRate')
self.paramList.append('inputKdjLen')
self.paramList.append('inputKdjTBLen')
self.paramList.append('inputKdjSlowLen')
self.paramList.append('inputKdjSmoothLen')
self.paramList.append('inputCciLen')
self.paramList.append('inputMacdFastPeriodLen')
self.paramList.append('inputMacdSlowPeriodLen')
self.paramList.append('inputMacdSignalPeriodLen')
self.paramList.append('inputKF')
self.paramList.append('inputSkd')
self.paramList.append('inputSkdLen1')
self.paramList.append('inputSkdLen2')
self.paramList.append('inputYb')
self.paramList.append('inputYbLen')
self.paramList.append('inputYbRef')
self.paramList.append('inputGoldenN')
self.paramList.append('activate_boll_ma_area')
self.paramList.append('is_7x24')
self.paramList.append('minDiff')
self.paramList.append('shortSymbol')
self.paramList.append('name')
# 输入参数
self.name = u'WeekBar'
self.mode = self.TICK_MODE # 缺省为tick模式
self.period = PERIOD_WEEK # 周线级别周期
self.barTimeInterval = 1 # 为1周
self.barMinuteInterval = 60 * 24 * 7
def addBar(self, bar, bar_is_completed=False, bar_freq=1):
"""
予以外部初始化程序增加bar
:param bar:
:param bar_is_completed: 插入的bar其周期与K线周期一致就设为True
:param bar_freq, bar对象得frequency
:return:
# 国内期货,周线时间开始为周五晚上21点
# 股票,周线开始时间为周一
# 数字货币,周线的开始时间为周一
"""
# 更新最后价格
self.cur_price = bar.close
l1 = len(self.lineBar)
if l1 == 0:
new_bar = copy.deepcopy(bar)
new_bar.datetime = self.get_bar_start_dt(bar.datetime)
self.writeCtaLog(u'周线开始时间:{}=>{}'.format(bar.datetime,new_bar.datetime))
self.lineBar.append(new_bar)
self.curTradingDay = bar.tradingDay if bar.tradingDay is not None else bar.date
if bar_is_completed:
self.onBar(bar)
return
# 与最后一个BAR的时间比对判断是否超过K线的周期
lastBar = self.lineBar[-1]
self.curTradingDay = bar.tradingDay if bar.tradingDay is not None else bar.date
is_new_bar = False
if bar_is_completed:
is_new_bar = True
# 时间判断,与上一根Bar的时间超过7天
if (bar.datetime - lastBar.datetime).total_seconds()>= 60*60*24*7:
is_new_bar = True
self.curTradingDay = bar.tradingDay if bar.tradingDay is not None else bar.date
if is_new_bar:
# 添加新的bar
new_bar = copy.deepcopy(bar)
new_bar.datetime = self.get_bar_start_dt(bar.datetime)
self.writeCtaLog(u'新周线开始时间:{}=>{}'.format(bar.datetime, new_bar.datetime))
self.lineBar.append(new_bar)
# 将上一个Bar推送至OnBar事件
self.onBar(lastBar)
else:
# 更新最后一个bar
# 此段代码针对一部分短周期生成长周期的k线更新如3根5分钟k线合并成1根15分钟k线。
lastBar.close = bar.close
lastBar.high = max(lastBar.high, bar.high)
lastBar.low = min(lastBar.low, bar.low)
lastBar.volume = lastBar.volume + bar.volume
lastBar.dayVolume = lastBar.volume
lastBar.mid3 = round((lastBar.close + lastBar.high + lastBar.low) / 3, self.round_n)
lastBar.mid4 = round((2 * lastBar.close + lastBar.high + lastBar.low) / 4, self.round_n)
lastBar.mid5 = round((2 * lastBar.close + lastBar.open + lastBar.high + lastBar.low) / 5, self.round_n)
# 实时计算
self.runtime_recount()
def get_bar_start_dt(self,cur_dt):
"""获取当前时间计算的周线Bar开始时间"""
if self.use_monday:
# 使用周一. 例如当前是周二weekday=1,相当于减去一天
monday_dt = cur_dt.replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(days=cur_dt.weekday())
start_dt = datetime.strptime(monday_dt.strftime('%Y-%m-%d')+' '+self.bar_start_hour_dt,'%Y-%m-%d %H:%M:%S')
return start_dt
else:
# 使用周五
week_day = cur_dt.weekday()
if week_day >= 5 or (week_day == 4 and cur_dt.hour > 20):
# 周六或周天; 或者周五晚上21:00以后
friday_dt = cur_dt.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=cur_dt.weekday()-4)
else:
# 周一~周五白天
friday_dt = cur_dt.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=cur_dt.weekday()+2)
friday_night_dt = datetime.strptime(friday_dt.strftime('%Y-%m-%d') + ' ' + self.bar_start_hour_dt,
'%Y-%m-%d %H:%M:%S')
return friday_night_dt
# ----------------------------------------------------------------------
def drawLineBar(self, tick):
"""
生成 line Bar
:param tick:
:return:
"""
l1 = len(self.lineBar)
# 保存第一个K线数据
if l1 == 0:
self.firstTick(tick)
return
# 清除480周期前的数据
if l1 > self.max_hold_bars:
del self.lineBar[0]
# 与最后一个BAR的时间比对判断是否超过K线周期
lastBar = self.lineBar[-1]
is_new_bar = False
# 交易日期不一致,新的交易日
if (tick.datetime - lastBar.datetime).total_seconds() >= 60 * 60 * 24 * 7:
is_new_bar = True
if is_new_bar:
# 创建并推入新的Bar
self.firstTick(tick)
# 触发OnBar事件
self.onBar(lastBar)
else:
# 更新当前最后一个bar
self.barFirstTick = False
# 更新最高价、最低价、收盘价、成交量
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:
# 针对第一个bar的tick volume更新
lastBar.volume = tick.volume
else:
lastBar.volume = tick.volume - self.lineBar[-2].dayVolume
# 更新Bar的颜色
if lastBar.close > lastBar.open:
lastBar.color = COLOR_RED
elif lastBar.close < lastBar.open:
lastBar.color = COLOR_BLUE
else:
lastBar.color = COLOR_EQUAL
# 实时计算
self.runtime_recount()
self.lastTick = tick
class test_strategy(object): class test_strategy(object):
def __init__(self): def __init__(self):
@ -4966,10 +5437,12 @@ class test_strategy(object):
self.shortSymbol = 'I' self.shortSymbol = 'I'
self.vtSymbol = 'I99' self.vtSymbol = 'I99'
self.lineM5 = None
self.lineM30 = None self.lineM30 = None
self.lineH1 = None self.lineH1 = None
self.lineH2 = None self.lineH2 = None
self.lineD = None self.lineD = None
self.lineW = None
self.TMinuteInterval = 1 self.TMinuteInterval = 1
@ -4978,6 +5451,20 @@ class test_strategy(object):
self.save_h2_bars = [] self.save_h2_bars = []
self.save_d_bars = [] self.save_d_bars = []
self.save_w_bars = []
def createM5(self):
lineM5Setting = {}
lineM5Setting['name'] = u'M5'
lineM5Setting['period'] = PERIOD_MINUTE
lineM5Setting['barTimeInterval'] =5
lineM5Setting['mode'] = CtaLineBar.TICK_MODE
lineM5Setting['minDiff'] = self.minDiff
lineM5Setting['shortSymbol'] = self.shortSymbol
self.lineM5 = CtaMinuteBar(self, self.onBarM5, lineM5Setting)
def onBarM5(self,bar):
self.writeCtaLog(self.lineM5.displayLastBar())
def createlineM30_with_macd(self): def createlineM30_with_macd(self):
# 创建M30 K线 # 创建M30 K线
lineM30Setting = {} lineM30Setting = {}
@ -5081,8 +5568,26 @@ class test_strategy(object):
lineDaySetting['shortSymbol'] = self.shortSymbol lineDaySetting['shortSymbol'] = self.shortSymbol
self.lineD = CtaDayBar(self, self.onBarD, lineDaySetting) self.lineD = CtaDayBar(self, self.onBarD, lineDaySetting)
def createLineW(self):
"""创建周线"""
lineWeekSetting = {}
lineWeekSetting['name'] = u'W1'
lineWeekSetting['inputPreLen'] = 5
lineWeekSetting['inputAtr1Len'] = 26
lineWeekSetting['inputMa1Len'] = 5
lineWeekSetting['inputMa2Len'] = 10
lineWeekSetting['inputMa3Len'] = 18
lineWeekSetting['inputYb'] = True
lineWeekSetting['inputSkd'] = True
lineWeekSetting['mode'] = CtaDayBar.TICK_MODE
lineWeekSetting['minDiff'] = self.minDiff
lineWeekSetting['shortSymbol'] = self.shortSymbol
self.lineW = CtaWeekBar(self, self.onBarW, lineWeekSetting)
def onBar(self, bar): def onBar(self, bar):
# print(u'tradingDay:{},dt:{},o:{},h:{},l:{},c:{},v:{}'.format(bar.tradingDay,bar.datetime, bar.open, bar.high, bar.low, bar.close, bar.volume)) # print(u'tradingDay:{},dt:{},o:{},h:{},l:{},c:{},v:{}'.format(bar.tradingDay,bar.datetime, bar.open, bar.high, bar.low, bar.close, bar.volume))
if self.lineW:
self.lineW.addBar(bar, bar_freq=self.TMinuteInterval)
if self.lineD: if self.lineD:
self.lineD.addBar(bar, bar_freq=self.TMinuteInterval) self.lineD.addBar(bar, bar_freq=self.TMinuteInterval)
if self.lineH2: if self.lineH2:
@ -5094,6 +5599,9 @@ class test_strategy(object):
if self.lineM30: if self.lineM30:
self.lineM30.addBar(bar, bar_freq=self.TMinuteInterval) self.lineM30.addBar(bar, bar_freq=self.TMinuteInterval)
if self.lineM5:
self.lineM5.addBar(bar,bar_freq=self.TMinuteInterval)
# if self.lineH2: # if self.lineH2:
# self.lineH2.skd_is_high_dead_cross(runtime=True, high_skd=30) # self.lineH2.skd_is_high_dead_cross(runtime=True, high_skd=30)
# self.lineH2.skd_is_low_golden_cross(runtime=True, low_skd=70) # self.lineH2.skd_is_low_golden_cross(runtime=True, low_skd=70)
@ -5173,6 +5681,25 @@ class test_strategy(object):
'sd': self.lineD.lineSD[-1] if len(self.lineD.lineSD) > 0 else 0 'sd': self.lineD.lineSD[-1] if len(self.lineD.lineSD) > 0 else 0
}) })
def onBarW(self, bar):
self.writeCtaLog(self.lineW.displayLastBar())
self.save_w_bars.append({
'datetime': bar.datetime,
'open': bar.open,
'high': bar.high,
'low': bar.low,
'close': bar.close,
'turnover': 0,
'volume': bar.volume,
'openInterest': 0,
'ma5': self.lineW.lineMa1[-1] if len(self.lineW.lineMa1) > 0 else bar.close,
'ma10': self.lineW.lineMa2[-1] if len(self.lineW.lineMa2) > 0 else bar.close,
'ma18': self.lineW.lineMa3[-1] if len(self.lineW.lineMa3) > 0 else bar.close,
'sk': self.lineW.lineSK[-1] if len(self.lineW.lineSK) > 0 else 0,
'sd': self.lineW.lineSD[-1] if len(self.lineW.lineSD) > 0 else 0
})
def onTick(self, tick): def onTick(self, tick):
print(u'{0},{1},ap:{2},av:{3},bp:{4},bv:{5}'.format(tick.datetime, tick.lastPrice, tick.askPrice1, print(u'{0},{1},ap:{2},av:{3},bp:{4},bv:{5}'.format(tick.datetime, tick.lastPrice, tick.askPrice1,
tick.askVolume1, tick.bidPrice1, tick.bidVolume1)) tick.askVolume1, tick.bidPrice1, tick.bidVolume1))
@ -5185,7 +5712,7 @@ class test_strategy(object):
if len(self.save_m30_bars) > 0: if len(self.save_m30_bars) > 0:
outputFile = '{}_m30.csv'.format(self.vtSymbol) outputFile = '{}_m30.csv'.format(self.vtSymbol)
with open(outputFile, 'w', encoding='utf8', newline='') as f: with open(outputFile, 'w', encoding='utf8', newline='') as f:
fieldnames = ['datetime', 'open', 'price', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest', fieldnames = ['datetime', 'open', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest',
'ma5', 'ma10', 'ma18', 'sk', 'sd'] 'ma5', 'ma10', 'ma18', 'sk', 'sd']
writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel') writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel')
writer.writeheader() writer.writeheader()
@ -5195,7 +5722,7 @@ class test_strategy(object):
if len(self.save_h1_bars) > 0: if len(self.save_h1_bars) > 0:
outputFile = '{}_h1.csv'.format(self.vtSymbol) outputFile = '{}_h1.csv'.format(self.vtSymbol)
with open(outputFile, 'w', encoding='utf8', newline='') as f: with open(outputFile, 'w', encoding='utf8', newline='') as f:
fieldnames = ['datetime', 'open', 'price', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest', fieldnames = ['datetime', 'open', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest',
'ma5', 'ma10', 'ma18', 'sk', 'sd'] 'ma5', 'ma10', 'ma18', 'sk', 'sd']
writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel') writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel')
writer.writeheader() writer.writeheader()
@ -5205,7 +5732,7 @@ class test_strategy(object):
if len(self.save_h2_bars) > 0: if len(self.save_h2_bars) > 0:
outputFile = '{}_h2.csv'.format(self.vtSymbol) outputFile = '{}_h2.csv'.format(self.vtSymbol)
with open(outputFile, 'w', encoding='utf8', newline='') as f: with open(outputFile, 'w', encoding='utf8', newline='') as f:
fieldnames = ['datetime', 'open', 'price', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest', fieldnames = ['datetime', 'open', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest',
'ma5', 'ma10', 'ma18', 'sk', 'sd'] 'ma5', 'ma10', 'ma18', 'sk', 'sd']
writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel') writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel')
writer.writeheader() writer.writeheader()
@ -5215,20 +5742,33 @@ class test_strategy(object):
if len(self.save_d_bars) > 0: if len(self.save_d_bars) > 0:
outputFile = '{}_d.csv'.format(self.vtSymbol) outputFile = '{}_d.csv'.format(self.vtSymbol)
with open(outputFile, 'w', encoding='utf8', newline='') as f: with open(outputFile, 'w', encoding='utf8', newline='') as f:
fieldnames = ['datetime', 'open', 'price', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest', fieldnames = ['datetime', 'open', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest',
'ma5', 'ma10', 'ma18', 'sk', 'sd'] 'ma5', 'ma10', 'ma18', 'sk', 'sd']
writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel') writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel')
writer.writeheader() writer.writeheader()
for row in self.save_d_bars: for row in self.save_d_bars:
writer.writerow(row) writer.writerow(row)
if len(self.save_w_bars) > 0:
outputFile = '{}_w.csv'.format(self.vtSymbol)
with open(outputFile, 'w', encoding='utf8', newline='') as f:
fieldnames = ['datetime', 'open', 'high', 'low', 'close', 'turnover', 'volume', 'openInterest',
'ma5', 'ma10', 'ma18', 'sk', 'sd']
writer = csv.DictWriter(f=f, fieldnames=fieldnames, dialect='excel')
writer.writeheader()
for row in self.save_w_bars:
writer.writerow(row)
if __name__ == '__main__': if __name__ == '__main__':
t = test_strategy() t = test_strategy()
t.minDiff = 1 t.minDiff = 0.5
t.shortSymbol = 'AP' t.shortSymbol = 'J'
t.vtSymbol = 'AP99' t.vtSymbol = 'J99'
t.createlineM30_with_macd()
t.createM5()
#t.createLineW()
#t.createlineM30_with_macd()
# 创建M30线 # 创建M30线
#t.createLineM30() #t.createLineM30()
@ -5242,7 +5782,7 @@ if __name__ == '__main__':
# 回测日线 # 回测日线
# t.createLineD() # t.createLineD()
filename = 'cache/{}_20170901_20181130_1m.csv'.format(t.vtSymbol) filename = 'cache/{}_20141201_20171231_1m.csv'.format(t.vtSymbol)
barTimeInterval = 60 # 60秒 barTimeInterval = 60 # 60秒
minDiff = 1 # 回测数据的最小跳动 minDiff = 1 # 回测数据的最小跳动