Exemple #1
0
class ClientEngine(object):
    """客户端引擎,提供和MainEngine完全相同的API接口"""

    #----------------------------------------------------------------------
    def __init__(self, client, eventEngine):
        """Constructor"""
        self.client = client
        self.eventEngine = eventEngine

        # 扩展模块
        self.ctaEngine = CtaEngine(self, self.eventEngine)
        self.drEngine = DrEngine(self, self.eventEngine)
        self.rmEngine = RmEngine(self, self.eventEngine)

    #----------------------------------------------------------------------
    def connect(self, gatewayName):
        """连接特定名称的接口"""
        self.client.connect(gatewayName)

    # ----------------------------------------------------------------------
    def disconnect(self, gatewayName):
        """连接特定名称的接口"""
        self.client.disconnect(gatewayName)

    #----------------------------------------------------------------------
    def subscribe(self, subscribeReq, gatewayName):
        """订阅特定接口的行情"""
        self.client.subscribe(subscribeReq, gatewayName)

    #----------------------------------------------------------------------
    def sendOrder(self, orderReq, gatewayName):
        """对特定接口发单"""
        self.client.sendOrder(orderReq, gatewayName)

    #----------------------------------------------------------------------
    def cancelOrder(self, cancelOrderReq, gatewayName):
        """对特定接口撤单"""
        self.client.cancelOrder(cancelOrderReq, gatewayName)

    #----------------------------------------------------------------------
    def qryAccont(self, gatewayName):
        """查询特定接口的账户"""
        self.client.qryAccount(gatewayName)

    #----------------------------------------------------------------------
    def qryPosition(self, gatewayName):
        """查询特定接口的持仓"""
        self.client.qryPosition(gatewayName)

    #----------------------------------------------------------------------
    def exit(self):
        """退出程序前调用,保证正常退出"""
        # 停止事件引擎
        self.eventEngine.stop()

        # 关闭客户端的推送数据接收
        self.client.stop()

        # 停止数据记录引擎
        self.drEngine.stop()

    #----------------------------------------------------------------------
    def writeLog(self, content):
        """快速发出日志事件"""
        self.client.writeLog(content)

    #----------------------------------------------------------------------
    def dbConnect(self):
        """连接MongoDB数据库"""
        self.client.dbConnect()

    #----------------------------------------------------------------------
    def dbInsert(self, dbName, collectionName, d):
        """向MongoDB中插入数据,d是具体数据"""
        self.client.dbInsert(dbName, collectionName, d)

    #----------------------------------------------------------------------
    def dbQuery(self, dbName, collectionName, d):
        """从MongoDB中读取数据,d是查询要求,返回的是数据库查询的数据列表"""
        return self.client.dbQuery(dbName, collectionName, d)

    #----------------------------------------------------------------------
    def dbUpdate(self, dbName, collectionName, d, flt, upsert=False):
        """向MongoDB中更新数据,d是具体数据,flt是过滤条件,upsert代表若无是否要插入"""
        self.client.dbUpdate(dbName, collectionName, d, flt, upsert)

    #----------------------------------------------------------------------
    def getContract(self, vtSymbol):
        """查询合约"""
        return self.client.getContract(vtSymbol)

    #----------------------------------------------------------------------
    def getAllContracts(self):
        """查询所有合约(返回列表)"""
        return self.client.getAllContracts()

    #----------------------------------------------------------------------
    def getOrder(self, vtOrderID):
        """查询委托"""
        return self.client.getOrder(vtOrderID)

    #----------------------------------------------------------------------
    def getAllWorkingOrders(self):
        """查询所有的活跃的委托(返回列表)"""
        return self.client.getAllWorkingOrders()

    #----------------------------------------------------------------------
    def getAllGatewayNames(self):
        """查询所有的接口名称"""
        return self.client.getAllGatewayNames()

    def getAccountInfo(self):
        """读取风控的账号与仓位数据
        # Added by IncenseLee
        仅支持一个账号。不支持多账号
        以后支持跨市场套利才更新吧。
        """
        return self.rmEngine.getAccountInfo()

    def clearData(self):
        """清空数据引擎的数据"""
        self.dataEngine.clearData()
        self.ctaEngine.clearData()

    def saveData(self):
        self.ctaEngine.saveStrategyData()
