合并vnpy v1.3版本
This commit is contained in:
parent
6c44da565d
commit
f37440e6bb
@ -57,6 +57,9 @@ class BacktestingEngine(object):
|
|||||||
self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除
|
self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除
|
||||||
self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除
|
self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除
|
||||||
|
|
||||||
|
# 引擎类型为回测
|
||||||
|
self.engineType = ENGINETYPE_BACKTESTING
|
||||||
|
|
||||||
# 回测相关
|
# 回测相关
|
||||||
self.strategy = None # 回测策略
|
self.strategy = None # 回测策略
|
||||||
self.mode = self.BAR_MODE # 回测模式,默认为K线
|
self.mode = self.BAR_MODE # 回测模式,默认为K线
|
||||||
@ -401,8 +404,7 @@ class BacktestingEngine(object):
|
|||||||
else:
|
else:
|
||||||
self.writeCtaLog(u'MysqlDB未连接,请检查')
|
self.writeCtaLog(u'MysqlDB未连接,请检查')
|
||||||
|
|
||||||
except MySQLdb.Error, e:
|
except MySQLdb.Error as e:
|
||||||
|
|
||||||
self.writeCtaLog(u'MysqlDB载入数据失败,请检查.Error {0}'.format(e))
|
self.writeCtaLog(u'MysqlDB载入数据失败,请检查.Error {0}'.format(e))
|
||||||
|
|
||||||
def __dataToTick(self, data):
|
def __dataToTick(self, data):
|
||||||
@ -494,15 +496,14 @@ class BacktestingEngine(object):
|
|||||||
else:
|
else:
|
||||||
self.writeCtaLog(u'MysqlDB未连接,请检查')
|
self.writeCtaLog(u'MysqlDB未连接,请检查')
|
||||||
|
|
||||||
except MySQLdb.Error, e:
|
except MySQLdb.Error as e:
|
||||||
|
|
||||||
self.writeCtaLog(u'MysqlDB载入数据失败,请检查.Error {0}: {1}'.format(e.arg[0],e.arg[1]))
|
self.writeCtaLog(u'MysqlDB载入数据失败,请检查.Error {0}: {1}'.format(e.arg[0],e.arg[1]))
|
||||||
|
|
||||||
# 出错后缺省返回
|
# 出错后缺省返回
|
||||||
return startDate-timedelta(days=3)
|
return startDate-timedelta(days=3)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def runBackTestingWithArbTickFile(self, arbSymbol):
|
def runBackTestingWithArbTickFile(self,mainPath, arbSymbol):
|
||||||
"""运行套利回测(使用本地tickcsv数据)
|
"""运行套利回测(使用本地tickcsv数据)
|
||||||
参数:套利代码 SP rb1610&rb1701
|
参数:套利代码 SP rb1610&rb1701
|
||||||
added by IncenseLee
|
added by IncenseLee
|
||||||
@ -567,38 +568,42 @@ class BacktestingEngine(object):
|
|||||||
self.output(u'回测日期:{0}'.format(testday))
|
self.output(u'回测日期:{0}'.format(testday))
|
||||||
|
|
||||||
# 白天数据
|
# 白天数据
|
||||||
self.__loadArbTicks(u'SHFE',testday,leg1,leg2)
|
self.__loadArbTicks(mainPath,testday,leg1,leg2)
|
||||||
|
|
||||||
# 夜盘数据
|
# 夜盘数据
|
||||||
self.__loadArbTicks(u'SHFE_night', testday, leg1, leg2)
|
self.__loadArbTicks(mainPath+'_night', testday, leg1, leg2)
|
||||||
|
|
||||||
|
|
||||||
def __loadArbTicks(self,mainPath,testday,leg1,leg2):
|
def __loadArbTicks(self,mainPath,testday,leg1,leg2):
|
||||||
|
|
||||||
leg1File = u'z:\\ticks\\{0}\\{1}\\{2}\\{3}\\{4}.txt' \
|
|
||||||
.format(mainPath,testday.strftime('%Y%m'), self.symbol, testday.strftime('%m%d'), leg1)
|
|
||||||
if not os.path.isfile(leg1File):
|
|
||||||
self.writeCtaLog(u'{0}文件不存在'.format(leg1File))
|
|
||||||
return
|
|
||||||
|
|
||||||
leg2File = u'z:\\ticks\\{0}\\{1}\\{2}\\{3}\\{4}.txt' \
|
|
||||||
.format(mainPath,testday.strftime('%Y%m'), self.symbol, testday.strftime('%m%d'), leg2)
|
|
||||||
if not os.path.isfile(leg2File):
|
|
||||||
self.writeCtaLog(u'{0}文件不存在'.format(leg2File))
|
|
||||||
return
|
|
||||||
|
|
||||||
self.writeCtaLog(u'加载回测日期:{0}\{1}的价差tick'.format(mainPath, testday))
|
self.writeCtaLog(u'加载回测日期:{0}\{1}的价差tick'.format(mainPath, testday))
|
||||||
|
|
||||||
cachefilename = u'{0}_{1}_{2}_{3}_{4}'.format(self.symbol,leg1,leg2, mainPath, testday.strftime('%Y%m%d'))
|
cachefilename = u'{0}_{1}_{2}_{3}_{4}'.format(self.symbol,leg1,leg2, mainPath, testday.strftime('%Y%m%d'))
|
||||||
|
|
||||||
arbTicks = self.__loadArbTicksFromLocalCache(cachefilename)
|
arbTicks = self.__loadArbTicksFromLocalCache(cachefilename)
|
||||||
|
|
||||||
|
dt = None
|
||||||
|
|
||||||
if len(arbTicks) < 1:
|
if len(arbTicks) < 1:
|
||||||
|
|
||||||
|
leg1File = u'z:\\ticks\\{0}\\{1}\\{2}\\{3}\\{4}.txt' \
|
||||||
|
.format(mainPath, testday.strftime('%Y%m'), self.symbol, testday.strftime('%m%d'), leg1)
|
||||||
|
if not os.path.isfile(leg1File):
|
||||||
|
self.writeCtaLog(u'{0}文件不存在'.format(leg1File))
|
||||||
|
return
|
||||||
|
|
||||||
|
leg2File = u'z:\\ticks\\{0}\\{1}\\{2}\\{3}\\{4}.txt' \
|
||||||
|
.format(mainPath, testday.strftime('%Y%m'), self.symbol, testday.strftime('%m%d'), leg2)
|
||||||
|
if not os.path.isfile(leg2File):
|
||||||
|
self.writeCtaLog(u'{0}文件不存在'.format(leg2File))
|
||||||
|
return
|
||||||
|
|
||||||
# 先读取leg2的数据到目录,以日期时间为key
|
# 先读取leg2的数据到目录,以日期时间为key
|
||||||
leg2Ticks = {}
|
leg2Ticks = {}
|
||||||
|
|
||||||
leg2CsvReadFile = file(leg2File, 'rb')
|
leg2CsvReadFile = file(leg2File, 'rb')
|
||||||
reader = csv.DictReader((line.replace('\0', '') for line in leg2CsvReadFile), delimiter=",")
|
#reader = csv.DictReader((line.replace('\0',' ') for line in leg2CsvReadFile), delimiter=",")
|
||||||
|
reader = csv.DictReader(leg2CsvReadFile, delimiter=",")
|
||||||
self.writeCtaLog(u'加载{0}'.format(leg2File))
|
self.writeCtaLog(u'加载{0}'.format(leg2File))
|
||||||
for row in reader:
|
for row in reader:
|
||||||
tick = CtaTickData()
|
tick = CtaTickData()
|
||||||
@ -607,8 +612,26 @@ class BacktestingEngine(object):
|
|||||||
tick.symbol = self.symbol
|
tick.symbol = self.symbol
|
||||||
|
|
||||||
tick.date = testday.strftime('%Y%m%d')
|
tick.date = testday.strftime('%Y%m%d')
|
||||||
|
tick.tradingDay = tick.date
|
||||||
tick.time = row['Time']
|
tick.time = row['Time']
|
||||||
tick.datetime = datetime.strptime(tick.date + ' ' + tick.time, '%Y%m%d %H:%M:%S.%f')
|
|
||||||
|
try:
|
||||||
|
tick.datetime = datetime.strptime(tick.date + ' ' + tick.time, '%Y%m%d %H:%M:%S.%f')
|
||||||
|
except Exception as ex:
|
||||||
|
self.writeCtaError(u'日期转换错误:{0},{1}:{2}'.format(tick.date + ' ' + tick.time, Exception, ex))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 修正毫秒
|
||||||
|
if tick.datetime.replace(microsecond = 0) == dt:
|
||||||
|
# 与上一个tick的时间(去除毫秒后)相同,修改为500毫秒
|
||||||
|
tick.datetime=tick.datetime.replace(microsecond = 500)
|
||||||
|
tick.time = tick.datetime.strftime('%H:%M:%S.%f')
|
||||||
|
|
||||||
|
else:
|
||||||
|
tick.datetime = tick.datetime.replace(microsecond=0)
|
||||||
|
tick.time = tick.datetime.strftime('%H:%M:%S.%f')
|
||||||
|
|
||||||
|
dt = tick.datetime
|
||||||
|
|
||||||
tick.lastPrice = float(row['LastPrice'])
|
tick.lastPrice = float(row['LastPrice'])
|
||||||
tick.volume = int(float(row['LVolume']))
|
tick.volume = int(float(row['LVolume']))
|
||||||
@ -622,27 +645,49 @@ class BacktestingEngine(object):
|
|||||||
or (tick.askPrice1 == float('1.79769E308') and tick.askVolume1 == 0):
|
or (tick.askPrice1 == float('1.79769E308') and tick.askVolume1 == 0):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
leg2Ticks[tick.date + ' ' + tick.time] = tick
|
dtStr = tick.date + ' ' + tick.time
|
||||||
|
if dtStr in leg2Ticks:
|
||||||
|
self.writeCtaError(u'日内数据重复,异常,数据时间为:{0}'.format(dtStr))
|
||||||
|
else:
|
||||||
|
leg2Ticks[dtStr] = tick
|
||||||
|
|
||||||
leg1CsvReadFile = file(leg1File, 'rb')
|
leg1CsvReadFile = file(leg1File, 'rb')
|
||||||
reader = csv.DictReader((line.replace('\0', '') for line in leg1CsvReadFile), delimiter=",")
|
#reader = csv.DictReader((line.replace('\0',' ') for line in leg1CsvReadFile), delimiter=",")
|
||||||
|
reader = csv.DictReader(leg1CsvReadFile, delimiter=",")
|
||||||
self.writeCtaLog(u'加载{0}'.format(leg1File))
|
self.writeCtaLog(u'加载{0}'.format(leg1File))
|
||||||
|
|
||||||
|
dt = None
|
||||||
for row in reader:
|
for row in reader:
|
||||||
dtStr = ' '.join([testday.strftime('%Y%m%d'), row['Time']])
|
|
||||||
|
arbTick = CtaTickData()
|
||||||
|
|
||||||
|
arbTick.date = testday.strftime('%Y%m%d')
|
||||||
|
arbTick.time = row['Time']
|
||||||
|
try:
|
||||||
|
arbTick.datetime = datetime.strptime(arbTick.date + ' ' + arbTick.time, '%Y%m%d %H:%M:%S.%f')
|
||||||
|
except Exception as ex:
|
||||||
|
self.writeCtaError(u'日期转换错误:{0},{1}:{2}'.format(arbTick.date + ' ' + arbTick.time, Exception, ex))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 修正毫秒
|
||||||
|
if arbTick.datetime.replace(microsecond=0) == dt:
|
||||||
|
# 与上一个tick的时间(去除毫秒后)相同,修改为500毫秒
|
||||||
|
arbTick.datetime = arbTick.datetime.replace(microsecond=500)
|
||||||
|
arbTick.time = arbTick.datetime.strftime('%H:%M:%S.%f')
|
||||||
|
|
||||||
|
else:
|
||||||
|
arbTick.datetime = arbTick.datetime.replace(microsecond=0)
|
||||||
|
arbTick.time = arbTick.datetime.strftime('%H:%M:%S.%f')
|
||||||
|
|
||||||
|
dt = arbTick.datetime
|
||||||
|
dtStr = ' '.join([arbTick.date, arbTick.time])
|
||||||
|
|
||||||
if dtStr in leg2Ticks:
|
if dtStr in leg2Ticks:
|
||||||
leg2Tick = leg2Ticks[dtStr]
|
leg2Tick = leg2Ticks[dtStr]
|
||||||
|
|
||||||
arbTick = CtaTickData()
|
|
||||||
|
|
||||||
arbTick.vtSymbol = self.symbol
|
arbTick.vtSymbol = self.symbol
|
||||||
arbTick.symbol = self.symbol
|
arbTick.symbol = self.symbol
|
||||||
|
|
||||||
arbTick.date = testday.strftime('%Y%m%d')
|
|
||||||
arbTick.time = row['Time']
|
|
||||||
arbTick.datetime = datetime.strptime(arbTick.date + ' ' + arbTick.time, '%Y%m%d %H:%M:%S.%f')
|
|
||||||
|
|
||||||
arbTick.lastPrice = EMPTY_FLOAT
|
arbTick.lastPrice = EMPTY_FLOAT
|
||||||
arbTick.volume = EMPTY_INT
|
arbTick.volume = EMPTY_INT
|
||||||
|
|
||||||
@ -667,6 +712,8 @@ class BacktestingEngine(object):
|
|||||||
|
|
||||||
arbTicks.append(arbTick)
|
arbTicks.append(arbTick)
|
||||||
|
|
||||||
|
del leg2Ticks[dtStr]
|
||||||
|
|
||||||
# 保存到历史目录
|
# 保存到历史目录
|
||||||
if len(arbTicks) > 0:
|
if len(arbTicks) > 0:
|
||||||
self.__saveArbTicksToLocalCache(cachefilename, arbTicks)
|
self.__saveArbTicksToLocalCache(cachefilename, arbTicks)
|
||||||
@ -790,7 +837,7 @@ class BacktestingEngine(object):
|
|||||||
if not (bar.datetime < self.dataStartDate or bar.datetime >= self.dataEndDate):
|
if not (bar.datetime < self.dataStartDate or bar.datetime >= self.dataEndDate):
|
||||||
self.newBar(bar)
|
self.newBar(bar)
|
||||||
|
|
||||||
except Exception, ex:
|
except Exception as ex:
|
||||||
self.writeCtaLog(u'{0}:{1}'.format(Exception,ex))
|
self.writeCtaLog(u'{0}:{1}'.format(Exception,ex))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -1109,8 +1156,8 @@ class BacktestingEngine(object):
|
|||||||
# 从字典中删除该限价单
|
# 从字典中删除该限价单
|
||||||
try:
|
try:
|
||||||
del self.workingLimitOrderDict[orderID]
|
del self.workingLimitOrderDict[orderID]
|
||||||
except Exception,ex:
|
except Exception as ex:
|
||||||
self.writeCtaError(u'{0}:{1}'.format(Exception,ex))
|
self.writeCtaError(u'{0}:{1}'.format(Exception, ex))
|
||||||
|
|
||||||
if self.calculateMode == self.REALTIME_MODE:
|
if self.calculateMode == self.REALTIME_MODE:
|
||||||
self.realtimeCalculate()
|
self.realtimeCalculate()
|
||||||
@ -1187,6 +1234,7 @@ class BacktestingEngine(object):
|
|||||||
# 从字典中删除该限价单
|
# 从字典中删除该限价单
|
||||||
del self.workingStopOrderDict[stopOrderID]
|
del self.workingStopOrderDict[stopOrderID]
|
||||||
|
|
||||||
|
# 若采用实时计算净值
|
||||||
if self.calculateMode == self.REALTIME_MODE:
|
if self.calculateMode == self.REALTIME_MODE:
|
||||||
self.realtimeCalculate()
|
self.realtimeCalculate()
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ TICK_DB_NAME = 'VnTrader_Tick_Db'
|
|||||||
DAILY_DB_NAME = 'VnTrader_Daily_Db'
|
DAILY_DB_NAME = 'VnTrader_Daily_Db'
|
||||||
MINUTE_DB_NAME = 'VnTrader_1Min_Db'
|
MINUTE_DB_NAME = 'VnTrader_1Min_Db'
|
||||||
|
|
||||||
|
# 引擎类型,用于区分当前策略的运行环境
|
||||||
|
ENGINETYPE_BACKTESTING = 'backtesting' # 回测
|
||||||
|
ENGINETYPE_TRADING = 'trading' # 实盘
|
||||||
|
|
||||||
# CTA引擎中涉及的数据类定义
|
# CTA引擎中涉及的数据类定义
|
||||||
from vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT, COLOR_EQUAL
|
from vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT, COLOR_EQUAL
|
||||||
|
|
||||||
|
@ -61,6 +61,13 @@ class DoubleEmaDemo(CtaTemplate):
|
|||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
super(DoubleEmaDemo, self).__init__(ctaEngine, setting)
|
super(DoubleEmaDemo, self).__init__(ctaEngine, setting)
|
||||||
|
|
||||||
|
# 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
|
||||||
|
# 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
|
||||||
|
# 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
|
||||||
|
# 策略时方便(更多是个编程习惯的选择)
|
||||||
|
self.fastMa = []
|
||||||
|
self.slowMa = []
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def onInit(self):
|
def onInit(self):
|
||||||
"""初始化策略(必须由用户继承实现)"""
|
"""初始化策略(必须由用户继承实现)"""
|
||||||
@ -76,14 +83,14 @@ class DoubleEmaDemo(CtaTemplate):
|
|||||||
def onStart(self):
|
def onStart(self):
|
||||||
"""启动策略(必须由用户继承实现)"""
|
"""启动策略(必须由用户继承实现)"""
|
||||||
self.writeCtaLog(u'双EMA演示策略启动')
|
self.writeCtaLog(u'双EMA演示策略启动')
|
||||||
|
self.putEvent()
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def onStop(self):
|
def onStop(self):
|
||||||
"""停止策略(必须由用户继承实现)"""
|
"""停止策略(必须由用户继承实现)"""
|
||||||
self.writeCtaLog(u'双EMA演示策略停止')
|
self.writeCtaLog(u'双EMA演示策略停止')
|
||||||
self.putEvent()
|
self.putEvent()
|
||||||
self.putEvent()
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def onTick(self, tick):
|
def onTick(self, tick):
|
||||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||||
|
@ -77,6 +77,12 @@ class CtaEngine(object):
|
|||||||
# key为vtSymbol,value为PositionBuffer对象
|
# key为vtSymbol,value为PositionBuffer对象
|
||||||
self.posBufferDict = {}
|
self.posBufferDict = {}
|
||||||
|
|
||||||
|
# 引擎类型为实盘
|
||||||
|
self.engineType = ENGINETYPE_TRADING
|
||||||
|
|
||||||
|
# tick缓存
|
||||||
|
self.tickDict = {}
|
||||||
|
|
||||||
# 注册事件监听
|
# 注册事件监听
|
||||||
self.registerEvent()
|
self.registerEvent()
|
||||||
|
|
||||||
@ -113,12 +119,19 @@ class CtaEngine(object):
|
|||||||
# 如果获取持仓缓存失败,则默认平昨
|
# 如果获取持仓缓存失败,则默认平昨
|
||||||
if not posBuffer:
|
if not posBuffer:
|
||||||
req.offset = OFFSET_CLOSE
|
req.offset = OFFSET_CLOSE
|
||||||
# 否则如果有多头今仓,则使用平今
|
|
||||||
elif posBuffer.longToday:
|
# modified by IncenseLee 2016/11/08,改为优先平昨仓
|
||||||
req.offset= OFFSET_CLOSETODAY
|
elif posBuffer.longYd :
|
||||||
# 其他情况使用平昨
|
|
||||||
else:
|
|
||||||
req.offset = OFFSET_CLOSE
|
req.offset = OFFSET_CLOSE
|
||||||
|
else:
|
||||||
|
req.offset = OFFSET_CLOSETODAY
|
||||||
|
|
||||||
|
# 否则如果有多头今仓,则使用平今
|
||||||
|
#elif posBuffer.longToday:
|
||||||
|
# req.offset= OFFSET_CLOSETODAY
|
||||||
|
# 其他情况使用平昨
|
||||||
|
#else:
|
||||||
|
# req.offset = OFFSET_CLOSE
|
||||||
|
|
||||||
elif orderType == CTAORDER_SHORT:
|
elif orderType == CTAORDER_SHORT:
|
||||||
req.direction = DIRECTION_SHORT
|
req.direction = DIRECTION_SHORT
|
||||||
@ -136,12 +149,19 @@ class CtaEngine(object):
|
|||||||
# 如果获取持仓缓存失败,则默认平昨
|
# 如果获取持仓缓存失败,则默认平昨
|
||||||
if not posBuffer:
|
if not posBuffer:
|
||||||
req.offset = OFFSET_CLOSE
|
req.offset = OFFSET_CLOSE
|
||||||
# 否则如果有空头今仓,则使用平今
|
|
||||||
elif posBuffer.shortToday:
|
#modified by IncenseLee 2016/11/08,改为优先平昨仓
|
||||||
req.offset= OFFSET_CLOSETODAY
|
elif posBuffer.shortYd:
|
||||||
# 其他情况使用平昨
|
|
||||||
else:
|
|
||||||
req.offset = OFFSET_CLOSE
|
req.offset = OFFSET_CLOSE
|
||||||
|
else:
|
||||||
|
req.offset = OFFSET_CLOSETODAY
|
||||||
|
|
||||||
|
# 否则如果有空头今仓,则使用平今
|
||||||
|
#elif posBuffer.shortToday:
|
||||||
|
# req.offset= OFFSET_CLOSETODAY
|
||||||
|
# 其他情况使用平昨
|
||||||
|
#else:
|
||||||
|
# req.offset = OFFSET_CLOSE
|
||||||
|
|
||||||
vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单
|
vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单
|
||||||
|
|
||||||
@ -191,12 +211,18 @@ class CtaEngine(object):
|
|||||||
self.writeCtaLog(u'从所有订单{0}中撤销{1}'.format(len(l), symbol))
|
self.writeCtaLog(u'从所有订单{0}中撤销{1}'.format(len(l), symbol))
|
||||||
|
|
||||||
for order in l:
|
for order in l:
|
||||||
|
|
||||||
|
if symbol == EMPTY_STRING:
|
||||||
|
symbolCond = True
|
||||||
|
else:
|
||||||
|
symbolCond = order.symbol == symbol
|
||||||
|
|
||||||
if offset == EMPTY_STRING:
|
if offset == EMPTY_STRING:
|
||||||
offsetCond = True
|
offsetCond = True
|
||||||
else:
|
else:
|
||||||
offsetCond = order.offset == offset
|
offsetCond = order.offset == offset
|
||||||
|
|
||||||
if order.symbol == symbol and offsetCond:
|
if symbolCond and offsetCond:
|
||||||
req = VtCancelOrderReq()
|
req = VtCancelOrderReq()
|
||||||
req.symbol = order.symbol
|
req.symbol = order.symbol
|
||||||
req.exchange = order.exchange
|
req.exchange = order.exchange
|
||||||
@ -304,6 +330,9 @@ class CtaEngine(object):
|
|||||||
# 1. 获取事件的Tick数据
|
# 1. 获取事件的Tick数据
|
||||||
tick = event.dict_['data']
|
tick = event.dict_['data']
|
||||||
|
|
||||||
|
# 缓存最新tick
|
||||||
|
self.tickDict[tick.vtSymbol] = tick
|
||||||
|
|
||||||
# 2.收到tick行情后,优先处理本地停止单(检查是否要立即发出)
|
# 2.收到tick行情后,优先处理本地停止单(检查是否要立即发出)
|
||||||
self.processStopOrder(tick)
|
self.processStopOrder(tick)
|
||||||
|
|
||||||
@ -327,7 +356,6 @@ class CtaEngine(object):
|
|||||||
ctaTick.datetime = datetime.strptime(' '.join([today, tick.time]), '%Y%m%d %H:%M:%S.%f')
|
ctaTick.datetime = datetime.strptime(' '.join([today, tick.time]), '%Y%m%d %H:%M:%S.%f')
|
||||||
ctaTick.date = today
|
ctaTick.date = today
|
||||||
|
|
||||||
|
|
||||||
# 逐个推送到策略实例中
|
# 逐个推送到策略实例中
|
||||||
l = self.tickStrategyDict[tick.vtSymbol]
|
l = self.tickStrategyDict[tick.vtSymbol]
|
||||||
for strategy in l:
|
for strategy in l:
|
||||||
@ -484,7 +512,7 @@ class CtaEngine(object):
|
|||||||
try:
|
try:
|
||||||
name = setting['name']
|
name = setting['name']
|
||||||
className = setting['className']
|
className = setting['className']
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
self.writeCtaLog(u'载入策略出错:%s' %e)
|
self.writeCtaLog(u'载入策略出错:%s' %e)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -750,9 +778,3 @@ class PositionBuffer(object):
|
|||||||
else:
|
else:
|
||||||
self.longPosition -= trade.volume
|
self.longPosition -= trade.volume
|
||||||
self.longYd -= trade.volume
|
self.longYd -= trade.volume
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,6 +196,11 @@ class CtaLineBar(object):
|
|||||||
self.lineUpperBand = [] # 上轨
|
self.lineUpperBand = [] # 上轨
|
||||||
self.lineMiddleBand = [] # 中线
|
self.lineMiddleBand = [] # 中线
|
||||||
self.lineLowerBand = [] # 下轨
|
self.lineLowerBand = [] # 下轨
|
||||||
|
self.lineBollStd =[] # 标准差
|
||||||
|
|
||||||
|
self.lastBollUpper = EMPTY_FLOAT # 最后一根K的Boll上轨数值(与MinDiff取整)
|
||||||
|
self.lastBollMiddle = EMPTY_FLOAT # 最后一根K的Boll中轨数值(与MinDiff取整)
|
||||||
|
self.lastBollLower = EMPTY_FLOAT # 最后一根K的Boll下轨数值(与MinDiff取整+1)
|
||||||
|
|
||||||
# K线的KDJ指标计算数据
|
# K线的KDJ指标计算数据
|
||||||
self.inputKdjLen = EMPTY_INT # KDJ指标的长度,缺省是9
|
self.inputKdjLen = EMPTY_INT # KDJ指标的长度,缺省是9
|
||||||
@ -497,12 +502,14 @@ class CtaLineBar(object):
|
|||||||
or (tick.datetime.hour == 2 and tick.datetime.minute == 30):
|
or (tick.datetime.hour == 2 and tick.datetime.minute == 30):
|
||||||
endtick = True
|
endtick = True
|
||||||
|
|
||||||
|
# 夜盘1:30收盘
|
||||||
if self.shortSymbol in NIGHT_MARKET_SQ2 and tick.datetime.hour == 1 and tick.datetime.minute == 00:
|
if self.shortSymbol in NIGHT_MARKET_SQ2 and tick.datetime.hour == 1 and tick.datetime.minute == 00:
|
||||||
endtick = True
|
endtick = True
|
||||||
|
|
||||||
|
# 夜盘23:00收盘
|
||||||
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
|
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
|
||||||
endtick = True
|
endtick = True
|
||||||
|
# 夜盘23:30收盘
|
||||||
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
|
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
|
||||||
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
|
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
|
||||||
endtick = True
|
endtick = True
|
||||||
@ -1109,10 +1116,25 @@ class CtaLineBar(object):
|
|||||||
del self.lineMiddleBand[0]
|
del self.lineMiddleBand[0]
|
||||||
if len(self.lineLowerBand) > self.inputBollLen*8:
|
if len(self.lineLowerBand) > self.inputBollLen*8:
|
||||||
del self.lineLowerBand[0]
|
del self.lineLowerBand[0]
|
||||||
|
if len(self.lineBollStd) > self.inputBollLen * 8:
|
||||||
|
del self.lineBollStd[0]
|
||||||
|
|
||||||
|
# 1标准差
|
||||||
|
std = (upper[-1] - lower[-1]) / (self.inputBollStdRate*2)
|
||||||
|
self.lineBollStd.append(std)
|
||||||
|
|
||||||
|
u = round(upper[-1], 2)
|
||||||
|
self.lineUpperBand.append(u) # 上轨
|
||||||
|
self.lastBollUpper = u - u % self.minDiff # 上轨取整
|
||||||
|
|
||||||
|
m = round(middle[-1], 2)
|
||||||
|
self.lineMiddleBand.append(m) # 中轨
|
||||||
|
self.lastBollMiddle = m - m % self.minDiff # 中轨取整
|
||||||
|
|
||||||
|
l = round(lower[-1], 2)
|
||||||
|
self.lineLowerBand.append(l) # 下轨
|
||||||
|
self.lastBollLower = l - l % self.minDiff # 下轨取整
|
||||||
|
|
||||||
self.lineUpperBand.append(upper[-1])
|
|
||||||
self.lineMiddleBand.append(middle[-1])
|
|
||||||
self.lineLowerBand.append(lower[-1])
|
|
||||||
|
|
||||||
def __recountKdj(self):
|
def __recountKdj(self):
|
||||||
"""KDJ指标"""
|
"""KDJ指标"""
|
||||||
@ -1277,3 +1299,232 @@ class CtaLineBar(object):
|
|||||||
if DEBUGCTALOG:
|
if DEBUGCTALOG:
|
||||||
self.strategy.writeCtaLog(u'['+self.name+u'-DEBUG]'+content)
|
self.strategy.writeCtaLog(u'['+self.name+u'-DEBUG]'+content)
|
||||||
|
|
||||||
|
|
||||||
|
class CtaDayBar(object):
|
||||||
|
"""日线"""
|
||||||
|
|
||||||
|
# 区别:
|
||||||
|
# -使用tick模式时,当tick到达后,最新一个lineBar[-1]是当前的正在拟合的bar,不断累积tick,传统按照OnBar来计算的话,是使用LineBar[-2]。
|
||||||
|
# -使用bar模式时,当一个bar到达时,lineBar[-1]是当前生成出来的Bar,不再更新
|
||||||
|
TICK_MODE = 'tick'
|
||||||
|
BAR_MODE = 'bar'
|
||||||
|
|
||||||
|
# 参数列表,保存了参数的名称
|
||||||
|
paramList = ['vtSymbol']
|
||||||
|
|
||||||
|
def __init__(self, strategy, onBarFunc, setting=None, ):
|
||||||
|
|
||||||
|
self.paramList.append('inputPreLen')
|
||||||
|
self.paramList.append('minDiff')
|
||||||
|
self.paramList.append('shortSymbol')
|
||||||
|
self.paramList.append('name')
|
||||||
|
|
||||||
|
# 输入参数
|
||||||
|
self.name = u'DayBar'
|
||||||
|
|
||||||
|
self.mode = self.TICK_MODE
|
||||||
|
self.inputPreLen = EMPTY_INT # 1
|
||||||
|
|
||||||
|
# OnBar事件回调函数
|
||||||
|
self.onBarFunc = onBarFunc
|
||||||
|
|
||||||
|
self.lineBar = []
|
||||||
|
|
||||||
|
self.currTick = None
|
||||||
|
self.lastTick = None
|
||||||
|
|
||||||
|
self.shortSymbol = EMPTY_STRING # 商品的短代码
|
||||||
|
self.minDiff = 1 # 商品的最小价格单位
|
||||||
|
|
||||||
|
|
||||||
|
def onTick(self, tick):
|
||||||
|
"""行情更新"""
|
||||||
|
|
||||||
|
if self.currTick is None:
|
||||||
|
self.currTick = tick
|
||||||
|
|
||||||
|
self.__drawLineBar(tick)
|
||||||
|
|
||||||
|
self.lastTick = tick
|
||||||
|
|
||||||
|
|
||||||
|
def addBar(self, bar):
|
||||||
|
"""予以外部初始化程序增加bar"""
|
||||||
|
l1 = len(self.lineBar)
|
||||||
|
|
||||||
|
if l1 == 0:
|
||||||
|
bar.datetme = bar.datetime.replace(minute=0, second=0)
|
||||||
|
bar.time = bar.datetime.strftime('%H:%M:%S')
|
||||||
|
self.lineBar.append(bar)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 与最后一个BAR的时间比对,判断是否超过K线的周期
|
||||||
|
lastBar = self.lineBar[-1]
|
||||||
|
|
||||||
|
if bar.tradingDay != lastBar.datetime:
|
||||||
|
bar.datetme = bar.datetime.replace(minute=0, second=0)
|
||||||
|
bar.time = bar.datetime.strftime('%H:%M:%S')
|
||||||
|
self.lineBar.append(bar)
|
||||||
|
self.onBar(lastBar)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 更新最后一个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.mid4 = round((2 * lastBar.close + lastBar.high + lastBar.low) / 4, 2)
|
||||||
|
lastBar.mid5 = round((2 * lastBar.close + lastBar.open + lastBar.high + lastBar.low) / 5, 2)
|
||||||
|
|
||||||
|
def __firstTick(self, tick):
|
||||||
|
""" K线的第一个Tick数据"""
|
||||||
|
self.bar = CtaBarData() # 创建新的K线
|
||||||
|
|
||||||
|
self.bar.vtSymbol = tick.vtSymbol
|
||||||
|
self.bar.symbol = tick.symbol
|
||||||
|
self.bar.exchange = tick.exchange
|
||||||
|
self.bar.openInterest = tick.openInterest
|
||||||
|
|
||||||
|
self.bar.open = tick.lastPrice # O L H C
|
||||||
|
self.bar.high = tick.lastPrice
|
||||||
|
self.bar.low = tick.lastPrice
|
||||||
|
self.bar.close = tick.lastPrice
|
||||||
|
|
||||||
|
# K线的日期时间
|
||||||
|
self.bar.tradingDay = tick.tradingDay # K线所在的交易日期
|
||||||
|
self.bar.date = tick.date # K线的日期,(夜盘的话,与交易日期不同哦)
|
||||||
|
|
||||||
|
self.bar.datetime = tick.datetime
|
||||||
|
# K线的日期时间(去除分钟、秒)设为第一个Tick的时间
|
||||||
|
self.bar.datetime = self.bar.datetime.replace(minute=0, second=0, microsecond=0)
|
||||||
|
self.bar.time = self.bar.datetime.strftime('%H:%M:%S')
|
||||||
|
|
||||||
|
self.barFirstTick = True # 标识该Tick属于该Bar的第一个tick数据
|
||||||
|
|
||||||
|
self.lineBar.append(self.bar) # 推入到lineBar队列
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
def __drawLineBar(self, tick):
|
||||||
|
"""生成 line Bar """
|
||||||
|
l1 = len(self.lineBar)
|
||||||
|
# 保存第一个K线数据
|
||||||
|
if l1 == 0:
|
||||||
|
self.__firstTick(tick)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 清除480周期前的数据,
|
||||||
|
if l1 > 60 * 8:
|
||||||
|
del self.lineBar[0]
|
||||||
|
|
||||||
|
# 与最后一个BAR的时间比对,判断是否超过5分钟
|
||||||
|
lastBar = self.lineBar[-1]
|
||||||
|
|
||||||
|
# 处理日内的间隔时段最后一个tick,如10:15分,11:30分,15:00 和 2:30分
|
||||||
|
endtick = False
|
||||||
|
if (tick.datetime.hour == 10 and tick.datetime.minute == 15) \
|
||||||
|
or (tick.datetime.hour == 11 and tick.datetime.minute == 30) \
|
||||||
|
or (tick.datetime.hour == 15 and tick.datetime.minute == 00) \
|
||||||
|
or (tick.datetime.hour == 2 and tick.datetime.minute == 30):
|
||||||
|
endtick = True
|
||||||
|
|
||||||
|
# 夜盘1:30收盘
|
||||||
|
if self.shortSymbol in NIGHT_MARKET_SQ2 and tick.datetime.hour == 1 and tick.datetime.minute == 00:
|
||||||
|
endtick = True
|
||||||
|
|
||||||
|
# 夜盘23:00收盘
|
||||||
|
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
|
||||||
|
endtick = True
|
||||||
|
# 夜盘23:30收盘
|
||||||
|
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
|
||||||
|
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
|
||||||
|
endtick = True
|
||||||
|
|
||||||
|
# 满足时间要求,tick的时间(夜盘21点;或者日盘9点,上一个tick为日盘收盘时间
|
||||||
|
if (tick.datetime.hour == 21 or tick.datetime.hour == 9 ) and 14 <= self.lastTick.datetime.hour <= 15:
|
||||||
|
# 创建并推入新的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的颜色
|
||||||
|
if lastBar.close > lastBar.open:
|
||||||
|
lastBar.color = COLOR_RED
|
||||||
|
elif lastBar.close < lastBar.open:
|
||||||
|
lastBar.color = COLOR_BLUE
|
||||||
|
else:
|
||||||
|
lastBar.color = COLOR_EQUAL
|
||||||
|
|
||||||
|
def displayLastBar(self):
|
||||||
|
"""显示最后一个Bar的信息"""
|
||||||
|
msg = u'[' + self.name + u']'
|
||||||
|
|
||||||
|
if len(self.lineBar) < 2:
|
||||||
|
return msg
|
||||||
|
|
||||||
|
if self.mode == self.TICK_MODE:
|
||||||
|
displayBar = self.lineBar[-2]
|
||||||
|
else:
|
||||||
|
displayBar = self.lineBar[-1]
|
||||||
|
|
||||||
|
msg = msg + u'{0} o:{1};h{2};l:{3};c:{4}'. \
|
||||||
|
format(displayBar.date + ' ' + displayBar.time, displayBar.open, displayBar.high,
|
||||||
|
displayBar.low, displayBar.close)
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def onBar(self, bar):
|
||||||
|
"""OnBar事件"""
|
||||||
|
|
||||||
|
self.__recountPreHighLow()
|
||||||
|
|
||||||
|
# 回调上层调用者
|
||||||
|
self.onBarFunc(bar)
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
def __recountPreHighLow(self):
|
||||||
|
"""计算 K线的前周期最高和最低"""
|
||||||
|
|
||||||
|
if self.inputPreLen <= 0: return # 不计算
|
||||||
|
|
||||||
|
# 1、lineBar满足长度才执行计算
|
||||||
|
if len(self.lineBar) < self.inputPreLen:
|
||||||
|
self.writeCtaLog(u'数据未充分,当前{0}r数据数量:{1},计算High、Low需要:{2}'.
|
||||||
|
format(self.name, len(self.lineBar), self.inputPreLen))
|
||||||
|
return
|
||||||
|
|
||||||
|
# 2.计算前inputPreLen周期内(不包含当前周期)的Bar高点和低点
|
||||||
|
preHigh = EMPTY_FLOAT
|
||||||
|
preLow = EMPTY_FLOAT
|
||||||
|
|
||||||
|
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周期高点
|
||||||
|
|
||||||
|
if self.lineBar[i].low < preLow or preLow == EMPTY_FLOAT:
|
||||||
|
preLow = self.lineBar[i].low # 前InputPreLen周期低点
|
||||||
|
|
||||||
|
# 保存
|
||||||
|
if len(self.preHigh) > self.inputPreLen * 8:
|
||||||
|
del self.preHigh[0]
|
||||||
|
self.preHigh.append(preHigh)
|
||||||
|
|
||||||
|
# 保存
|
||||||
|
if len(self.preLow)> self.inputPreLen * 8:
|
||||||
|
del self.preLow[0]
|
||||||
|
self.preLow.append(preLow)
|
@ -73,7 +73,6 @@ class CtaPosition:
|
|||||||
"""平、减仓"""
|
"""平、减仓"""
|
||||||
|
|
||||||
if direction == DIRECTION_LONG: # 平空仓 Cover
|
if direction == DIRECTION_LONG: # 平空仓 Cover
|
||||||
|
|
||||||
if self.pos + vol > 0:
|
if self.pos + vol > 0:
|
||||||
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},平仓:{1}'.format(self.pos,vol))
|
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},平仓:{1}'.format(self.pos,vol))
|
||||||
self.strategy.pos = self.pos
|
self.strategy.pos = self.pos
|
||||||
@ -84,7 +83,6 @@ class CtaPosition:
|
|||||||
self.strategy.pos = self.pos
|
self.strategy.pos = self.pos
|
||||||
|
|
||||||
if direction == DIRECTION_SHORT: # 平多仓
|
if direction == DIRECTION_SHORT: # 平多仓
|
||||||
|
|
||||||
if self.pos - vol < 0 :
|
if self.pos - vol < 0 :
|
||||||
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1}'.format(self.pos, vol))
|
self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1}'.format(self.pos, vol))
|
||||||
self.strategy.pos = self.pos
|
self.strategy.pos = self.pos
|
||||||
|
@ -8,13 +8,15 @@
|
|||||||
在CTA_setting.json中写入具体每个策略对象的类和合约设置。
|
在CTA_setting.json中写入具体每个策略对象的类和合约设置。
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ctaTemplate import DataRecorder
|
#from ctaTemplate import DataRecorder
|
||||||
from ctaDemo import DoubleEmaDemo
|
#from ctaDemo import DoubleEmaDemo
|
||||||
from strategy22_ArbitrageGrid import Strategy22
|
from strategy22_ArbitrageGrid import Strategy22
|
||||||
from strategy24_M15RB import Strategy24
|
from strategy24_M15RB import Strategy24
|
||||||
|
from strategy25_NonStdArbitrageGrid import Strategy25
|
||||||
|
|
||||||
STRATEGY_CLASS = {}
|
STRATEGY_CLASS = {}
|
||||||
STRATEGY_CLASS['DataRecorder'] = DataRecorder
|
#STRATEGY_CLASS['DataRecorder'] = DataRecorder
|
||||||
STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo
|
#STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo
|
||||||
STRATEGY_CLASS['Strategy22'] = Strategy22
|
STRATEGY_CLASS['Strategy22'] = Strategy22
|
||||||
STRATEGY_CLASS['Strategy24'] = Strategy24
|
STRATEGY_CLASS['Strategy24'] = Strategy24
|
||||||
|
STRATEGY_CLASS['Strategy25'] = Strategy25
|
@ -257,108 +257,9 @@ class CtaTemplate(object):
|
|||||||
def putEvent(self):
|
def putEvent(self):
|
||||||
"""发出策略状态变化事件"""
|
"""发出策略状态变化事件"""
|
||||||
self.ctaEngine.putStrategyEvent(self.name)
|
self.ctaEngine.putStrategyEvent(self.name)
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
class DataRecorder(CtaTemplate):
|
|
||||||
"""
|
|
||||||
纯粹用来记录历史数据的工具(基于CTA策略),
|
|
||||||
建议运行在实际交易程序外的一个vn.trader实例中,
|
|
||||||
本工具会记录Tick和1分钟K线数据。
|
|
||||||
"""
|
|
||||||
className = 'DataRecorder'
|
|
||||||
author = u'用Python的交易员'
|
|
||||||
|
|
||||||
# 策略的基本参数
|
|
||||||
name = EMPTY_UNICODE # 策略实例名称
|
|
||||||
vtSymbol = EMPTY_STRING # 交易的合约vt系统代码
|
|
||||||
|
|
||||||
# 策略的变量
|
|
||||||
bar = None # K线数据对象
|
|
||||||
barMinute = EMPTY_STRING # 当前的分钟,初始化设为-1
|
|
||||||
|
|
||||||
# 变量列表,保存了变量的名称
|
|
||||||
varList = ['inited',
|
|
||||||
'trading',
|
|
||||||
'pos',
|
|
||||||
'barMinute']
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def __init__(self, ctaEngine, setting):
|
def getEngineType(self):
|
||||||
"""Constructor"""
|
"""查询当前运行的环境"""
|
||||||
super(DataRecorder, self).__init__(ctaEngine, setting)
|
return self.ctaEngine.engineType
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onInit(self):
|
|
||||||
"""初始化"""
|
|
||||||
self.writeCtaLog(u'数据记录工具初始化')
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onStart(self):
|
|
||||||
"""启动策略(必须由用户继承实现)"""
|
|
||||||
self.writeCtaLog(u'数据记录工具启动')
|
|
||||||
self.putEvent()
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onStop(self):
|
|
||||||
"""停止策略(必须由用户继承实现)"""
|
|
||||||
self.writeCtaLog(u'数据记录工具停止')
|
|
||||||
self.putEvent()
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onTick(self, tick):
|
|
||||||
"""收到行情TICK推送"""
|
|
||||||
# 收到Tick后,首先插入到数据库里
|
|
||||||
self.insertTick(tick)
|
|
||||||
|
|
||||||
# 计算K线
|
|
||||||
tickMinute = tick.datetime.minute
|
|
||||||
|
|
||||||
if tickMinute != self.barMinute: # 如果分钟变了,则把旧的K线插入数据库,并生成新的K线
|
|
||||||
if self.bar:
|
|
||||||
self.onBar(self.bar)
|
|
||||||
|
|
||||||
bar = CtaBarData() # 创建新的K线,目的在于防止之前K线对象在插入Mongo中被再次修改,导致出错
|
|
||||||
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
|
|
||||||
|
|
||||||
bar.volume = bar.volume + tick.volume # 成交量是累加的
|
|
||||||
bar.openInterest = tick.openInterest # 持仓量直接更新
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onOrder(self, order):
|
|
||||||
"""收到委托变化推送"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onTrade(self, trade):
|
|
||||||
"""收到成交推送"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onBar(self, bar):
|
|
||||||
"""收到Bar推送"""
|
|
||||||
self.insertBar(bar)
|
|
@ -8,6 +8,7 @@ CTA模块相关的GUI控制组件
|
|||||||
from uiBasicWidget import QtGui, QtCore, BasicCell
|
from uiBasicWidget import QtGui, QtCore, BasicCell
|
||||||
from eventEngine import *
|
from eventEngine import *
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
@ -54,6 +55,8 @@ class CtaValueMonitor(QtGui.QTableWidget):
|
|||||||
cell = self.keyCellDict[k]
|
cell = self.keyCellDict[k]
|
||||||
cell.setText(unicode(v))
|
cell.setText(unicode(v))
|
||||||
|
|
||||||
|
self.resizeColumnsToContents()
|
||||||
|
self.resizeRowsToContents()
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class CtaStrategyManager(QtGui.QGroupBox):
|
class CtaStrategyManager(QtGui.QGroupBox):
|
||||||
@ -183,7 +186,9 @@ class CtaEngineManager(QtGui.QWidget):
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def initUi(self):
|
def initUi(self):
|
||||||
"""初始化界面"""
|
"""初始化界面"""
|
||||||
self.setWindowTitle(u'CTA策略')
|
path = os.getcwd().rsplit('\\')[-1]
|
||||||
|
|
||||||
|
self.setWindowTitle(u'{0} CTA策略'.format(path))
|
||||||
|
|
||||||
# 按钮
|
# 按钮
|
||||||
loadButton = QtGui.QPushButton(u'加载策略')
|
loadButton = QtGui.QPushButton(u'加载策略')
|
||||||
|
Loading…
Reference in New Issue
Block a user