示例#1
0
    def loadStrategy(self, setting):
        """载入策略"""
        try:
            name = setting['name']
            className = setting['className']
        except Exception:
            msg = traceback.format_exc()
            self.writeCtaLog(u'载入策略出错:%s' % msg)
            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

            # 创建委托号列表
            self.strategyOrderDict[name] = set()

            # 保存Tick映射关系
            if strategy.vtSymbol in self.tickStrategyDict:
                l = self.tickStrategyDict[strategy.vtSymbol]
            else:
                l = []
                self.tickStrategyDict[strategy.vtSymbol] = l
            l.append(strategy)
示例#2
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))
示例#3
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))
示例#4
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):
        """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.tradeSet = set()

        # 引擎类型为实盘
        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 = self.roundToPriceTick(contract.priceTick, 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 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']

        # 过滤已经收到过的成交回报
        if trade.vtTradeID in self.tradeSet:
            return
        self.tradeSet.add(trade.vtTradeID)

        # 将成交推送到策略对象中
        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

            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 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}}
        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 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))
示例#5
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)