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)
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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))
Example #5
0
    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))
Example #6
0
 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
                 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
                 
         # 注册事件监听
         self.registerEvent()            
    def startAll(self):
        if self.ctpConnected is False:
            self.writeCtaLog(u'未登录CTP, 期货Tick 订阅失败')
            return
        if self.mainEngine.dbClient is None:
            self.writeCtaLog(u'未连接数据库, 期货Tick 订阅失败')
            return

        # 订阅合约
        print self.contractsDict.values()       # 打印所有订阅合约
        for contract in self.contractsDict.values():
            try:
                # print contract
                req = VtSubscribeReq()
                req.symbol = contract
                self.mainEngine.subscribe(req, 'CTP')
            except:
                self.writeCtaLog(u'期货Tick , 合约%s 订阅失败' %(contract))

        self.eventEngine.register(EVENT_TICK, self.procecssTickEvent)
        self.writeCtaLog(u'期货Tick 订阅成功')
Example #8
0
    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))
Example #9
0
    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()
Example #10
0
    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))
Example #11
0
    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))
Example #12
0
    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()
Example #13
0
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))
Example #14
0
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))
Example #15
0
    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()   
Example #16
0
            # 保存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]
Example #17
0
    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()
Example #18
0
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))
Example #19
0
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))
Example #20
0
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)
Example #21
0
    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()