Exemple #2
0
class MainEngine(object):
    """主引擎"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        # 记录今日日期
        self.todayDate = datetime.now().strftime('%Y%m%d')

        # 创建事件引擎
        self.eventEngine = EventEngine2()
        self.eventEngine.start()

        # 创建数据引擎
        self.dataEngine = DataEngine(self, self.eventEngine)

        # MongoDB数据库相关
        self.dbClient = None  # MongoDB客户端对象

        # 接口实例
        self.gatewayDict = OrderedDict()
        self.gatewayDetailList = []

        # 应用模块实例
        self.appDict = OrderedDict()
        self.appDetailList = []

        # 扩展模块
        self.ctaEngine = CtaEngine(self, self.eventEngine)  # cta策略运行模块
        self.drEngine = DrEngine(self, self.eventEngine)  # 数据记录模块
        self.rmEngine = RmEngine(self, self.eventEngine)  # 风险管理模块

        self.connected_gw_name = u''

    # ----------------------------------------------------------------------
    def addGateway(self, gatewayModule, gateway_name=EMPTY_STRING):
        """添加底层接口"""
        # 是否使用指定的gateway_name
        if gateway_name == EMPTY_STRING:
            gatewayName = gatewayModule.gatewayName
        else:
            gatewayName = gateway_name

        # 创建接口实例
        self.gatewayDict[gatewayName] = gatewayModule.gatewayClass(
            self.eventEngine, gatewayName)

        # 设置接口轮询
        if gatewayModule.gatewayQryEnabled:
            self.gatewayDict[gatewayName].setQryEnabled(
                gatewayModule.gatewayQryEnabled)

        # 保存接口详细信息
        d = {
            'gatewayName': gatewayModule.gatewayName,
            'gatewayDisplayName': gatewayModule.gatewayDisplayName,
            'gatewayType': gatewayModule.gatewayType
        }
        self.gatewayDetailList.append(d)

        if gateway_name != self.connected_gw_name:
            self.connected_gw_name = gateway_name

    # ----------------------------------------------------------------------
    def connect(self, gatewayName):
        """连接特定名称的接口"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            gateway.connect()

            if gatewayName != self.connected_gw_name:
                self.connected_gw_name = gatewayName

            # 接口连接后自动执行数据库连接的任务
            self.dbConnect()

            return True
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

            return False

    def checkGatewayStatus(self, gatewayName):
        """check gateway connect status"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            return gateway.checkStatus()
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))
            return False

    def qryStatus(self):
        """查询Status"""
        status_dict = OrderedDict()

        # gateway Status
        gw_status_dict = OrderedDict()
        for k, g in self.gatewayDict.items():
            gw_status_dict[k] = g.checkStatus()
        status_dict['gateways'] = gw_status_dict

        # ctaEngine Status
        if self.ctaEngine:
            tick_dict, strategy_dict = self.ctaEngine.qryStatus()
            status_dict['ticks'] = tick_dict
            status_dict['strategies'] = strategy_dict

        event = vn_event(type_=EVENT_STATUS)
        event.dict_['data'] = status_dict
        self.eventEngine.put(event)

        return True

    # ----------------------------------------------------------------------
    def subscribe(self, subscribeReq, gatewayName):
        """订阅特定接口的行情"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            gateway.subscribe(subscribeReq)
        else:
            if len(self.gatewayDict) > 0:
                for gateway in self.gatewayDict.values():
                    gateway.subscribe(subscribeReq)
            else:
                self.writeLog(
                    text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

    # ----------------------------------------------------------------------
    def sendOrder(self, orderReq, gatewayName):
        """对特定接口发单"""
        # 如果风控检查失败则不发单
        if not self.rmEngine.checkRisk(orderReq):
            self.writeCritical(u'风控检查不通过')
            return ''

        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            return gateway.sendOrder(orderReq)
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

    # ----------------------------------------------------------------------
    def cancelOrder(self, cancelOrderReq, gatewayName):
        """对特定接口撤单"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            gateway.cancelOrder(cancelOrderReq)
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

    # ----------------------------------------------------------------------
    def qryAccount(self, gatewayName):
        """查询特定接口的账户"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            gateway.qryAccount()
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

    def getAccountInfo(self):
        """读取风控的账号与仓位数据
        # Added by IncenseLee
        仅支持一个账号。不支持多账号
        以后支持跨市场套利才更新吧。
        """
        return self.rmEngine.getAccountInfo()

    # ----------------------------------------------------------------------
    def qryPosition(self, gatewayName):
        """查询特定接口的持仓"""
        if gatewayName in self.gatewayDict:
            gateway = self.gatewayDict[gatewayName]
            gateway.qryPosition()
        else:
            self.writeLog(text.GATEWAY_NOT_EXIST.format(gateway=gatewayName))

    # ----------------------------------------------------------------------
    def exit(self):
        """退出程序前调用,保证正常退出"""
        # 安全关闭所有接口
        for gateway in self.gatewayDict.values():
            gateway.close()

        # 停止事件引擎
        self.eventEngine.stop()

        # 停止数据记录引擎
        self.drEngine.stop()

        # 保存数据引擎里的合约数据到硬盘
        self.dataEngine.saveContracts()

    def disconnect(self, gateway_name=EMPTY_STRING):
        """断开底层gateway的连接"""
        try:
            # 只断开指定的gateway
            if gateway_name != EMPTY_STRING:
                if gateway_name in self.gatewayDict:
                    gateway = self.gatewayDict[gateway_name]
                    gateway.close()
                    return
                else:
                    self.writeLog(u'gateway接口不存在:%s' % gateway_name)

            # 断开所有的gateway
            for gateway in self.gatewayDict.values():
                gateway.close()

            return True

        except Exception as ex:
            print u'vtEngine.disconnect Exception:{0} '.format(str(ex))
            return False

    # ----------------------------------------------------------------------
    def writeLog(self, content):
        """快速发出日志事件"""
        log = VtLogData()
        log.logContent = content
        event = vn_event(type_=EVENT_LOG)
        event.dict_['data'] = log
        self.eventEngine.put(event)

        # 写入本地log日志
        logging.info(content)

    # ----------------------------------------------------------------------
    def writeError(self, content):
        """快速发出错误日志事件"""
        log = VtErrorData()
        log.errorMsg = content
        event = vn_event(type_=EVENT_ERROR)
        event.dict_['data'] = log
        self.eventEngine.put(event)

        # 写入本地log日志
        logging.error(content)

    # ----------------------------------------------------------------------
    def writeWarning(self, content):
        """快速发出告警日志事件"""
        log = VtLogData()
        log.logContent = content
        event = vn_event(type_=EVENT_WARNING)
        event.dict_['data'] = log
        self.eventEngine.put(event)

        # 写入本地log日志
        logging.warning(content)

        # 发出邮件
        try:
            sendmail(subject=u'{0} Warning'.format(self.connected_gw_name),
                     msgcontent=content)
        except:
            pass

    # ----------------------------------------------------------------------
    def writeNotification(self, content):
        """快速发出通知日志事件"""
        log = VtLogData()
        log.logContent = content
        event = vn_event(type_=EVENT_NOTIFICATION)
        event.dict_['data'] = log
        self.eventEngine.put(event)

        # 发出邮件
        try:
            sendmail(subject=u'{0} Notification'.format(
                self.connected_gw_name),
                     msgcontent=content)
        except:
            pass

    # ----------------------------------------------------------------------
    def writeCritical(self, content):
        """快速发出严重错误日志事件"""

        log = VtLogData()
        log.logContent = content
        event = vn_event(type_=EVENT_CRITICAL)
        event.dict_['data'] = log
        self.eventEngine.put(event)

        # 写入本地log日志
        logging.critical(content)

        # 发出邮件
        try:
            sendmail(subject=u'{0} Critical'.format(self.connected_gw_name),
                     msgcontent=content)
        except:
            pass

    # ----------------------------------------------------------------------
    def dbConnect(self):
        """连接MongoDB数据库"""
        if not self.dbClient:
            # 读取MongoDB的设置
            host, port, logging = loadMongoSetting()

            try:
                # 设置MongoDB操作的超时时间为0.5秒
                self.dbClient = MongoClient(host, port, connectTimeoutMS=500)

                # 调用server_info查询服务器状态,防止服务器异常并未连接成功
                self.dbClient.server_info()

                self.writeLog(text.DATABASE_CONNECTING_COMPLETED)

                # 如果启动日志记录,则注册日志事件监听函数
                if logging:
                    self.eventEngine.register(EVENT_LOG, self.dbLogging)

            except ConnectionFailure:
                self.writeError(text.DATABASE_CONNECTING_FAILED)

    # ----------------------------------------------------------------------
    def dbInsert(self, dbName, collectionName, d):
        """向MongoDB中插入数据,d是具体数据"""
        if self.dbClient:
            db = self.dbClient[dbName]
            collection = db[collectionName]
            collection.insert_one(d)
        else:
            self.writeLog(text.DATA_INSERT_FAILED)

    # ----------------------------------------------------------------------
    def dbQuery(self, dbName, collectionName, d):
        """从MongoDB中读取数据,d是查询要求,返回的是数据库查询的指针"""
        if self.dbClient:
            db = self.dbClient[dbName]
            collection = db[collectionName]
            cursor = collection.find(d)
            if cursor:
                return list(cursor)
            else:
                return []
        else:
            self.writeLog(text.DATA_QUERY_FAILED)
            return []

    #----------------------------------------------------------------------
    def dbUpdate(self, dbName, collectionName, d, flt, upsert=False):
        """向MongoDB中更新数据,d是具体数据,flt是过滤条件,upsert代表若无是否要插入"""
        if self.dbClient:
            db = self.dbClient[dbName]
            collection = db[collectionName]
            collection.replace_one(flt, d, upsert)
        else:
            self.writeLog(text.DATA_UPDATE_FAILED)

    #----------------------------------------------------------------------
    def dbLogging(self, event):
        """向MongoDB中插入日志"""
        log = event.dict_['data']
        d = {
            'content': log.logContent,
            'time': log.logTime,
            'gateway': log.gatewayName
        }
        self.dbInsert(LOG_DB_NAME, self.todayDate, d)

    #----------------------------------------------------------------------
    def getContract(self, vtSymbol):
        """查询合约"""
        return self.dataEngine.getContract(vtSymbol)

    #----------------------------------------------------------------------
    def getAllContracts(self):
        """查询所有合约(返回列表)"""
        return self.dataEngine.getAllContracts()

    #----------------------------------------------------------------------
    def getOrder(self, vtOrderID):
        """查询委托"""
        return self.dataEngine.getOrder(vtOrderID)

    #----------------------------------------------------------------------
    def getAllWorkingOrders(self):
        """查询所有的活跃的委托(返回列表)"""
        return self.dataEngine.getAllWorkingOrders()

    # ----------------------------------------------------------------------
    def getAllGatewayNames(self):
        """查询引擎中所有可用接口的名称"""
        return self.gatewayDict.keys()

    def clearData(self):
        """清空数据引擎的数据"""
        self.dataEngine.clearData()
        self.ctaEngine.clearData()

    def saveData(self):
        self.ctaEngine.saveStrategyData()

    def initStrategy(self, name, force=False):
        if not self.ctaEngine:
            self.writeError(u'Cta Engine not started')
            return
        self.ctaEngine.initStrategy(name=name, force=force)
        self.qryStatus()

    def startStrategy(self, name):
        if not self.ctaEngine:
            self.writeError(u'Cta Engine not started')
            return
        self.ctaEngine.startStrategy(name=name)
        self.qryStatus()

    def stopStrategy(self, name):
        if not self.ctaEngine:
            self.writeError(u'Cta Engine not started')
            return
        self.ctaEngine.stopStrategy(name=name)
        self.qryStatus()