[Add]实现K线合成器功能,自动管理合成K线相关的逻辑
This commit is contained in:
parent
eba153f3da
commit
553cf002d8
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@ from vnpy.trader.app.ctaStrategy.ctaBacktesting import BacktestingEngine, MINUTE
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from vnpy.trader.app.ctaStrategy.strategy.strategyAtrRsi import AtrRsiStrategy
|
||||
from vnpy.trader.app.ctaStrategy.strategy.strategyKingKeltner import KkStrategy
|
||||
|
||||
# 创建回测引擎
|
||||
engine = BacktestingEngine()
|
||||
@ -32,8 +32,8 @@ if __name__ == '__main__':
|
||||
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
|
||||
|
||||
# 在引擎中创建策略对象
|
||||
d = {'atrLength': 11}
|
||||
engine.initStrategy(AtrRsiStrategy, d)
|
||||
d = {}
|
||||
engine.initStrategy(KkStrategy, d)
|
||||
|
||||
# 开始跑回测
|
||||
engine.runBacktesting()
|
||||
|
@ -5,8 +5,9 @@
|
||||
'''
|
||||
|
||||
from vnpy.trader.vtConstant import *
|
||||
from vnpy.trader.vtObject import VtBarData
|
||||
|
||||
from vnpy.trader.app.ctaStrategy.ctaBase import *
|
||||
from .ctaBase import *
|
||||
|
||||
|
||||
########################################################################
|
||||
@ -302,4 +303,117 @@ class TargetPosTemplate(CtaTemplate):
|
||||
else:
|
||||
vtOrderID = self.short(shortPrice, abs(posChange))
|
||||
self.orderList.append(vtOrderID)
|
||||
|
||||
|
||||
########################################################################
|
||||
class BarManager(object):
|
||||
"""
|
||||
K线合成器,支持:
|
||||
1. 基于Tick合成1分钟K线
|
||||
2. 基于1分钟K线合成X分钟K线(X可以是2、3、5、10、15、30、60)
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, onBar, xmin=0, onXminBar=None):
|
||||
"""Constructor"""
|
||||
self.bar = None # 1分钟K线对象
|
||||
self.onBar = onBar # 1分钟K线回调函数
|
||||
|
||||
self.xminBar = None # X分钟K线对象
|
||||
self.xmin = xmin # X的值
|
||||
self.onXminBar = onXminBar # X分钟K线的回调函数
|
||||
|
||||
self.lastTick = None # 上一TICK缓存对象
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def updateTick(self, tick):
|
||||
"""TICK更新"""
|
||||
newMinute = False # 默认不是新的一分钟
|
||||
|
||||
# 尚未创建对象
|
||||
if not self.bar:
|
||||
self.bar = VtBarData()
|
||||
newMinute = True
|
||||
# 新的一分钟
|
||||
elif self.bar.datetime.minute != tick.datetime.minute:
|
||||
# 生成上一分钟K线的时间戳
|
||||
self.bar.datetime = self.bar.datetime.replace(second=0, microsecond=0) # 将秒和微秒设为0
|
||||
self.bar.date = self.bar.datetime.strftime('%Y%m%d')
|
||||
self.bar.time = self.bar.datetime.strftime('%H:%M:%S.%f')
|
||||
|
||||
# 推送已经结束的上一分钟K线
|
||||
self.onBar(self.bar)
|
||||
|
||||
# 创建新的K线对象
|
||||
self.bar = VtBarData()
|
||||
newMinute = True
|
||||
|
||||
# 初始化新一分钟的K线数据
|
||||
if newMinute:
|
||||
self.bar.vtSymbol = tick.vtSymbol
|
||||
self.bar.symbol = tick.symbol
|
||||
self.bar.exchange = tick.exchange
|
||||
|
||||
self.bar.open = tick.lastPrice
|
||||
self.bar.high = tick.lastPrice
|
||||
self.bar.low = tick.lastPrice
|
||||
# 累加更新老一分钟的K线数据
|
||||
else:
|
||||
self.bar.high = max(self.bar.high, tick.lastPrice)
|
||||
self.bar.low = min(self.bar.low, tick.lastPrice)
|
||||
|
||||
# 通用更新部分
|
||||
self.bar.close = tick.lastPrice
|
||||
self.bar.datetime = tick.datetime
|
||||
self.bar.openInterest = tick.openInterest
|
||||
|
||||
if self.lastTick:
|
||||
self.bar.volume += (tick.volume - self.lastTick.volume) # 当前K线内的成交量
|
||||
|
||||
# 缓存Tick
|
||||
self.lastTick = tick
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def updateBar(self, bar):
|
||||
"""1分钟K线更新"""
|
||||
newX = False # 默认不是新的X分钟
|
||||
|
||||
# 尚未创建对象
|
||||
if not self.xminBar:
|
||||
self.xminBar = VtBarData()
|
||||
newX = True
|
||||
# X分钟已经走完
|
||||
elif not bar.datetime.minute % self.xmin: # 可以用X整除
|
||||
# 生成上一X分钟K线的时间戳
|
||||
self.xminBar.datetime = self.xminBar.datetime.replace(second=0, microsecond=0) # 将秒和微秒设为0
|
||||
self.xminBar.date = self.xminBar.datetime.strftime('%Y%m%d')
|
||||
self.xminBar.time = self.xminBar.datetime.strftime('%H:%M:%S.%f')
|
||||
|
||||
# 推送
|
||||
self.onXminBar(self.xminBar)
|
||||
|
||||
# 创建新的K线
|
||||
self.xminBar = VtBarData()
|
||||
newX = True
|
||||
|
||||
# 初始化K线数据
|
||||
if newX:
|
||||
self.xminBar.vtSymbol = bar.vtSymbol
|
||||
self.xminBar.symbol = bar.symbol
|
||||
self.xminBar.exchange = bar.exchange
|
||||
|
||||
self.xminBar.open = bar.open
|
||||
self.xminBar.high = bar.high
|
||||
self.xminBar.low = bar.low
|
||||
# 累加老K线
|
||||
else:
|
||||
self.xminBar.high = max(self.xminBar.high, bar.high)
|
||||
self.xminBar.low = min(self.xminBar.low, bar.low)
|
||||
|
||||
# 通用部分
|
||||
self.xminBar.close = bar.close
|
||||
self.xminBar.datetime = bar.datetime
|
||||
self.xminBar.openInterest = bar.openInterest
|
||||
self.xminBar.volume += int(bar.volume)
|
||||
|
||||
|
@ -15,7 +15,7 @@ import numpy as np
|
||||
|
||||
from vnpy.trader.vtObject import VtBarData
|
||||
from vnpy.trader.vtConstant import EMPTY_STRING
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate, BarManager
|
||||
|
||||
|
||||
########################################################################
|
||||
@ -34,9 +34,6 @@ class AtrRsiStrategy(CtaTemplate):
|
||||
fixedSize = 1 # 每次交易的数量
|
||||
|
||||
# 策略变量
|
||||
bar = None # K线对象
|
||||
barMinute = EMPTY_STRING # K线当前的分钟
|
||||
|
||||
bufferSize = 100 # 需要缓存的数据的大小
|
||||
bufferCount = 0 # 目前已经缓存了的数据的计数
|
||||
highArray = np.zeros(bufferSize) # K线最高价的数组
|
||||
@ -82,6 +79,9 @@ class AtrRsiStrategy(CtaTemplate):
|
||||
"""Constructor"""
|
||||
super(AtrRsiStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
# 创建K线合成器对象
|
||||
self.bm = BarManager(self.onBar)
|
||||
|
||||
# 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
|
||||
# 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
|
||||
# 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
|
||||
@ -118,35 +118,7 @@ class AtrRsiStrategy(CtaTemplate):
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
# 计算K线
|
||||
tickMinute = tick.datetime.minute
|
||||
|
||||
if tickMinute != self.barMinute:
|
||||
if self.bar:
|
||||
self.onBar(self.bar)
|
||||
|
||||
bar = VtBarData()
|
||||
bar.vtSymbol = tick.vtSymbol
|
||||
bar.symbol = tick.symbol
|
||||
bar.exchange = tick.exchange
|
||||
|
||||
bar.open = tick.lastPrice
|
||||
bar.high = tick.lastPrice
|
||||
bar.low = tick.lastPrice
|
||||
bar.close = tick.lastPrice
|
||||
|
||||
bar.date = tick.date
|
||||
bar.time = tick.time
|
||||
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
|
||||
|
||||
self.bar = bar # 这种写法为了减少一层访问,加快速度
|
||||
self.barMinute = tickMinute # 更新当前的分钟
|
||||
else: # 否则继续累加新的K线
|
||||
bar = self.bar # 写法同样为了加快速度
|
||||
|
||||
bar.high = max(bar.high, tick.lastPrice)
|
||||
bar.low = min(bar.low, tick.lastPrice)
|
||||
bar.close = tick.lastPrice
|
||||
self.bm.updateTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
|
@ -8,7 +8,7 @@ from datetime import time
|
||||
|
||||
from vnpy.trader.vtObject import VtBarData
|
||||
from vnpy.trader.vtConstant import EMPTY_STRING
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate, BarManager
|
||||
|
||||
|
||||
########################################################################
|
||||
@ -25,8 +25,6 @@ class DualThrustStrategy(CtaTemplate):
|
||||
initDays = 10
|
||||
|
||||
# 策略变量
|
||||
bar = None # K线对象
|
||||
barMinute = EMPTY_STRING # K线当前的分钟
|
||||
barList = [] # K线对象的列表
|
||||
|
||||
dayOpen = 0
|
||||
@ -65,6 +63,7 @@ class DualThrustStrategy(CtaTemplate):
|
||||
"""Constructor"""
|
||||
super(DualThrustStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
self.bm = BarManager(self.onBar)
|
||||
self.barList = []
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@ -94,36 +93,8 @@ class DualThrustStrategy(CtaTemplate):
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
# 计算K线
|
||||
tickMinute = tick.datetime.minute
|
||||
|
||||
if tickMinute != self.barMinute:
|
||||
if self.bar:
|
||||
self.onBar(self.bar)
|
||||
|
||||
bar = VtBarData()
|
||||
bar.vtSymbol = tick.vtSymbol
|
||||
bar.symbol = tick.symbol
|
||||
bar.exchange = tick.exchange
|
||||
|
||||
bar.open = tick.lastPrice
|
||||
bar.high = tick.lastPrice
|
||||
bar.low = tick.lastPrice
|
||||
bar.close = tick.lastPrice
|
||||
|
||||
bar.date = tick.date
|
||||
bar.time = tick.time
|
||||
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
|
||||
|
||||
self.bar = bar # 这种写法为了减少一层访问,加快速度
|
||||
self.barMinute = tickMinute # 更新当前的分钟
|
||||
else: # 否则继续累加新的K线
|
||||
bar = self.bar # 写法同样为了加快速度
|
||||
|
||||
bar.high = max(bar.high, tick.lastPrice)
|
||||
bar.low = min(bar.low, tick.lastPrice)
|
||||
bar.close = tick.lastPrice
|
||||
|
||||
self.bm.updateTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
"""收到Bar推送(必须由用户继承实现)"""
|
||||
|
@ -15,7 +15,7 @@ from __future__ import division
|
||||
|
||||
from vnpy.trader.vtObject import VtBarData
|
||||
from vnpy.trader.vtConstant import EMPTY_STRING, EMPTY_FLOAT
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate, BarManager
|
||||
|
||||
|
||||
########################################################################
|
||||
@ -30,9 +30,6 @@ class EmaDemoStrategy(CtaTemplate):
|
||||
initDays = 10 # 初始化数据所用的天数
|
||||
|
||||
# 策略变量
|
||||
bar = None
|
||||
barMinute = EMPTY_STRING
|
||||
|
||||
fastMa = [] # 快速EMA均线数组
|
||||
fastMa0 = EMPTY_FLOAT # 当前最新的快速EMA
|
||||
fastMa1 = EMPTY_FLOAT # 上一根的快速EMA
|
||||
@ -63,6 +60,8 @@ class EmaDemoStrategy(CtaTemplate):
|
||||
"""Constructor"""
|
||||
super(EmaDemoStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
self.bm = BarManager(self.onBar)
|
||||
|
||||
# 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
|
||||
# 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
|
||||
# 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
|
||||
@ -96,40 +95,7 @@ class EmaDemoStrategy(CtaTemplate):
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
# 计算K线
|
||||
tickMinute = tick.datetime.minute
|
||||
|
||||
if tickMinute != self.barMinute:
|
||||
if self.bar:
|
||||
self.onBar(self.bar)
|
||||
|
||||
bar = VtBarData()
|
||||
bar.vtSymbol = tick.vtSymbol
|
||||
bar.symbol = tick.symbol
|
||||
bar.exchange = tick.exchange
|
||||
|
||||
bar.open = tick.lastPrice
|
||||
bar.high = tick.lastPrice
|
||||
bar.low = tick.lastPrice
|
||||
bar.close = tick.lastPrice
|
||||
|
||||
bar.date = tick.date
|
||||
bar.time = tick.time
|
||||
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
|
||||
|
||||
# 实盘中用不到的数据可以选择不算,从而加快速度
|
||||
#bar.volume = tick.volume
|
||||
#bar.openInterest = tick.openInterest
|
||||
|
||||
self.bar = bar # 这种写法为了减少一层访问,加快速度
|
||||
self.barMinute = tickMinute # 更新当前的分钟
|
||||
|
||||
else: # 否则继续累加新的K线
|
||||
bar = self.bar # 写法同样为了加快速度
|
||||
|
||||
bar.high = max(bar.high, tick.lastPrice)
|
||||
bar.low = min(bar.low, tick.lastPrice)
|
||||
bar.close = tick.lastPrice
|
||||
self.bm.updateTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
|
@ -17,7 +17,7 @@ import numpy as np
|
||||
|
||||
from vnpy.trader.vtObject import VtBarData
|
||||
from vnpy.trader.vtConstant import EMPTY_STRING
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate
|
||||
from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate, BarManager
|
||||
|
||||
|
||||
########################################################################
|
||||
@ -34,10 +34,6 @@ class KkStrategy(CtaTemplate):
|
||||
fixedSize = 1 # 每次交易的数量
|
||||
|
||||
# 策略变量
|
||||
bar = None # 1分钟K线对象
|
||||
barMinute = EMPTY_STRING # K线当前的分钟
|
||||
fiveBar = None # 1分钟K线对象
|
||||
|
||||
bufferSize = 100 # 需要缓存的数据的大小
|
||||
bufferCount = 0 # 目前已经缓存了的数据的计数
|
||||
highArray = np.zeros(bufferSize) # K线最高价的数组
|
||||
@ -77,6 +73,8 @@ class KkStrategy(CtaTemplate):
|
||||
"""Constructor"""
|
||||
super(KkStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
self.bm = BarManager(self.onBar, 5, self.onFiveBar) # 创建K线合成器对象
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onInit(self):
|
||||
"""初始化策略(必须由用户继承实现)"""
|
||||
@ -103,83 +101,18 @@ class KkStrategy(CtaTemplate):
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
# 聚合为1分钟K线
|
||||
tickMinute = tick.datetime.minute
|
||||
|
||||
if tickMinute != self.barMinute:
|
||||
if self.bar:
|
||||
self.onBar(self.bar)
|
||||
|
||||
bar = VtBarData()
|
||||
bar.vtSymbol = tick.vtSymbol
|
||||
bar.symbol = tick.symbol
|
||||
bar.exchange = tick.exchange
|
||||
|
||||
bar.open = tick.lastPrice
|
||||
bar.high = tick.lastPrice
|
||||
bar.low = tick.lastPrice
|
||||
bar.close = tick.lastPrice
|
||||
|
||||
bar.date = tick.date
|
||||
bar.time = tick.time
|
||||
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
|
||||
|
||||
self.bar = bar # 这种写法为了减少一层访问,加快速度
|
||||
self.barMinute = tickMinute # 更新当前的分钟
|
||||
else: # 否则继续累加新的K线
|
||||
bar = self.bar # 写法同样为了加快速度
|
||||
|
||||
bar.high = max(bar.high, tick.lastPrice)
|
||||
bar.low = min(bar.low, tick.lastPrice)
|
||||
bar.close = tick.lastPrice
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
self.bm.updateTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
"""收到Bar推送(必须由用户继承实现)"""
|
||||
# 如果当前是一个5分钟走完(分钟线的时间戳是当前分钟的开始时间戳,因此要+1)
|
||||
if (bar.datetime.minute + 1) % 5 == 0:
|
||||
# 如果已经有聚合5分钟K线
|
||||
if self.fiveBar:
|
||||
# 将最新分钟的数据更新到目前5分钟线中
|
||||
fiveBar = self.fiveBar
|
||||
fiveBar.high = max(fiveBar.high, bar.high)
|
||||
fiveBar.low = min(fiveBar.low, bar.low)
|
||||
fiveBar.close = bar.close
|
||||
|
||||
# 推送5分钟线数据
|
||||
self.onFiveBar(fiveBar)
|
||||
|
||||
# 清空5分钟线数据缓存
|
||||
self.fiveBar = None
|
||||
else:
|
||||
# 如果没有缓存则新建
|
||||
if not self.fiveBar:
|
||||
fiveBar = VtBarData()
|
||||
|
||||
fiveBar.vtSymbol = bar.vtSymbol
|
||||
fiveBar.symbol = bar.symbol
|
||||
fiveBar.exchange = bar.exchange
|
||||
|
||||
fiveBar.open = bar.open
|
||||
fiveBar.high = bar.high
|
||||
fiveBar.low = bar.low
|
||||
fiveBar.close = bar.close
|
||||
|
||||
fiveBar.date = bar.date
|
||||
fiveBar.time = bar.time
|
||||
fiveBar.datetime = bar.datetime
|
||||
|
||||
self.fiveBar = fiveBar
|
||||
else:
|
||||
fiveBar = self.fiveBar
|
||||
fiveBar.high = max(fiveBar.high, bar.high)
|
||||
fiveBar.low = min(fiveBar.low, bar.low)
|
||||
fiveBar.close = bar.close
|
||||
self.bm.updateBar(bar)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onFiveBar(self, bar):
|
||||
"""收到5分钟K线"""
|
||||
print bar.datetime, bar.open, bar.high, bar.low, bar.close
|
||||
# 撤销之前发出的尚未成交的委托(包括限价单和停止单)
|
||||
for orderID in self.orderList:
|
||||
self.cancelOrder(orderID)
|
||||
|
Loading…
Reference in New Issue
Block a user