From a8f289dd105a38ed4160d46b442845d55d22f01c Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 5 Nov 2018 11:11:20 +0800 Subject: [PATCH] =?UTF-8?q?[Mod]=E5=B0=86BarGenerator=E5=92=8CArrayManager?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=88=B0vtUtility.py=E4=B8=AD=EF=BC=8CClose?= =?UTF-8?q?=20#1084?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RqdataDataService/dataService.py | 3 - vnpy/trader/app/ctaStrategy/ctaTemplate.py | 288 +----------------- vnpy/trader/app/dataRecorder/drEngine.py | 2 +- vnpy/trader/vtUtility.py | 283 +++++++++++++++++ 4 files changed, 285 insertions(+), 291 deletions(-) create mode 100644 vnpy/trader/vtUtility.py diff --git a/examples/DataService/RqdataDataService/dataService.py b/examples/DataService/RqdataDataService/dataService.py index ab79add9..21a339ef 100644 --- a/examples/DataService/RqdataDataService/dataService.py +++ b/examples/DataService/RqdataDataService/dataService.py @@ -30,9 +30,6 @@ rq.init(USERNAME, PASSWORD) FIELDS = ['open', 'high', 'low', 'close', 'volume'] -#print (rq.all_instruments(type='Future')) -#print(rq.get_price('IF99', frequency='1m', fields=FIELDS)) - #---------------------------------------------------------------------- def generateVtBar(row, symbol): """生成K线""" diff --git a/vnpy/trader/app/ctaStrategy/ctaTemplate.py b/vnpy/trader/app/ctaStrategy/ctaTemplate.py index f6b6a465..1e1dedc3 100644 --- a/vnpy/trader/app/ctaStrategy/ctaTemplate.py +++ b/vnpy/trader/app/ctaStrategy/ctaTemplate.py @@ -4,11 +4,8 @@ 本文件包含了CTA引擎中的策略开发用模板,开发策略时需要继承CtaTemplate类。 ''' -import numpy as np -import talib - from vnpy.trader.vtConstant import * -from vnpy.trader.vtObject import VtBarData +from vnpy.trader.vtUtility import BarGenerator, ArrayManager from .ctaBase import * @@ -201,7 +198,6 @@ class CtaTemplate(object): return self.ctaEngine.getPriceTick(self) - ######################################################################## class TargetPosTemplate(CtaTemplate): """ @@ -340,282 +336,6 @@ class TargetPosTemplate(CtaTemplate): l = self.short(shortPrice, abs(posChange)) self.orderList.extend(l) - -######################################################################## -class BarGenerator(object): - """ - K线合成器,支持: - 1. 基于Tick合成1分钟K线 - 2. 基于1分钟K线合成X分钟K线(X可以是2、3、5、10、15、30 ) - """ - - #---------------------------------------------------------------------- - 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: - volumeChange = tick.volume - self.lastTick.volume # 当前K线内的成交量 - self.bar.volume += max(volumeChange, 0) # 避免夜盘开盘lastTick.volume为昨日收盘数据,导致成交量变化为负的情况 - - # 缓存Tick - self.lastTick = tick - - #---------------------------------------------------------------------- - def updateBar(self, bar): - """1分钟K线更新""" - # 尚未创建对象 - if not self.xminBar: - self.xminBar = VtBarData() - - 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 - - self.xminBar.datetime = bar.datetime # 以第一根分钟K线的开始时间戳作为X分钟线的时间戳 - # 累加老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.openInterest = bar.openInterest - self.xminBar.volume += int(bar.volume) - - # X分钟已经走完 - if not (bar.datetime.minute + 1) % 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 = None - - #---------------------------------------------------------------------- - def generate(self): - """手动强制立即完成K线合成""" - self.onBar(self.bar) - self.bar = None - - - -######################################################################## -class ArrayManager(object): - """ - K线序列管理工具,负责: - 1. K线时间序列的维护 - 2. 常用技术指标的计算 - """ - - #---------------------------------------------------------------------- - def __init__(self, size=100): - """Constructor""" - self.count = 0 # 缓存计数 - self.size = size # 缓存大小 - self.inited = False # True if count>=size - - self.openArray = np.zeros(size) # OHLC - self.highArray = np.zeros(size) - self.lowArray = np.zeros(size) - self.closeArray = np.zeros(size) - self.volumeArray = np.zeros(size) - - #---------------------------------------------------------------------- - def updateBar(self, bar): - """更新K线""" - self.count += 1 - if not self.inited and self.count >= self.size: - self.inited = True - - self.openArray[0:self.size-1] = self.openArray[1:self.size] - self.highArray[0:self.size-1] = self.highArray[1:self.size] - self.lowArray[0:self.size-1] = self.lowArray[1:self.size] - self.closeArray[0:self.size-1] = self.closeArray[1:self.size] - self.volumeArray[0:self.size-1] = self.volumeArray[1:self.size] - - self.openArray[-1] = bar.open - self.highArray[-1] = bar.high - self.lowArray[-1] = bar.low - self.closeArray[-1] = bar.close - self.volumeArray[-1] = bar.volume - - #---------------------------------------------------------------------- - @property - def open(self): - """获取开盘价序列""" - return self.openArray - - #---------------------------------------------------------------------- - @property - def high(self): - """获取最高价序列""" - return self.highArray - - #---------------------------------------------------------------------- - @property - def low(self): - """获取最低价序列""" - return self.lowArray - - #---------------------------------------------------------------------- - @property - def close(self): - """获取收盘价序列""" - return self.closeArray - - #---------------------------------------------------------------------- - @property - def volume(self): - """获取成交量序列""" - return self.volumeArray - - #---------------------------------------------------------------------- - def sma(self, n, array=False): - """简单均线""" - result = talib.SMA(self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def std(self, n, array=False): - """标准差""" - result = talib.STDDEV(self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def cci(self, n, array=False): - """CCI指标""" - result = talib.CCI(self.high, self.low, self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def atr(self, n, array=False): - """ATR指标""" - result = talib.ATR(self.high, self.low, self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def rsi(self, n, array=False): - """RSI指标""" - result = talib.RSI(self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def macd(self, fastPeriod, slowPeriod, signalPeriod, array=False): - """MACD指标""" - macd, signal, hist = talib.MACD(self.close, fastPeriod, - slowPeriod, signalPeriod) - if array: - return macd, signal, hist - return macd[-1], signal[-1], hist[-1] - - #---------------------------------------------------------------------- - def adx(self, n, array=False): - """ADX指标""" - result = talib.ADX(self.high, self.low, self.close, n) - if array: - return result - return result[-1] - - #---------------------------------------------------------------------- - def boll(self, n, dev, array=False): - """布林通道""" - mid = self.sma(n, array) - std = self.std(n, array) - - up = mid + std * dev - down = mid - std * dev - - return up, down - - #---------------------------------------------------------------------- - def keltner(self, n, dev, array=False): - """肯特纳通道""" - mid = self.sma(n, array) - atr = self.atr(n, array) - - up = mid + atr * dev - down = mid - atr * dev - - return up, down - - #---------------------------------------------------------------------- - def donchian(self, n, array=False): - """唐奇安通道""" - up = talib.MAX(self.high, n) - down = talib.MIN(self.low, n) - - if array: - return up, down - return up[-1], down[-1] - ######################################################################## class CtaSignal(object): @@ -647,9 +367,3 @@ class CtaSignal(object): def getSignalPos(self): """获取信号仓位""" return self.signalPos - - - - - - \ No newline at end of file diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index 8a84305f..959e8f1f 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -21,7 +21,7 @@ from vnpy.event import Event from vnpy.trader.vtEvent import * from vnpy.trader.vtFunction import todayDate, getJsonPath from vnpy.trader.vtObject import VtSubscribeReq, VtLogData, VtBarData, VtTickData -from vnpy.trader.app.ctaStrategy.ctaTemplate import BarGenerator +from vnpy.trader.vtUtility import BarGenerator from .drBase import * from .language import text diff --git a/vnpy/trader/vtUtility.py b/vnpy/trader/vtUtility.py new file mode 100644 index 00000000..1264aa22 --- /dev/null +++ b/vnpy/trader/vtUtility.py @@ -0,0 +1,283 @@ +# encoding: UTF-8 + + +import numpy as np +import talib + +from vnpy.trader.vtObject import VtBarData + + +######################################################################## +class BarGenerator(object): + """ + K线合成器,支持: + 1. 基于Tick合成1分钟K线 + 2. 基于1分钟K线合成X分钟K线(X可以是2、3、5、10、15、30 ) + """ + + #---------------------------------------------------------------------- + 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: + volumeChange = tick.volume - self.lastTick.volume # 当前K线内的成交量 + self.bar.volume += max(volumeChange, 0) # 避免夜盘开盘lastTick.volume为昨日收盘数据,导致成交量变化为负的情况 + + # 缓存Tick + self.lastTick = tick + + #---------------------------------------------------------------------- + def updateBar(self, bar): + """1分钟K线更新""" + # 尚未创建对象 + if not self.xminBar: + self.xminBar = VtBarData() + + 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 + + self.xminBar.datetime = bar.datetime # 以第一根分钟K线的开始时间戳作为X分钟线的时间戳 + # 累加老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.openInterest = bar.openInterest + self.xminBar.volume += int(bar.volume) + + # X分钟已经走完 + if not (bar.datetime.minute + 1) % 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 = None + + #---------------------------------------------------------------------- + def generate(self): + """手动强制立即完成K线合成""" + self.onBar(self.bar) + self.bar = None + + + +######################################################################## +class ArrayManager(object): + """ + K线序列管理工具,负责: + 1. K线时间序列的维护 + 2. 常用技术指标的计算 + """ + + #---------------------------------------------------------------------- + def __init__(self, size=100): + """Constructor""" + self.count = 0 # 缓存计数 + self.size = size # 缓存大小 + self.inited = False # True if count>=size + + self.openArray = np.zeros(size) # OHLC + self.highArray = np.zeros(size) + self.lowArray = np.zeros(size) + self.closeArray = np.zeros(size) + self.volumeArray = np.zeros(size) + + #---------------------------------------------------------------------- + def updateBar(self, bar): + """更新K线""" + self.count += 1 + if not self.inited and self.count >= self.size: + self.inited = True + + self.openArray[0:self.size-1] = self.openArray[1:self.size] + self.highArray[0:self.size-1] = self.highArray[1:self.size] + self.lowArray[0:self.size-1] = self.lowArray[1:self.size] + self.closeArray[0:self.size-1] = self.closeArray[1:self.size] + self.volumeArray[0:self.size-1] = self.volumeArray[1:self.size] + + self.openArray[-1] = bar.open + self.highArray[-1] = bar.high + self.lowArray[-1] = bar.low + self.closeArray[-1] = bar.close + self.volumeArray[-1] = bar.volume + + #---------------------------------------------------------------------- + @property + def open(self): + """获取开盘价序列""" + return self.openArray + + #---------------------------------------------------------------------- + @property + def high(self): + """获取最高价序列""" + return self.highArray + + #---------------------------------------------------------------------- + @property + def low(self): + """获取最低价序列""" + return self.lowArray + + #---------------------------------------------------------------------- + @property + def close(self): + """获取收盘价序列""" + return self.closeArray + + #---------------------------------------------------------------------- + @property + def volume(self): + """获取成交量序列""" + return self.volumeArray + + #---------------------------------------------------------------------- + def sma(self, n, array=False): + """简单均线""" + result = talib.SMA(self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def std(self, n, array=False): + """标准差""" + result = talib.STDDEV(self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def cci(self, n, array=False): + """CCI指标""" + result = talib.CCI(self.high, self.low, self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def atr(self, n, array=False): + """ATR指标""" + result = talib.ATR(self.high, self.low, self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def rsi(self, n, array=False): + """RSI指标""" + result = talib.RSI(self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def macd(self, fastPeriod, slowPeriod, signalPeriod, array=False): + """MACD指标""" + macd, signal, hist = talib.MACD(self.close, fastPeriod, + slowPeriod, signalPeriod) + if array: + return macd, signal, hist + return macd[-1], signal[-1], hist[-1] + + #---------------------------------------------------------------------- + def adx(self, n, array=False): + """ADX指标""" + result = talib.ADX(self.high, self.low, self.close, n) + if array: + return result + return result[-1] + + #---------------------------------------------------------------------- + def boll(self, n, dev, array=False): + """布林通道""" + mid = self.sma(n, array) + std = self.std(n, array) + + up = mid + std * dev + down = mid - std * dev + + return up, down + + #---------------------------------------------------------------------- + def keltner(self, n, dev, array=False): + """肯特纳通道""" + mid = self.sma(n, array) + atr = self.atr(n, array) + + up = mid + atr * dev + down = mid - atr * dev + + return up, down + + #---------------------------------------------------------------------- + def donchian(self, n, array=False): + """唐奇安通道""" + up = talib.MAX(self.high, n) + down = talib.MIN(self.low, n) + + if array: + return up, down + return up[-1], down[-1]