def loadSetting(self): """载入设置""" with open(self.settingFileName) as f: setting = json.load(f) # 如果working设为False则不启动行情记录功能 working = setting['working'] if not working: return if 'tick' in setting: l = setting['tick'] for symbol, gatewayName in l: drTick = DrTickData() # 该tick实例可以用于缓存部分数据(目前未使用) self.tickDict[symbol] = drTick req = VtSubscribeReq() req.symbol = symbol self.mainEngine.subscribe(req, gatewayName) if 'bar' in setting: l = setting['bar'] for symbol, gatewayName in l: bar = DrBarData() self.barDict[symbol] = bar m5bar = DrBarData() self.m5barDict[symbol] = m5bar daybar = DrBarData() self.daybarDict[symbol] = daybar req = VtSubscribeReq() req.symbol = symbol self.mainEngine.subscribe(req, gatewayName) if 'active' in setting: d = setting['active'] for activeSymbol, symbol in d.items(): self.activeSymbolDict[symbol] = activeSymbol if 'time' in setting: self.timeDict = setting['time'] #启动数据插入线程 self.start() # 注册事件监听 self.registerEvent()
def initStrategy(self, name, strategyClass, paramDict=None): """初始化策略""" # 防止策略重名 if name not in self.strategyDict: # 创建策略对象 strategy = strategyClass(self, name, paramDict) self.strategyDict[name] = strategy # 保存Tick映射关系 if strategy.vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[strategy.vtSymbol] else: l = [] self.tickStrategyDict[strategy.vtSymbol] = l l.append(strategy) # 订阅合约 contract = self.mainEngine.getContract(strategy.vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' %(name, strategy.vtSymbol)) else: self.writeCtaLog(u'存在策略对象重名:' + name)
def updateSymbol(self): """合约变化""" # 读取组件数据 instrumentid = str(self.codeEdit.text()) # 获取合约 # instrument = self.__chanlunEngine.selectInstrument(instrumentid) # 重新注册事件监听 self.eventEngine.unregister(EVENT_TICK + self.instrumentid, self.signal.emit) self.eventEngine.register(EVENT_TICK + instrumentid, self.signal.emit) # 订阅合约 # self.__mainEngine.subscribe(instrumentid, instrument['ExchangeID']) # 订阅合约[仿照ctaEngine.py写的] contract = self.mainEngine.getContract(instrumentid) if contract: req = VtSubscribeReq() req.symbol = contract.symbol self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeChanlunLog(u'交易合约%s无法找到' % (instrumentid)) # 更新目前的合约 self.instrumentid = instrumentid
def updateSymbol(self): """合约变化""" # 读取组件数据 symbol = self.symbol exchange = None vtSymbol = None # 查询合约 if exchange: vtSymbol = '.'.join([symbol, exchange]) contract = self.__mainEngine.getContract(vtSymbol) else: vtSymbol = symbol contract = self.__mainEngine.getContract(symbol) if contract: vtSymbol = contract.vtSymbol gatewayName = contract.gatewayName print(contract.name) exchange = contract.exchange # 保证有交易所代码 # 重新注册事件监听 self.__eventEngine.unregister(EVENT_TICK + symbol, self.signal.emit) self.__eventEngine.register(EVENT_TICK + vtSymbol, self.signal.emit) # 订阅合约 req = VtSubscribeReq() req.symbol = symbol req.exchange = exchange #req.currency = currency req.productClass = PRODUCT_FUTURES self.__mainEngine.subscribe(req, gatewayName) # 更新组件当前交易的合约 self.symbol = vtSymbol
def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception as e: self.writeCtaLog(u'载入策略出错:%s' % e) return # 获取策略类 strategyClass = STRATEGY_CLASS.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' % className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' % name) else: # 1.创建策略对象 strategy = strategyClass(self, setting) self.strategyDict[name] = strategy # 2.保存Tick映射关系(symbol <==> Strategy[] ) # modifid by Incenselee 支持多个Symbol的订阅 symbols = strategy.vtSymbol.split(';') for symbol in symbols: if symbol in self.tickStrategyDict: l = self.tickStrategyDict[symbol] else: l = [] self.tickStrategyDict[symbol] = l l.append(strategy) # 3.订阅合约 contract = self.mainEngine.getContract(symbol) if contract: # 4.构造订阅请求包 req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass # 5.调用主引擎的订阅接口 self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, symbol))
def subscribeMarketData(self, strategy): """订阅行情""" # 订阅合约 contract = self.mainEngine.getContract(strategy.vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (strategy.name, strategy.vtSymbol))
def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except: self.writeCtaLog(u'载入策略出错:%s' % traceback.format_exc()) return # 获取策略类 strategyClass = STRATEGY_CLASS.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' % className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' % name) else: # 创建策略实例 strategy = strategyClass(self, setting) self.strategyDict[name] = strategy # 保存Tick映射关系 if strategy.vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[strategy.vtSymbol] else: l = [] self.tickStrategyDict[strategy.vtSymbol] = l l.append(strategy) # 订阅合约 contract = self.mainEngine.getContract(strategy.vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, strategy.vtSymbol))
def loadSetting(self): """载入设置""" with open(self.settingFileName) as f: drSetting = json.load(f) # 如果working设为False则不启动行情记录功能 working = drSetting['working'] if not working: return if 'bar' in drSetting: l = drSetting['bar'] for setting in l: vtSymbol = setting.get('vtSymbol') hisGatewayName = setting.get('hisGatewayName') if vtSymbol: contract = self.mainEngine.getContract(vtSymbol) if not contract: print u'请先手动订阅成功一次' req = VtSubscribeReq() req.symbol = contract.symbol req.currency = contract.currency req.exchange = contract.exchange req.productClass = contract.productClass if vtSymbol in self.vtSymbolContractDict: pass else: l = {} self.vtSymbolContractDict[vtSymbol] = l l['hisGatewayName'] = hisGatewayName l['contract'] = req # 注册事件监听 self.registerEvent()
class CtaEngine(object): """CTA策略引擎""" settingFileName = 'CTA_setting.json' settingFileName = os.getcwd() + '/ctaAlgo/' + settingFileName #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): """Constructor""" self.mainEngine = mainEngine self.eventEngine = eventEngine # 当前日期 self.today = todayDate() # 保存策略实例的字典 # key为策略名称,value为策略实例,注意策略名称不允许重复 self.strategyDict = {} # 保存vtSymbol和策略实例映射的字典(用于推送tick数据) # 由于可能多个strategy交易同一个vtSymbol,因此key为vtSymbol # value为包含所有相关strategy对象的list self.tickStrategyDict = {} # 保存vtOrderID和strategy对象映射的字典(用于推送order和trade数据) # key为vtOrderID,value为strategy对象 self.orderStrategyDict = {} # 本地停止单编号计数 self.stopOrderCount = 0 # stopOrderID = STOPORDERPREFIX + str(stopOrderCount) # 本地停止单字典 # key为stopOrderID,value为stopOrder对象 self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 # 持仓缓存字典 # key为vtSymbol,value为PositionBuffer对象 self.posBufferDict = {} # 引擎类型为实盘 self.engineType = ENGINETYPE_TRADING # 注册事件监听 self.registerEvent() #---------------------------------------------------------------------- def sendOrder(self, vtSymbol, orderType, price, volume, strategy): """发单""" contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = price req.volume = volume req.productClass = strategy.productClass req.currency = strategy.currency # 设计为CTA引擎发出的委托只允许使用限价单 req.priceType = PRICETYPE_LIMITPRICE # CTA委托类型映射 if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有多头今仓,则使用平今 elif posBuffer.longToday: req.offset= OFFSET_CLOSETODAY # 其他情况使用平昨 else: req.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有空头今仓,则使用平今 elif posBuffer.shortToday: req.offset= OFFSET_CLOSETODAY # 其他情况使用平昨 else: req.offset = OFFSET_CLOSE vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog(u'策略%s发送委托,%s,%s,%s@%s' %(strategy.name, vtSymbol, req.direction, volume, price)) return vtOrderID #---------------------------------------------------------------------- def cancelOrder(self, vtOrderID): """撤单""" # 查询报单对象 order = self.mainEngine.getOrder(vtOrderID) # 如果查询成功 if order: # 检查是否报单还有效,只有有效时才发出撤单指令 orderFinished = (order.status==STATUS_ALLTRADED or order.status==STATUS_CANCELLED) if not orderFinished: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) #---------------------------------------------------------------------- def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy): """发停止单(本地实现)""" self.stopOrderCount += 1 stopOrderID = STOPORDERPREFIX + str(self.stopOrderCount) so = StopOrder() so.vtSymbol = vtSymbol so.orderType = orderType so.price = price so.volume = volume so.strategy = strategy so.stopOrderID = stopOrderID so.status = STOPORDER_WAITING if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG so.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: so.direction = DIRECTION_SHORT so.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: so.direction = DIRECTION_SHORT so.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: so.direction = DIRECTION_LONG so.offset = OFFSET_CLOSE # 保存stopOrder对象到字典中 self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so return stopOrderID #---------------------------------------------------------------------- def cancelStopOrder(self, stopOrderID): """撤销停止单""" # 检查停止单是否存在 if stopOrderID in self.workingStopOrderDict: so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] #---------------------------------------------------------------------- def processStopOrder(self, tick): """收到行情后处理本地停止单(检查是否要立即发出)""" vtSymbol = tick.vtSymbol # 首先检查是否有策略交易该合约 if vtSymbol in self.tickStrategyDict: # 遍历等待中的停止单,检查是否会被触发 for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: longTriggered = so.direction==DIRECTION_LONG and tick.lastPrice>=so.price # 多头停止单被触发 shortTriggered = so.direction==DIRECTION_SHORT and tick.lastPrice<=so.price # 空头停止单被触发 if longTriggered or shortTriggered: # 买入和卖出分别以涨停跌停价发单(模拟市价单) if so.direction==DIRECTION_LONG: price = tick.upperLimit else: price = tick.lowerLimit so.status = STOPORDER_TRIGGERED self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) del self.workingStopOrderDict[so.stopOrderID] #---------------------------------------------------------------------- def procecssTickEvent(self, event): """处理行情推送""" tick = event.dict_['data'] # 收到tick行情后,先处理本地停止单(检查是否要立即发出) self.processStopOrder(tick) # 推送tick到对应的策略实例进行处理 if tick.vtSymbol in self.tickStrategyDict: # 将vtTickData数据转化为ctaTickData ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): if key != 'datetime': d[key] = tick.__getattribute__(key) # 添加datetime字段 ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: strategy.onTick(ctaTick) #---------------------------------------------------------------------- def processOrderEvent(self, event): """处理委托推送""" order = event.dict_['data'] if order.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] strategy.onOrder(order) #---------------------------------------------------------------------- def processTradeEvent(self, event): """处理成交推送""" trade = event.dict_['data'] if trade.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[trade.vtOrderID] # 计算策略持仓 if trade.direction == DIRECTION_LONG: strategy.pos += trade.volume else: strategy.pos -= trade.volume strategy.onTrade(trade) # 更新持仓缓存数据 if trade.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(trade.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = trade.vtSymbol self.posBufferDict[trade.vtSymbol] = posBuffer posBuffer.updateTradeData(trade) #---------------------------------------------------------------------- def processPositionEvent(self, event): """处理持仓推送""" pos = event.dict_['data'] # 更新持仓缓存数据 if pos.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(pos.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = pos.vtSymbol self.posBufferDict[pos.vtSymbol] = posBuffer posBuffer.updatePositionData(pos) #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" self.eventEngine.register(EVENT_TICK, self.procecssTickEvent) self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)""" self.mainEngine.dbInsert(dbName, collectionName, data.__dict__) #---------------------------------------------------------------------- def loadBar(self, dbName, collectionName, days): """从数据库中读取Bar数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: bar = CtaBarData() bar.__dict__ = d l.append(bar) return l #---------------------------------------------------------------------- def loadTick(self, dbName, collectionName, days): """从数据库中读取Tick数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: tick = CtaTickData() tick.__dict__ = d l.append(tick) return l #---------------------------------------------------------------------- def writeCtaLog(self, content): """快速发出CTA模块日志事件""" log = VtLogData() log.logContent = content event = Event(type_=EVENT_CTA_LOG) event.dict_['data'] = log self.eventEngine.put(event) #---------------------------------------------------------------------- def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception, e: self.writeCtaLog(u'载入策略出错:%s' %e) return # 获取策略类 strategyClass = STRATEGY_CLASS.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' %className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' %name) else: # 创建策略实例 strategy = strategyClass(self, setting) self.strategyDict[name] = strategy # 保存Tick映射关系 if strategy.vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[strategy.vtSymbol] else: l = [] self.tickStrategyDict[strategy.vtSymbol] = l l.append(strategy) # 订阅合约 contract = self.mainEngine.getContract(strategy.vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' %(name, strategy.vtSymbol))
# 保存Tick映射关系 vtSymbolset = setting['vtSymbol'] vtSymbolList = vtSymbolset.split(',') for vtSymbol in vtSymbolList: #by hw 单个策略订阅多个合约,配置文件中"vtSymbol": "IF1602,IF1603" if vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[vtSymbol] else: l = [] self.tickStrategyDict[vtSymbol] = l l.append(strategy) # 订阅合约 contract = self.mainEngine.getContract(vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, vtSymbol)) #---------------------------------------------------------------------- def initStrategy(self, name): """初始化策略""" if name in self.strategyDict: strategy = self.strategyDict[name]
def loadSetting(self): """载入设置""" with open(self.settingFileName) as f: drSetting = json.load(f) # 如果working设为False则不启动行情记录功能 working = drSetting['working'] if not working: return if 'tick' in drSetting: l = drSetting['tick'] for setting in l: symbol = setting[0] vtSymbol = symbol req = VtSubscribeReq() req.symbol = setting[0] # 针对LTS和IB接口,订阅行情需要交易所代码 if len(setting) >= 3: req.exchange = setting[2] vtSymbol = '.'.join([symbol, req.exchange]) # 针对IB接口,订阅行情需要货币和产品类型 if len(setting) >= 5: req.currency = setting[3] req.productClass = setting[4] self.mainEngine.subscribe(req, setting[1]) drTick = DrTickData() # 该tick实例可以用于缓存部分数据(目前未使用) self.tickDict[vtSymbol] = drTick if 'bar' in drSetting: l = drSetting['bar'] for setting in l: symbol = setting[0] vtSymbol = symbol req = VtSubscribeReq() req.symbol = symbol if len(setting) >= 3: req.exchange = setting[2] vtSymbol = '.'.join([symbol, req.exchange]) if len(setting) >= 5: req.currency = setting[3] req.productClass = setting[4] self.mainEngine.subscribe(req, setting[1]) bar = DrBarData() self.barDict[vtSymbol] = bar if 'active' in drSetting: d = drSetting['active'] # 注意这里的vtSymbol对于IB和LTS接口,应该后缀.交易所 for activeSymbol, vtSymbol in d.items(): self.activeSymbolDict[vtSymbol] = activeSymbol # 启动数据插入线程 self.start() # 注册事件监听 self.registerEvent()
class CtaEngine(object): """CTA策略引擎""" settingFileName = 'CTA_setting.json' path = os.path.abspath(os.path.dirname(__file__)) settingFileName = os.path.join(path, settingFileName) #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine, context=' '): """Constructor""" self.context = context self.doCheck() self.mainEngine = mainEngine self.eventEngine = eventEngine #================================================================= self.posFileName = "PositionInfo.json" self.mPosInfo = {} self.loadPosInfo() #================================================================= # 当前日期 self.today = todayDate() self.dbtype = 'mongodb' # 保存策略实例的字典 # key为策略名称,value为策略实例,注意策略名称不允许重复 self.strategyDict = {} # 保存vtSymbol和策略实例映射的字典(用于推送tick数据) # 由于可能多个strategy交易同一个vtSymbol,因此key为vtSymbol # value为包含所有相关strategy对象的list self.tickStrategyDict = {} # 保存vtOrderID和strategy对象映射的字典(用于推送order和trade数据) # key为vtOrderID,value为strategy对象 self.orderStrategyDict = {} # 本地停止单编号计数 self.stopOrderCount = 0 # stopOrderID = STOPORDERPREFIX + str(stopOrderCount) # 本地停止单字典 # key为stopOrderID,value为stopOrder对象 self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 # 持仓缓存字典 # key为vtSymbol,value为PositionBuffer对象 self.posBufferDict = {} # 引擎类型为实盘 self.engineType = ENGINETYPE_TRADING # 注册事件监听 self.registerEvent() def doCheck(self): try: if not self.context.check_token(): exit() except: exit() #============================================================================== #============================================================================== #============================================================================== def loadPosInfo(self): with open(self.posFileName, 'r') as f: self.mPosInfo = json.load(f) def savePosInfo(self): with open(self.posFileName, 'w') as f: json.dump(self.mPosInfo, f) def excPos(self, name=None): for x in self.mPosInfo.keys(): self.mPosInfo[x]['long']['ytd'] += self.mPosInfo[x]['long']['td'] self.mPosInfo[x]['long']['td'] = 0 self.mPosInfo[x]['short']['ytd'] += self.mPosInfo[x]['short']['td'] self.mPosInfo[x]['short']['td'] = 0 with open(self.posFileName, 'w') as f: json.dump(self.mPosInfo, f) def addStrategy(self, setting, strategyName=None, strategyType=None): with open(self.settingFileName, 'r') as f: l = json.load(f) f.close() for x in l: if x['name'] == setting['name']: self.writeCtaLog(u'策略实例重名!!') return -1 with open(self.settingFileName, 'w') as f: l.append(setting) json.dump(l, f) f.close() def chStrategy(self, setting, strategyName=None, strategyType=None): with open(self.settingFileName, 'r') as f: l = json.load(f) f.close() for x in range(0, len(l)): if l[x]['name'] == setting['name']: l[x] = setting with open(self.settingFileName, 'w') as f: json.dump(l, f) f.close() #============================================================================== #============================================================================== #============================================================================== def sendIBOrder(self, vtSymbol, orderType, price, volume, strategy, isMKT): contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = price - price % contract.priceTick req.volume = volume if isMKT: req.priceType = PRICETYPE_MARKETPRICE else: req.priceType = PRICETYPE_LIMITPRICE req.productClass = strategy.productClass req.currency = strategy.currency if orderType == CTAORDER_BUY or orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG else: req.direction = DIRECTION_SHORT vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName, strategy) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog( u'策略%s发送委托,%s,%s,%s@%s' % (strategy.name, vtSymbol, req.direction, volume, price)) return vtOrderID #---------------------------------------------------------------------- def sendOrder(self, vtSymbol, orderType, price, volume, strategy, isMKT): """发单""" contract = self.mainEngine.getContract(vtSymbol) if contract.gatewayName == "IB": return self.sendIBOrder(vtSymbol, orderType, price, volume, strategy, isMKT) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = price - price % contract.priceTick req.volume = volume closeFirst = strategy.closeFirst req.productClass = strategy.productClass req.currency = strategy.currency # 设计为CTA引擎发出的委托只允许使用限价单 req.priceType = PRICETYPE_LIMITPRICE if vtSymbol not in self.mPosInfo.keys(): l = {} l['ytd'] = 0 l['td'] = 0 s = {} s['ytd'] = 0 s['td'] = 0 self.mPosInfo[vtSymbol] = {} self.mPosInfo[vtSymbol]['long'] = l self.mPosInfo[vtSymbol]['short'] = s if closeFirst != None and closeFirst == False: if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['long']['td'] += volume elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE if self.mPosInfo[vtSymbol]['long']['td'] >= volume: self.mPosInfo[vtSymbol]['long']['td'] -= volume else: self.mPosInfo[vtSymbol]['long']['ytd'] -= volume else: # 如果获取持仓缓存失败,则默认平昨 if self.mPosInfo[vtSymbol]['long']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['long']['ytd'] -= volume # 否则如果有多头今仓,则使用平今 else: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['long']['td'] -= volume elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['short']['td'] += volume elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE if self.mPosInfo[vtSymbol]['short']['td'] >= volume: self.mPosInfo[vtSymbol]['short']['td'] -= volume else: self.mPosInfo[vtSymbol]['short']['ytd'] -= volume else: if self.mPosInfo[vtSymbol]['short']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['short']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['short']['td'] >= volume: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['short']['td'] -= volume vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName, strategy) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog(u'策略%s发送委托,%s,%s,%s, %s@%s' % (strategy.name, vtSymbol, req.direction, req.offset, volume, price)) return vtOrderID if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG if self.mPosInfo[vtSymbol]['short']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['short']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['short']['td'] >= volume: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['short']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['long']['td'] += volume elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: if self.mPosInfo[vtSymbol]['long']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['long']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['long']['td'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['long']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['short']['td'] += volume else: if self.mPosInfo[vtSymbol]['long']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['long']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['long']['td'] >= volume: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['long']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['short']['td'] += volume #======================================================================= elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT if self.mPosInfo[vtSymbol]['long']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['long']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['long']['td'] >= volume: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['long']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['short']['td'] += volume elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: if self.mPosInfo[vtSymbol]['short']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['short']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['short']['td'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['short']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['long']['td'] += volume else: if self.mPosInfo[vtSymbol]['short']['ytd'] >= volume: req.offset = OFFSET_CLOSE self.mPosInfo[vtSymbol]['short']['ytd'] -= volume elif self.mPosInfo[vtSymbol]['short']['td'] >= volume: req.offset = OFFSET_CLOSETODAY self.mPosInfo[vtSymbol]['short']['td'] -= volume else: req.offset = OFFSET_OPEN self.mPosInfo[vtSymbol]['long']['td'] += volume #======================================================================= vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName, strategy) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog( u'策略%s发送委托,%s,%s,%s@%s' % (strategy.name, vtSymbol, req.direction, volume, price)) return vtOrderID #---------------------------------------------------------------------- def cancelOrder(self, vtOrderID): """撤单""" # 查询报单对象 order = self.mainEngine.getOrder(vtOrderID) # 如果查询成功 if order: # 检查是否报单还有效,只有有效时才发出撤单指令 orderFinished = (order.status == STATUS_ALLTRADED or order.status == STATUS_CANCELLED) if not orderFinished: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) #---------------------------------------------------------------------- def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy): """发停止单(本地实现)""" self.stopOrderCount += 1 stopOrderID = STOPORDERPREFIX + str(self.stopOrderCount) so = StopOrder() so.vtSymbol = vtSymbol so.orderType = orderType so.price = price so.volume = volume so.strategy = strategy so.stopOrderID = stopOrderID so.status = STOPORDER_WAITING if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG so.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: so.direction = DIRECTION_SHORT so.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: so.direction = DIRECTION_SHORT so.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: so.direction = DIRECTION_LONG so.offset = OFFSET_CLOSE # 保存stopOrder对象到字典中 self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so return stopOrderID #---------------------------------------------------------------------- def cancelStopOrder(self, stopOrderID): """撤销停止单""" # 检查停止单是否存在 if stopOrderID in self.workingStopOrderDict: so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] #---------------------------------------------------------------------- def processStopOrder(self, tick): """收到行情后处理本地停止单(检查是否要立即发出)""" vtSymbol = tick.vtSymbol # 首先检查是否有策略交易该合约 if vtSymbol in self.tickStrategyDict: # 遍历等待中的停止单,检查是否会被触发 for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: longTriggered = so.direction == DIRECTION_LONG and tick.lastPrice >= so.price # 多头停止单被触发 shortTriggered = so.direction == DIRECTION_SHORT and tick.lastPrice <= so.price # 空头停止单被触发 if longTriggered or shortTriggered: # 买入和卖出分别以涨停跌停价发单(模拟市价单) if so.direction == DIRECTION_LONG: price = tick.upperLimit else: price = tick.lowerLimit so.status = STOPORDER_TRIGGERED self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) del self.workingStopOrderDict[so.stopOrderID] #---------------------------------------------------------------------- def processTickEvent(self, event): """处理行情推送""" tick = event.dict_['data'] # 收到tick行情后,先处理本地停止单(检查是否要立即发出) self.processStopOrder(tick) # 推送tick到对应的策略实例进行处理 if tick.vtSymbol in self.tickStrategyDict: # 将vtTickData数据转化为ctaTickData ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): if key != 'datetime': d[key] = tick.__getattribute__(key) # 添加datetime字段 ctaTick.datetime = datetime.strptime( ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: strategy.onTick(ctaTick) #---------------------------------------------------------------------- def processOrderEvent(self, event): """处理委托推送""" order = event.dict_['data'] if order.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] strategy.onOrder(order) #---------------------------------------------------------------------- def processTradeEvent(self, event): """处理成交推送""" trade = event.dict_['data'] if trade.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[trade.vtOrderID] # 计算策略持仓 if trade.vtSymbol not in strategy.pos.keys(): #by hw strategy.pos[trade.vtSymbol] = 0 if trade.direction == DIRECTION_LONG: strategy.pos[trade.vtSymbol] += trade.volume else: strategy.pos[trade.vtSymbol] -= trade.volume strategy.onTrade(trade) # 更新持仓缓存数据 if trade.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(trade.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = trade.vtSymbol self.posBufferDict[trade.vtSymbol] = posBuffer posBuffer.updateTradeData(trade) #====================================================================================== #if trade.vtSymbol not in self.mPosInfo.keys(): #self.mPosInfo[trade.vtSymbol] = 0 #if trade.offset == OFFSET_OPEN : #self.mPosInfo[trade.vtSymbol] += trade.volume #else: #if self.mPosInfo[trade.vtSymbol] > 0: # self.mPosInfo[trade.vtSymbol] -= trade.volume #====================================================================================== #---------------------------------------------------------------------- def processPositionEvent(self, event): """处理持仓推送""" pos = event.dict_['data'] # 更新持仓缓存数据 if pos.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(pos.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = pos.vtSymbol self.posBufferDict[pos.vtSymbol] = posBuffer posBuffer.updatePositionData(pos) #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" self.eventEngine.register(EVENT_TICK, self.processTickEvent) self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)""" self.mainEngine.dbInsert(dbName, collectionName, data.__dict__) #---------------------------------------------------------------------- def loadBar(self, dbName, collectionName, days): """从数据库中读取Bar数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: bar = CtaBarData() bar.__dict__ = d l.append(bar) return l #---------------------------------------------------------------------- def loadTick(self, dbName, collectionName, days): """从数据库中读取Tick数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: tick = CtaTickData() tick.__dict__ = d l.append(tick) return l #---------------------------------------------------------------------- def writeCtaLog(self, content): """快速发出CTA模块日志事件""" log = VtLogData() log.logContent = content event = Event(type_=EVENT_CTA_LOG) event.dict_['data'] = log self.eventEngine.put(event) #---------------------------------------------------------------------- def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception, e: self.writeCtaLog(u'载入策略出错:%s' % e) return # 获取策略类 strategyClass = STRATEGY_TYPE.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' % className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' % name) else: # 创建策略实例 fileName = "parameter_" + name + '.json' strategy = strategyClass(self, setting, fileName) self.strategyDict[name] = strategy # 保存Tick映射关系 vtSymbolset = setting['vtSymbol'] vtSymbolList = vtSymbolset.split(',') for vtSymbol in vtSymbolList: if vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[vtSymbol] else: l = [] self.tickStrategyDict[vtSymbol] = l l.append(strategy) # 订阅合约 if "." in vtSymbol: req = VtSubscribeReq() req.symbol = vtSymbol[:vtSymbol.index('.')] req.exchange = vtSymbol[vtSymbol.index('.') + 1:] # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, "IB") continue contract = self.mainEngine.getContract(vtSymbol) if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, vtSymbol))
class CtaEngine(object): """CTA策略引擎""" # 策略配置文件 settingFileName = 'CTA_setting.json' settingFileName = os.getcwd() + '/ctaAlgo/' + settingFileName #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): """Constructor""" self.mainEngine = mainEngine self.eventEngine = eventEngine # 当前日期 self.today = todayDate() # 保存策略实例的字典 # key为策略名称,value为策略实例,注意策略名称不允许重复 self.strategyDict = {} # 保存vtSymbol和策略实例映射的字典(用于推送tick数据) # 由于可能多个strategy交易同一个vtSymbol,因此key为vtSymbol # value为包含所有相关strategy对象的list self.tickStrategyDict = {} # 保存vtOrderID和strategy对象映射的字典(用于推送order和trade数据) # key为vtOrderID,value为strategy对象 self.orderStrategyDict = {} # 本地停止单编号计数 self.stopOrderCount = 0 # stopOrderID = STOPORDERPREFIX + str(stopOrderCount) # 本地停止单字典 # key为stopOrderID,value为stopOrder对象 self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 # 持仓缓存字典 # key为vtSymbol,value为PositionBuffer对象 self.posBufferDict = {} # 注册事件监听 self.registerEvent() # ---------------------------------------------------------------------- def sendOrder(self, vtSymbol, orderType, price, volume, strategy): """发单""" contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol # 合约代码 req.exchange = contract.exchange # 交易所 req.price = price # 价格 req.volume = volume # 数量 req.productClass = strategy.productClass req.currency = strategy.currency # 设计为CTA引擎发出的委托只允许使用限价单 req.priceType = PRICETYPE_LIMITPRICE # 价格类型 # CTA委托类型映射 if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG # 合约方向 req.offset = OFFSET_OPEN # 开/平 elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有多头今仓,则使用平今 elif posBuffer.longToday: req.offset = OFFSET_CLOSETODAY # 其他情况使用平昨 else: req.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有空头今仓,则使用平今 elif posBuffer.shortToday: req.offset = OFFSET_CLOSETODAY # 其他情况使用平昨 else: req.offset = OFFSET_CLOSE vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog(u'策略%s发送委托,%s, %s,%s,%s@%s' % (strategy.name, vtSymbol, req.offset, req.direction, volume, price)) return vtOrderID # ---------------------------------------------------------------------- def cancelOrder(self, vtOrderID): """撤单""" # 查询报单对象 # 1.调用主引擎接口,查询委托单对象 order = self.mainEngine.getOrder(vtOrderID) # 如果查询成功 if order: # 2.检查是否报单(委托单)还有效,只有有效时才发出撤单指令 orderFinished = (order.status == STATUS_ALLTRADED or order.status == STATUS_CANCELLED) if not orderFinished: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) else: if order.status == STATUS_ALLTRADED: self.writeCtaLog(u'委托单({0}已执行,无法撤销'.format(vtOrderID)) if order.status == STATUS_CANCELLED: self.writeCtaLog(u'委托单({0}已撤销,无法再次撤销'.format(vtOrderID)) # 查询不成功 else: self.writeCtaLog(u'委托单({0}不存在'.format(vtOrderID)) # ---------------------------------------------------------------------- def cancelOrders(self, symbol, offset=EMPTY_STRING): """撤销所有单""" # Symbol参数:指定合约的撤单; # OFFSET参数:指定Offset的撤单,缺省不填写时,为所有 l = self.mainEngine.getAllWorkingOrders() self.writeCtaLog(u'从所有订单{0}中撤销{1}'.format(len(l), symbol)) for order in l: if offset == EMPTY_STRING: offsetCond = True else: offsetCond = order.offset == offset if order.symbol == symbol and offsetCond: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.writeCtaLog(u'撤单:{0}/{1},{2}{3}手'.format( order.symbol, order.orderID, order.offset, order.totalVolume - order.tradedVolume)) self.mainEngine.cancelOrder(req, order.gatewayName) # ---------------------------------------------------------------------- def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy): """发停止单(本地实现)""" # 1.生成本地停止单ID self.stopOrderCount += 1 stopOrderID = STOPORDERPREFIX + str(self.stopOrderCount) # 2.创建停止单对象 so = StopOrder() so.vtSymbol = vtSymbol # 代码 so.orderType = orderType # 停止单类型 so.price = price # 价格 so.volume = volume # 数量 so.strategy = strategy # 来源策略 so.stopOrderID = stopOrderID # Id so.status = STOPORDER_WAITING # 状态 if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG so.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: so.direction = DIRECTION_SHORT so.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: so.direction = DIRECTION_SHORT so.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: so.direction = DIRECTION_LONG so.offset = OFFSET_CLOSE # 保存stopOrder对象到字典中 self.stopOrderDict[stopOrderID] = so # 字典中不会删除 self.workingStopOrderDict[stopOrderID] = so # 字典中会删除 self.writeCtaLog(u'发停止单成功,' u'Id:{0},Symbol:{1},Type:{2},Price:{3},Volume:{4}' u'.'.format(stopOrderID, vtSymbol, orderType, price, volume)) return stopOrderID # ---------------------------------------------------------------------- def cancelStopOrder(self, stopOrderID): """撤销停止单 Incense Li modified 20160124: 增加返回True 和 False """ # 1.检查停止单是否存在 if stopOrderID in self.workingStopOrderDict: so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED # STOPORDER_WAITING =》STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] # 删除 self.writeCtaLog(u'撤销停止单:{0}成功.'.format(stopOrderID)) return True else: self.writeCtaLog(u'撤销停止单:{0}失败,不存在Id.'.format(stopOrderID)) return False # ---------------------------------------------------------------------- def processStopOrder(self, tick): """收到行情后处理本地停止单(检查是否要立即发出)""" vtSymbol = tick.vtSymbol # 1.首先检查是否有策略交易该合约 if vtSymbol in self.tickStrategyDict: # 2.遍历等待中的停止单,检查是否会被触发 for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: # 3. 触发标识判断 longTriggered = so.direction == DIRECTION_LONG and tick.lastPrice >= so.price # 多头停止单被触发 shortTriggered = so.direction == DIRECTION_SHORT and tick.lasatPrice <= so.price # 空头停止单被触发 # 4.触发处理 if longTriggered or shortTriggered: # 5.设定价格,买入和卖出分别以涨停跌停价发单(模拟市价单) if so.direction == DIRECTION_LONG: price = tick.upperLimit else: price = tick.lowerLimit # 6.更新停止单状态,触发 so.status = STOPORDER_TRIGGERED # 7.发单 self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) # 8.删除停止单 del self.workingStopOrderDict[so.stopOrderID] # ---------------------------------------------------------------------- def procecssTickEvent(self, event): """处理行情推送事件""" # 1. 获取事件的Tick数据 tick = event.dict_['data'] # 2.收到tick行情后,优先处理本地停止单(检查是否要立即发出) self.processStopOrder(tick) # 3.推送tick到对应的策略对象进行处理 if tick.vtSymbol in self.tickStrategyDict: # 4.将vtTickData数据转化为ctaTickData ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): if key != 'datetime': d[key] = tick.__getattribute__(key) ctaTick.datetime = datetime.strptime( ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') # 5.添加datetime字段 if ctaTick.datetime.hour >= 20: dt = datetime.now() today = dt.strftime('%Y%m%d') ctaTick.datetime = datetime.strptime( ' '.join([today, tick.time]), '%Y%m%d %H:%M:%S.%f') ctaTick.date = today # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: strategy.onTick(ctaTick) # ---------------------------------------------------------------------- def processOrderEvent(self, event): """处理委托推送事件""" # 1.获取事件的Order数据 order = event.dict_['data'] # order.vtOrderID 在gateway中,已经格式化为 gatewayName.vtOrderID # 2.判断order是否在映射字典中 if order.vtOrderID in self.orderStrategyDict: # 3.提取对应的策略 strategy = self.orderStrategyDict[order.vtOrderID] # 4.触发策略的委托推送事件方法 strategy.onOrder(order) # ---------------------------------------------------------------------- def processTradeEvent(self, event): """处理成交推送事件""" # 1.获取事件的Trade数据 trade = event.dict_['data'] # 2.判断Trade是否在映射字典中 if trade.vtOrderID in self.orderStrategyDict: # 3.提取对应的策略 strategy = self.orderStrategyDict[trade.vtOrderID] # 计算策略持仓 if trade.direction == DIRECTION_LONG: strategy.pos += trade.volume else: strategy.pos -= trade.volume # 4.触发策略的成交推送事件。 strategy.onTrade(trade) # 更新持仓缓存数据 if trade.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(trade.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = trade.vtSymbol self.posBufferDict[trade.vtSymbol] = posBuffer posBuffer.updateTradeData(trade) #---------------------------------------------------------------------- def processPositionEvent(self, event): """处理持仓推送""" pos = event.dict_['data'] # 更新持仓缓存数据 if pos.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(pos.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = pos.vtSymbol self.posBufferDict[pos.vtSymbol] = posBuffer posBuffer.updatePositionData(pos) #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" # 注册行情数据推送(Tick数据到达)的响应事件 self.eventEngine.register(EVENT_TICK, self.procecssTickEvent) # 注册订单推送的响应事件 self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) # 注册成交推送(交易)的响应时间 self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) # 注册持仓更新事件 self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) # ---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)""" self.mainEngine.dbInsert(dbName, collectionName, data.__dict__) # ---------------------------------------------------------------------- def loadBar(self, dbName, collectionName, days): """从数据库中读取Bar数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: bar = CtaBarData() bar.__dict__ = d l.append(bar) return l # ---------------------------------------------------------------------- def loadTick(self, dbName, collectionName, days): """从数据库中读取Tick数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: tick = CtaTickData() tick.__dict__ = d l.append(tick) return l # ---------------------------------------------------------------------- def getToday(self): """获取代表今日的datetime对象""" today = datetime.today() today = today.replace(hour=0, minute=0, second=0, microsecond=0) return today # ---------------------------------------------------------------------- def writeCtaLog(self, content): """快速发出CTA模块日志事件""" log = VtLogData() log.logContent = content event = Event(type_=EVENT_CTA_LOG) event.dict_['data'] = log self.eventEngine.put(event) # 写入本地log日志 logging.info(content) # ---------------------------------------------------------------------- def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception, e: self.writeCtaLog(u'载入策略出错:%s' % e) return # 获取策略类 strategyClass = STRATEGY_CLASS.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' % className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' % name) else: # 1.创建策略对象 strategy = strategyClass(self, setting) self.strategyDict[name] = strategy # 2.保存Tick映射关系(symbol <==> Strategy[] ) if strategy.vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[strategy.vtSymbol] else: l = [] self.tickStrategyDict[strategy.vtSymbol] = l l.append(strategy) # 3.订阅合约 contract = self.mainEngine.getContract(strategy.vtSymbol) if contract: # 4.构造订阅请求包 req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange # 对于IB接口订阅行情时所需的货币和产品类型,从策略属性中获取 req.currency = strategy.currency req.productClass = strategy.productClass # 5.调用主引擎的订阅接口 self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, strategy.vtSymbol))
class CtaEngine2(object): """CTA Strategy Engine for Single-Strategy-Multi-Symbol use""" settingFileName = 'CTA_setting2.json' path = os.path.abspath(os.path.dirname(__file__)) settingFileName = os.path.join(path, settingFileName) #------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): """Constructor""" self.mainEngine = mainEngine self.eventEngine = eventEngine # 当前日期 self.today = todayDate() # 保存策略实例的字典 # key为策略名称,value为策略实例,注意策略名称不允许重复 self.strategyDict = {} # 保存vtSymbol和策略实例映射的字典(用于推送tick数据) # 由于可能多个strategy交易同一个vtSymbol,因此key为vtSymbol # value为包含所有相关strategy对象的list self.tickStrategyDict = {} # 保存vtOrderID和strategy对象映射的字典(用于推送order和trade数据) # key为vtOrderID,value为strategy对象 self.orderStrategyDict = {} # 保存vtOrderID和在order上关联的信息 (发单时任意填写的信息,用于保存到数据库,方便分析) self.orderAppendInfoDict = {} #保存gatewayName和strategy对象映射的字典,用于推送balance数据 self.gatewayNameStrategyDict = {} #保存task和strategy对象映射的字典,用于推送task数据 self.taskStrategyDict = {} # 本地停止单编号计数 self.stopOrderCount = 0 # stopOrderID = STOPORDERPREFIX + str(stopOrderCount) # 本地停止单字典 # key为stopOrderID,value为stopOrder对象 self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 # 预埋单集合 self.parkedOrderSet = set() self.workingParkedOrderSet = set() # key为parkedOrderID, value为vtOrderID self.parkedOrderMap = {} # 持仓缓存字典 # key为vtSymbol,value为PositionBuffer对象 self.posBufferDict = {} # 成交号集合,用来过滤已经收到过的成交推送 self.tradeSet = set() # 引擎类型为实盘 self.engineType = ENGINETYPE_TRADING # 注册事件监听 self.eventEngine.register(EVENT_TICK, self.processTickEvent) self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) self.eventEngine.register(EVENT_BALANCE, self.processBalanceEvent) self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) self.eventEngine.register(EVENT_CTA_TASK, self.processTaskEvent) #------------------------------------------------------------- def getPosition(self, vtSymbol): """返回longToday, longYd, shortToday, shortYd""" posBuffer = self.posBufferDict.get(vtSymbol, None) if not posBuffer: pmEngine = self.mainEngine.pmEngine pos = pmEngine.qryPosition(vtSymbol) posBuffer = PositionBuffer() posBuffer.vtSymbol = vtSymbol posBuffer.longYd = pos['longYd'] posBuffer.longToday = pos['longToday'] posBuffer.longPosition = posBuffer.longYd + posBuffer.longToday posBuffer.shortYd = pos['shortYd'] posBuffer.shortToday = pos['shortToday'] posBuffer.shortPosition = posBuffer.shortYd + posBuffer.shortToday self.posBufferDict[vtSymbol] = posBuffer return [ posBuffer.longToday, posBuffer.longYd, posBuffer.shortToday, posBuffer.shortYd ] #------------------------------------------------------------- def sendOrder2(self, vtSymbol, orderType, price, volume, strategy, priceType, kwargs): contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = self.roundToPriceTick(contract.priceTick, price) req.volume = volume req.productClass = strategy.productClass req.currency = strategy.currency req.priceType = priceType #CTA OrderType Map if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT req.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG req.offset = OFFSET_CLOSE if contract.exchange == EXCHANGE_SHFE: posBuffer = self.posBufferDict.get(vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = vtSymbol self.posBufferDict[vtSymbol] = posBuffer posBuffer.longToday, posBuffer.longYd, posBuffer.shortToday, posBuffer.shortYd = self.getPosition( vtSymbol) if req.direction == DIRECTION_LONG: print 'long' if posBuffer.shortYd >= req.volume: print 'close shortYd' req.offset = OFFSET_CLOSE else: print 'open today' req.offset = OFFSET_OPEN else: print 'short' if posBuffer.longYd >= req.volume: print 'close longYd' req.offset = OFFSET_CLOSE else: print 'open today' req.offset = OFFSET_OPEN vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) self.orderStrategyDict[vtOrderID] = strategy if 'append_info' in kwargs: print kwargs['append_info'] self.orderAppendInfoDict[vtOrderID] = kwargs['append_info'] self.writeCtaLog( u'策略%s发送委托, %s, %s, %s@%s' % (strategy.name, vtSymbol, req.direction, volume, price)) return vtOrderID #------------------------------------------------------------- if sendorder alt=falsee elseif sendorder2 alt=true def sendOrder(self, vtSymbol, orderType, price, volume, strategy, priceType, parked, alt, kwargs): """send order""" #if alt: # return self.sendOrder2(vtSymbol, orderType, price, volume, strategy, priceType, kwargs) contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = self.roundToPriceTick(contract.priceTick, price) req.volume = volume req.productClass = strategy.productClass req.currency = strategy.currency req.priceType = priceType # market or limit order # CTA委托类型映射 if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有多头今仓,则使用平今 elif posBuffer.longToday: print 'close today' req.offset = OFFSET_CLOSETODAY # 其他情况使用平昨 else: print 'close yesterday' req.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG # 只有上期所才要考虑平今平昨 if contract.exchange != EXCHANGE_SHFE: req.offset = OFFSET_CLOSE else: # 获取持仓缓存数据 posBuffer = self.posBufferDict.get(vtSymbol, None) # 如果获取持仓缓存失败,则默认平昨 if not posBuffer: req.offset = OFFSET_CLOSE # 否则如果有空头今仓,则使用平今 elif posBuffer.shortToday: print 'close today' req.offset = OFFSET_CLOSETODAY # 其他情况使用平昨 else: print 'close yesterday' req.offset = OFFSET_CLOSE if not parked: vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) self.orderStrategyDict[vtOrderID] = strategy if 'append_info' in kwargs: self.orderAppendInfoDict[vtOrderID] = kwargs['append_info'] else: vtOrderID = self.mainEngine.sendParkedOrder( req, contract.gatewayName) po = ParkedOrder() po.vtSymbol = vtSymbol po.orderType = orderType po.price = self.roundToPriceTick(contract.priceTick, price) po.volume = volume po.strategy = strategy po.localOrderID = vtOrderID if orderType == CTAORDER_BUY: po.direction = DIRECTION_LONG po.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: po.direction = DIRECTION_SHORT po.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: po.direction = DIRECTION_SHORT po.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: po.direction = DIRECTION_LONG po.offset = OFFSET_CLOSE self.parkedOrderSet.add(po) self.workingParkedOrderSet.add(po) self.writeCtaLog( u'策略%s发送委托, %s, %s, %s@%s' % (strategy.name, vtSymbol, req.direction, volume, price)) return vtOrderID #------------------------------------------------------------- def qryOrder(self, vtOrderID): gatewayName = vtOrderID.split('.')[0] self.mainEngine.qryOrder(vtOrderID, gatewayName) #------------------------------------------------------------- def cancelOrder(self, vtOrderID): order = self.mainEngine.getOrder(vtOrderID) if order: # check if order still valid, only if valid, cancel order command will be sent orderFinished = (order.status == STATUS_ALLTRADED or order.status == STATUS_CANCELLED) if not orderFinished: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) #------------------------------------------------------------- def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy): self.stopOrderCount += 1 stopOrderID = STOPORDERPREFIX + str(self.stopOrderCount) so = StopOrder() so.vtSymbol = vtSymbol so.orderType = orderType so.price = price so.volume = volume so.strategy = strategy so.stopOrderID = stopOrderID so.status = STOPORDER_WAITING if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG so.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: so.direction = DIRECTION_SHORT so.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: so.direction = DIRECTION_SHORT so.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: so.direction = DIRECTION_LONG so.offset = OFFSET_CLOSE # 保存stopOrder对象到字典中 self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so return stopOrderID #------------------------------------------------------ def cancelStopOrder(self, stopOrderID): """撤销停止单""" # 检查停止单是否存在 if stopOrderID in self.workingStopOrderDict: so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] #------------------------------------------------------ def processStopOrder(self, tick): """ stop order trigger check upon market data arrival """ vtSymbol = tick.vtSymbol # check whether symbol is bound to a strategy if vtSymbol in self.tickStrategyDict: # iterate all pending stop orders, check whether they will be triggered for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: longTriggered = so.direction == DIRECTION_LONG and tick.lastPrice >= so.price shortTriggered = so.direction == DIRECTION_SHORT and tick.lastPrice <= so.price if longTriggered or shortTriggered: if so.direction == DIRECTION_LONG: price = tick.upperLimit else: price = tick.lowerLimit so.status = STOPORDER_TRIGGERED self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) del self.workingStopOrderDict[so.stopOrderID] ############## more process the other symbols in the basket ############# #-------------------------------------------------------------- def processTickEvent(self, event): """ Tick Event Router """ # fetch tick data from event tick = event.dict_['data'] # process pending stop orders self.processStopOrder(tick) # push tick to corresponding strategy instance if tick.vtSymbol in self.tickStrategyDict: # data transforming ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): if key != 'datetime': d[key] = tick.__getattribute__(key) # 添加datetime字段 try: ctaTick.datetime = datetime.strptime( ' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') except ValueError: try: ctaTick.datetime = datetime.strptime( ' '.join([tick.date, tick.time]), '%Y-%m-%d %H:%M:%S') except ValueError: ctaTick.datetime = datetime.strptime( tick.time, '%Y-%m-%dT%H:%M:%S.%f') # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: self.callStrategyFunc(strategy, strategy.onTick, ctaTick) #----------------------------------------------------------------- def processOrderEvent(self, event): """ Order Event """ order = event.dict_['data'] order.localtime = datetime.now() # import pprint # pprint.pprint(order.__dict__) if order.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] self.callStrategyFunc(strategy, strategy.onOrder, order) ########################################################### # 处理预埋单触发的情况 elif order.exchange == EXCHANGE_SHFE and order.sessionID == 0 and order.frontID == 0: #print 'ctaEngine: processOrderEvent' # 把ParkedOrder加入orderStrategyDict #print 'workingParkedOrderSet: ', self.workingParkedOrderSet #print 'parkedOrderMap:', self.parkedOrderMap for po in self.workingParkedOrderSet: if order.vtOrderID not in self.parkedOrderMap: # 尚未匹配, 则与parkedOrder匹配 # import pprint # pprint.pprint(order.__dict__) # pprint.pprint(po.__dict__) if po.vtSymbol == order.vtSymbol and po.direction == order.direction and po.offset == order.offset and po.price == order.price and po.volume == order.totalVolume: # vtSymbol, orderType, price, volume均匹配 print 'match:', order.vtOrderID, po.strategy.name self.parkedOrderMap[order.vtOrderID] = po self.workingParkedOrderSet.remove(po) order.isParkedTriggered = True order.localOrderID = po.localOrderID self.orderStrategyDict[order.vtOrderID] = po.strategy self.callStrategyFunc(po.strategy, po.strategy.onOrder, order) break ############################################################ #------------------------------------------------------------------ def processTradeEvent(self, event): """ Trade Event """ trade = event.dict_['data'] if trade.vtTradeID in self.tradeSet: return self.tradeSet.add(trade.vtTradeID) # push trade data to the strategy if trade.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[trade.vtOrderID] # calculate strategy position if trade.direction == DIRECTION_LONG: strategy.pos[trade.vtSymbol] += trade.volume else: strategy.pos[trade.vtSymbol] -= trade.volume self.callStrategyFunc(strategy, strategy.__onTrade__, trade) # 更新持仓缓存数据 if trade.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(trade.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = trade.vtSymbol self.posBufferDict[trade.vtSymbol] = posBuffer posBuffer.updateTradeData(trade) #----------------------------------------------------------------- def processBalanceEvent(self, event): balance = event.dict_['data'] # 逐个推送到策略实例中 l = self.gatewayNameStrategyDict[balance.gatewayName] for strategy in l: self.callStrategyFunc(strategy, strategy.onBalance, balance) #----------------------------------------------------------------- def processPositionEvent(self, event): """处理持仓推送""" pos = event.dict_['data'] # 更新持仓缓存数据 if pos.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(pos.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = pos.vtSymbol self.posBufferDict[pos.vtSymbol] = posBuffer posBuffer.updatePositionData(pos) #----------------------------------------------------------------- def processTaskEvent(self, event): task_ret = event.dict_['data'] strategy = task_ret['strategy'] task_result = task_ret['result'] self.callStrategyFunc(strategy, strategy.onTask, task_result) #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)""" try: self.mainEngine.dbInsert(dbName, collectionName, data) except: pass #---------------------------------------------------------------------- def loadBar(self, dbName, collectionName, days): # fetch Bar data from MongoDB startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} barData = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] for d in barData: bar = CtaBarData() bar.__dict__ = d l.append(bar) return l #------------------------------------------------------------------------- def loadTick(self, dbName, collectionName, days): """从数据库中读取Tick数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime': {'$gte': startDate}} tickData = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] for d in tickData: tick = CtaTickData() tick.__dict__ = d l.append(tick) return l #------------------------------------------------------------------------- def loadTickToDataFrame(self, dbName, collectionName, start_time, end_time, where=''): """从数据库中读取Tick数据,起始日期为当日前days个工作日""" l = [] time = start_time window_length = 3 while time <= end_time: q = { 'datetime': { '$gte': time, '$lt': min(end_time, time + timedelta(hours=window_length)) } } tickData = self.mainEngine.dbQuery(dbName, collectionName, q, where) time = time + timedelta(hours=window_length) for d in tickData: tick = {} tick['datetime'] = d['datetime'] tick['lastPrice'] = d['lastPrice'] l.append(tick) tickData = [] return DataFrame(l) #-------------------------------------------------------------------------- def writeCtaLog(self, content): log = VtLogData() log.logContent = content event = Event(type_=EVENT_CTA_LOG) event.dict_['data'] = log self.eventEngine.put(event) #-------------------------------------------------------------------------- def writeWebLog(self, content, strategyName): event = Event(type_=EVENT_WEB_LOG) d = {} d['msg'] = content d['strategy'] = strategyName event.dict_['data'] = json.dumps(d) self.eventEngine.put(event) #-------------------------------------------------------------------------- def sendChartData(self, content, strategyName): event = Event(type_=EVENT_CHART_DATA) d = {} d['chart'] = content d['strategy'] = strategyName event.dict_['data'] = json.dumps(d) self.eventEngine.put(event) #-------------------------------------------------------------------------- def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception, e: self.writeCtaLog(u'载入策略出错:%s' % e) return # 获取策略类 strategyClass2 = STRATEGY_CLASS.get(className, None) if not strategyClass2: self.writeCtaLog(u'找不到策略类:%s' % className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' % name) else: # 创建策略实例 strategy = strategyClass2(self, setting) self.strategyDict[name] = strategy # Tick map for vtSymbol in strategy.vtSymbols: if vtSymbol in self.tickStrategyDict: l = self.tickStrategyDict[vtSymbol] else: l = [] self.tickStrategyDict[vtSymbol] = l l.append(strategy) # subscribe contract = self.mainEngine.getContract(vtSymbol) if contract and not self.getExchange(vtSymbol) in [ 'SMART', 'NYMEX', 'GLOBEX', 'IDEALPRO', 'HKEX', 'HKFE' ]: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange req.currency = strategy.currency req.productClass = strategy.productClass self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' % (name, vtSymbol)) # gatewayNameStrategyMap for vtSymbol in strategy.vtSymbols: contract = self.mainEngine.getContract(vtSymbol) if contract and not self.getExchange in [ 'SMART', 'NYMEX', 'GLOBEX', 'IDEALPRO', 'HKEX', 'HKFE' ]: gatewayName = contract.gatewayName if gatewayName in self.gatewayNameStrategyDict: l = self.gatewayNameStrategyDict[gatewayName] else: l = [] self.gatewayNameStrategyDict[gatewayName] = l l.append(strategy)
class CtaEngine(object): """CTA策略引擎""" settingFileName = 'CTA_setting.json' settingFileName = os.getcwd() + '/configFiles/' + settingFileName if datetime.now().hour>4 and datetime.now().hour<20: ctaEngineLogFile =os.getcwd() + '/ctaLogFile/' + datetime.now().replace(hour = 9,minute=0,second=0).strftime('%Y%m%d-%H%M%S') else: ctaEngineLogFile =os.getcwd() + '/ctaLogFile/' + datetime.now().replace(hour = 21,minute=0,second=0).strftime('%Y%m%d-%H%M%S') #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): """Constructor""" self.mainEngine = mainEngine self.eventEngine = eventEngine self.drEngine = DrEngine(mainEngine, eventEngine) # 当前日期 self.today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) # 保存策略实例的字典 # key为策略名称,value为策略实例,注意策略名称不允许重复 self.strategyDict = {} # 保存vtSymbol和策略实例映射的字典(用于推送tick数据) # 由于可能多个strategy交易同一个vtSymbol,因此key为vtSymbol # value为包含所有相关strategy对象的list self.tickStrategyDict = {} # 保存vtOrderID和strategy对象映射的字典(用于推送order和trade数据) # key为vtOrderID,value为strategy对象 self.orderStrategyDict = {} # tradeID记录,防止系统重复返回 self.tradIDList = [] # 本地停止单编号计数 self.stopOrderCount = 0 # stopOrderID = STOPORDERPREFIX + str(stopOrderCount) # 本地停止单字典 # key为stopOrderID,value为stopOrder对象 self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 # 持仓缓存字典 # key为vtSymbol,value为PositionBuffer对象 self.posBufferDict = {} # 引擎类型为实盘 self.engineType = ENGINETYPE_TRADING # 注册事件监听 self.registerEvent() # log 配置 if not os.path.exists(self.ctaEngineLogFile): os.makedirs(self.ctaEngineLogFile) with open(self.ctaEngineLogFile+'/ctaLog','ab') as f: pass self.logger1 = logging.getLogger('ctaLogger') self.logger1.setLevel(logging.DEBUG) fh = logging.handlers.RotatingFileHandler(self.ctaEngineLogFile+'/ctaLog', mode='a', maxBytes=1024*1024) ch = logging.StreamHandler() self.logger1.addHandler(fh) self.logger1.addHandler(ch) #---------------------------------------------------------------------- def sendOrder(self, vtSymbol, orderType, price, volume, strategy): """发单""" contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = price req.volume = volume req.productClass = strategy.productClass req.currency = strategy.currency # 设计为CTA引擎发出的委托只允许使用限价单 req.priceType = PRICETYPE_LIMITPRICE # CTA委托类型映射 if contract.exchange != EXCHANGE_SHFE: if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT req.offset = OFFSET_CLOSE elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG req.offset = OFFSET_CLOSE return self.SubsendOrder(req,strategy,contract.gatewayName) # 针对可能发生的平昨、平今进行订单拆分 else: if orderType == CTAORDER_BUY: req.direction = DIRECTION_LONG req.offset = OFFSET_OPEN return self.SubsendOrder(req,strategy,contract.gatewayName) elif orderType == CTAORDER_SHORT: req.direction = DIRECTION_SHORT req.offset = OFFSET_OPEN return self.SubsendOrder(req,strategy,contract.gatewayName) elif orderType == CTAORDER_SELL: req.direction = DIRECTION_SHORT if strategy.posTD[vtSymbol]['long'] > 0 : if volume <= strategy.posTD[vtSymbol]['long']: req.offset = OFFSET_CLOSETODAY return self.SubsendOrder(req,strategy,contract.gatewayName) else: req.volume = strategy.posTD[vtSymbol]['long'] req.offset = OFFSET_CLOSETODAY vtOrderID1 = self.SubsendOrder(req,strategy,contract.gatewayName) req.volume = volume - strategy.posTD[vtSymbol]['long'] req.offset = OFFSET_CLOSE vtOrderID2 = self.SubsendOrder(req,strategy,contract.gatewayName) return [vtOrderID1,vtOrderID2] elif strategy.posYD[vtSymbol]['long'] > 0 : req.volume = volume req.offset = OFFSET_CLOSE return self.SubsendOrder(req,strategy,contract.gatewayName) else : self.writeCtaLog(u'%s:下单委托,报单与当前持仓不匹配!' %(strategy.name)) elif orderType == CTAORDER_COVER: req.direction = DIRECTION_LONG if strategy.posTD[vtSymbol]['short'] > 0: if volume <= strategy.posTD[vtSymbol]['short']: req.offset = OFFSET_CLOSETODAY return self.SubsendOrder(req,strategy,contract.gatewayName) else: req.volume = strategy.posTD[vtSymbol]['short'] req.offset = OFFSET_CLOSETODAY vtOrderID1 = self.SubsendOrder(req,strategy,contract.gatewayName) req.volume = volume - strategy.posTD[vtSymbol]['short'] req.offset = OFFSET_CLOSE vtOrderID2 = self.SubsendOrder(req,strategy,contract.gatewayName) return [vtOrderID1,vtOrderID2] elif strategy.posYD[vtSymbol]['short'] > 0: req.volume = volume req.offset = OFFSET_CLOSE return self.SubsendOrder(req,strategy,contract.gatewayName) else: self.writeCtaLog(u'%s:下单委托,报单与当前持仓不匹配!' %(strategy.name)) def SubsendOrder(self,req,strategy,contractgatewayName): # 下单函数子函数,无实际意义,只为了便于重复使用 vtOrderID = self.mainEngine.sendOrder(req, contractgatewayName) # 发单 self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 self.writeCtaLog(u'%s:下单委托,标的--%s,方向--%s,开平--%s,下单量--%s,下单价--%s' %(strategy.name, req.symbol, req.direction, req.offset, req.volume, req.price)) return vtOrderID #---------------------------------------------------------------------- def sendOrderOriginal(self, vtSymbol, direction, offset, price, volume, strategy): """CTP原始发单""" contract = self.mainEngine.getContract(vtSymbol) req = VtOrderReq() req.symbol = contract.symbol req.exchange = contract.exchange req.price = price req.volume = volume req.direction = direction req.offset = offset req.productClass = strategy.productClass req.currency = strategy.currency # 设计为CTA引擎发出的委托只允许使用限价单 req.priceType = PRICETYPE_LIMITPRICE vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单 if __name__ == '__main__': self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 # 这样做之后,收到的委托回报和成交回报就可以正确的提交到对应的策略,不至于乱套. self.writeCtaLog(u'%s:下单委托,标的--%s,方向--%s,开平--%s,下单量--%s,下单价--%s' %(strategy.name, vtSymbol, req.direction, req.offset, req.volume, req.price)) return vtOrderID #---------------------------------------------------------------------- def cancelOrder(self, vtOrderID): """撤单""" # 查询报单对象 order = self.mainEngine.getOrder(vtOrderID) # 如果查询成功 if order: # 检查是否报单还有效,只有有效时才发出撤单指令 orderFinished = (order.status==STATUS_ALLTRADED or order.status==STATUS_CANCELLED) if not orderFinished: req = VtCancelOrderReq() req.symbol = order.symbol req.exchange = order.exchange req.frontID = order.frontID req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) #---------------------------------------------------------------------- def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy): """发停止单(本地实现)""" self.stopOrderCount += 1 stopOrderID = STOPORDERPREFIX + str(self.stopOrderCount) so = StopOrder() so.vtSymbol = vtSymbol so.orderType = orderType so.price = price so.volume = volume so.strategy = strategy so.stopOrderID = stopOrderID so.status = STOPORDER_WAITING if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG so.offset = OFFSET_OPEN elif orderType == CTAORDER_SELL: so.direction = DIRECTION_SHORT so.offset = OFFSET_CLOSE elif orderType == CTAORDER_SHORT: so.direction = DIRECTION_SHORT so.offset = OFFSET_OPEN elif orderType == CTAORDER_COVER: so.direction = DIRECTION_LONG so.offset = OFFSET_CLOSE # 保存stopOrder对象到字典中 self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so return stopOrderID #---------------------------------------------------------------------- def cancelStopOrder(self, stopOrderID): """撤销停止单""" # 检查停止单是否存在 if stopOrderID in self.workingStopOrderDict: so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] #---------------------------------------------------------------------- def processStopOrder(self, tick): """收到行情后处理本地停止单(检查是否要立即发出)""" vtSymbol = tick.vtSymbol # 首先检查是否有策略交易该合约 if vtSymbol in self.tickStrategyDict: # 遍历等待中的停止单,检查是否会被触发 for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: longTriggered = so.direction==DIRECTION_LONG and tick.lastPrice>=so.price # 多头停止单被触发 shortTriggered = so.direction==DIRECTION_SHORT and tick.lastPrice<=so.price # 空头停止单被触发 if longTriggered or shortTriggered: # 买入和卖出分别以涨停跌停价发单(模拟市价单) if so.direction==DIRECTION_LONG: price = tick.upperLimit else: price = tick.lowerLimit so.status = STOPORDER_TRIGGERED self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) del self.workingStopOrderDict[so.stopOrderID] #---------------------------------------------------------------------- def processTickEvent(self, event): """处理行情推送""" tick = event.dict_['data'] # 收到tick行情后,先处理本地停止单(检查是否要立即发出) self.processStopOrder(tick) # 推送tick到对应的策略实例进行处理 if tick.vtSymbol in self.tickStrategyDict: # 将vtTickData数据转化为ctaTickData ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): if key != 'datetime': d[key] = tick.__getattribute__(key) # 添加datetime字段 ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: self.callStrategyFunc(strategy, strategy.onTick, ctaTick) #---------------------------------------------------------------------- def processOrderEvent(self, event): """处理委托推送""" order = event.dict_['data'] if order.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] self.callStrategyFunc(strategy, strategy.onOrder, order) #---------------------------------------------------------------------- def processTradeEvent(self, event): """处理成交推送""" trade = event.dict_['data'] contract = self.mainEngine.getContract(trade.vtSymbol) # 防止系统重复发出成交回报 if trade.tradeID not in self.tradIDList: self.tradIDList.append(trade.tradeID) else: return if trade.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[trade.vtOrderID] # 计算策略持仓 # if trade.vtSymbol not in strategy.pos.keys(): #by hw # strategy.pos[trade.vtSymbol]=0 if contract.exchange != EXCHANGE_SHFE: if trade.offset == OFFSET_OPEN: if trade.direction == DIRECTION_LONG: strategy.posYD[trade.vtSymbol]['long'] += trade.volume strategy.posYD[trade.vtSymbol]['pos'] += trade.volume elif trade.direction == DIRECTION_SHORT: strategy.posYD[trade.vtSymbol]['short'] += trade.volume strategy.posYD[trade.vtSymbol]['pos'] -= trade.volume else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) elif trade.offset == OFFSET_CLOSE: if trade.direction == DIRECTION_LONG: strategy.posYD[trade.vtSymbol]['short'] -= trade.volume strategy.posYD[trade.vtSymbol]['pos'] += trade.volume elif trade.direction == DIRECTION_SHORT: strategy.posYD[trade.vtSymbol]['long'] -= trade.volume strategy.posYD[trade.vtSymbol]['pos'] -= trade.volume else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) else: if trade.offset == OFFSET_OPEN: if trade.direction == DIRECTION_LONG: strategy.posTD[trade.vtSymbol]['pos'] += trade.volume strategy.posTD[trade.vtSymbol]['long'] += trade.volume elif trade.direction == DIRECTION_SHORT: strategy.posTD[trade.vtSymbol]['pos'] -= trade.volume strategy.posTD[trade.vtSymbol]['short'] += trade.volume else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) elif trade.offset == OFFSET_CLOSETODAY: if trade.direction == DIRECTION_LONG: strategy.posTD[trade.vtSymbol]['pos'] += trade.volume strategy.posTD[trade.vtSymbol]['short'] -= trade.volume elif trade.direction == DIRECTION_SHORT: strategy.posTD[trade.vtSymbol]['pos'] -= trade.volume strategy.posTD[trade.vtSymbol]['long'] -= trade.volume else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) elif trade.offset == OFFSET_CLOSEYESTERDAY: if trade.direction == DIRECTION_LONG: strategy.posYD[trade.vtSymbol]['pos'] += trade.volume strategy.posYD[trade.vtSymbol]['short'] -= trade.volume elif trade.direction == DIRECTION_SHORT: strategy.posYD[trade.vtSymbol]['pos'] -= trade.volume strategy.posYD[trade.vtSymbol]['long'] -= trade.volume else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) else: self.writeCtaLog(u'%s:收到异常成交回报,异常回报值: 开平--%s,多空--%s,成交量--%s,成交价--%s' %(strategy.name, trade.offset, trade.direction, trade.volume, trade.price)) self.callStrategyFunc(strategy, strategy.onTrade, trade) # # del self.orderStrategyDict[trade.vtOrderID] else: self.writeCtaLog(u'非系统运行策略自动操作:'+u'成交回报,标的--%s,方向--%s,开平--%s,成交量--%s,成交价--%s' %(trade.vtSymbol, trade.direction, trade.offset, trade.volume, trade.price)) # 更新持仓缓存数据 if trade.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(trade.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = trade.vtSymbol self.posBufferDict[trade.vtSymbol] = posBuffer posBuffer.updateTradeData(trade) #---------------------------------------------------------------------- def processPositionEvent(self, event): """处理持仓推送""" pos = event.dict_['data'] # 更新持仓缓存数据 if pos.vtSymbol in self.tickStrategyDict: posBuffer = self.posBufferDict.get(pos.vtSymbol, None) if not posBuffer: posBuffer = PositionBuffer() posBuffer.vtSymbol = pos.vtSymbol self.posBufferDict[pos.vtSymbol] = posBuffer posBuffer.updatePositionData(pos) # #---------------------------------------------------------------------- # def procecssBarEvent(self, event): # """处理K线行情推送""" # Bar = event.dict_['data'] # # 收到tick行情后,先处理本地停止单(检查是否要立即发出) # self.processStopOrder(tick) # # 推送tick到对应的策略实例进行处理 # if tick.vtSymbol in self.tickStrategyDict: # # 将vtTickData数据转化为ctaTickData # ctaTick = CtaTickData() # d = ctaTick.__dict__ # for key in d.keys(): # if key != 'datetime': # d[key] = tick.__getattribute__(key) # # 添加datetime字段 # ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') # # 逐个推送到策略实例中 # l = self.tickStrategyDict[tick.vtSymbol] # for strategy in l: # strategy.onTick(ctaTick) #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" self.eventEngine.register(EVENT_TICK, self.processTickEvent) self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) self.eventEngine.register(EVENT_CTA_LOG, self.writeCtaLogFile) self.eventEngine.register(EVENT_ERROR, self.writeCtaLogFile) #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """插入数据到数据库(这里的data可以是CtaTickData或者CtaBarData)""" self.mainEngine.dbInsert(dbName, collectionName, data.__dict__) #---------------------------------------------------------------------- def loadBar(self, dbName, collectionName, days): """从数据库中读取Bar数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: bar = CtaBarData() bar.__dict__ = d l.append(bar) return l #---------------------------------------------------------------------- def loadTick(self, dbName, collectionName, days): """从数据库中读取Tick数据,startDate是datetime对象""" startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} cursor = self.mainEngine.dbQuery(dbName, collectionName, d) l = [] if cursor: for d in cursor: tick = CtaTickData() tick.__dict__ = d l.append(tick) return l #---------------------------------------------------------------------- def writeCtaLog(self, content): """快速发出CTA模块日志事件""" log = VtLogData() log.logContent = content event = Event(type_=EVENT_CTA_LOG) event.dict_['data'] = log self.eventEngine.put(event) #---------------------------------------------------------------------- def writeCtaLogFile(self, event): """快速发出CTA模块日志事件""" log = event.dict_['data'] try: content = '\t'.join([log.logTime, log.logContent]) self.logger1.info(content) except Exception as e: if isinstance(log, VtErrorData): content = '\t'.join([log.errorTime, str(log.errorID), log.errorMsg, log.additionalInfo]) self.logger1.info(content) else: print e #---------------------------------------------------------------------- def loadStrategy(self, setting): """载入策略""" try: name = setting['name'] className = setting['className'] except Exception, e: self.writeCtaLog(u'载入策略出错:%s' %e) return # 获取策略类 strategyClass = STRATEGY_CLASS.get(className, None) if not strategyClass: self.writeCtaLog(u'找不到策略类:%s' %className) return # 防止策略重名 if name in self.strategyDict: self.writeCtaLog(u'策略实例重名:%s' %name) else: # 创建策略实例 strategy = strategyClass(self, setting) self.strategyDict[name] = strategy strategy.name = name # 保存Tick映射关系 # 增加循环,用于单策略订阅多个合约 vtSymbolList=strategy.vtSymbol for vtSymbol in vtSymbolList: if vtSymbol in self.tickStrategyDict: # key为vtSymbol,value为包含所有相关strategy对象的list l = self.tickStrategyDict[vtSymbol] else: l = [] self.tickStrategyDict[vtSymbol] = l l.append(strategy) # 订阅合约 contract = self.mainEngine.getContract(vtSymbol) # 获取合约的最小变动价位、合约乘数等相关信息---------------------------------------------------------------------------- if contract: req = VtSubscribeReq() req.symbol = contract.symbol req.exchange = contract.exchange self.mainEngine.subscribe(req, contract.gatewayName) else: self.writeCtaLog(u'%s的交易合约%s无法找到' %(name, vtSymbol))
def loadSetting(self): """载入设置""" with open(self.settingFileName) as f: setting = json.load(f) lastVT = {} persontype = np.dtype({'names':['symbol', 'v', 't'], 'formats':['S32','f', 'f']}) try: with open(self.dataPath1+'lastVT/'+'lastVT.csv') as f: lastVT1 = np.genfromtxt(f,delimiter=',',dtype = persontype) # print lastVT1[0] for line in lastVT1: lastVT[line[0]] = [line[1],line[2]] # print line # for k in lastVT.keys(): # print k,lastVT[k] except Exception as e: print e pass # 日盘、夜盘时段读取不同的1ms序列 if datetime.now().hour >= 16 : with open(self.Standard1ms+'Night.json','r') as f: dictStandard1ms = json.load(f) else: with open(self.Standard1ms+'Day.json','r') as f: dictStandard1ms = json.load(f) self.barDict = {} self.splitDict = {} lastBar = DrBarData() barDataRam = BarDataRam() for strIns in setting: for symbol in strIns['vtSymbol']: if symbol not in self.barDict.keys(): self.splitDict[symbol] = {} self.barDict[symbol] = {} self.barDict[symbol][1] = {} self.barDict[symbol][1]['data'] = copy.copy(barDataRam) self.barDict[symbol][1]['lastData'] = copy.copy(lastBar) # self.barDict[symbol][1]['lastTickVolume'] = 0 # self.barDict[symbol][1]['lastTickTurnover'] = 0 self.barDict[symbol][1]['initial1ms'] = False # self.barDict[symbol][1]['break1msTime'] = [] strList = dictStandard1ms[filter(lambda ch: ch not in '0123456789', symbol).lower()] timesList = self.timeSeries(strList) # print temp1 timesList.append(timesList[-1]+timedelta(minutes=1)) self.splitDict[symbol][1] = copy.copy(timesList) # print timesList # print strIns.keys() if u'cycle' in strIns.keys(): if strIns['cycle'] == 1: continue if strIns['cycle'] not in self.barDict[symbol]: # 针对郑商所的合约代码可能要进行额外的处理 temp2 = dictStandard1ms[filter(lambda ch: ch not in '0123456789', symbol).lower()][-1] strList = dictStandard1ms[filter(lambda ch: ch not in '0123456789', symbol).lower()][::strIns['cycle']] # temp.pop(0) timesList = self.timeSeries(strList) # 使用正的偏差还是负的偏差尚未确定 if len(timesList)>1: timesList.append(datetime.strptime(str(int(temp2)),'%Y%m%d%H%M%S').replace(year=timesList[-1].year,month=timesList[-1].month,day=timesList[-1].day)+timedelta(minutes=2)) else: timesList.append(datetime.strptime(str(int(temp2)),'%Y%m%d%H%M%S').replace(year=datetime.now().year,month=datetime.now().month,day=datetime.now().day)+timedelta(minutes=2)) self.splitDict[symbol][strIns['cycle']] = copy.copy(timesList) # print symbol,strIns['cycle'],timesList self.barDict[symbol][strIns['cycle']] = {} self.barDict[symbol][strIns['cycle']]['data'] = copy.copy(barDataRam) self.barDict[symbol][strIns['cycle']]['lastData'] = copy.copy(lastBar) self.barDict[symbol][strIns['cycle']]['updateTime'] = datetime.now() + timedelta(hours = 3) if vars().has_key('lastVT'): if symbol not in lastVT.keys(): self.barDict[symbol][1]['data'].lastVolume = 0 self.barDict[symbol][1]['data'].lastTurnover = 0 else: self.barDict[symbol][1]['data'].lastVolume = lastVT[symbol][0] self.barDict[symbol][1]['data'].lastTurnover = lastVT[symbol][1] self.barDict[symbol][1]['data'].lastTick = 0 gatewayName = "CTP" for symbol in self.barDict.keys(): # bar = DrBarData() # self.barDict[symbol] = bar req = VtSubscribeReq() req.symbol = symbol self.mainEngine.subscribe(req, gatewayName) self.registerEvent()