class StrategyEngine(object): '''策略引擎''' def __init__(self, logger, eg2uiQueue, ui2egQueue): self.logger = logger # Engine->Ui, 包括资金,权益等 self._eg2uiQueue = eg2uiQueue # Ui->Engine, 包括策略加载等 self._ui2egQueue = ui2egQueue def _initialize(self): '''进程中初始化函数''' self.logger.info('Initialize strategy engine!') # 数据模型 self._dataModel = DataModel(self.logger) self._qteModel = self._dataModel.getQuoteModel() self._hisModel = self._dataModel.getHisQuoteModel() self._trdModel = self._dataModel.getTradeModel() # api回调函数 self._regApiCallback() # 策略发送函数 self._regMainWorkFunc() # Api->Engine, 品种、行情、K线、交易等 self._api2egQueue = queue.Queue() # Strategy->Engine, 初始化、行情、K线、交易等 self._st2egQueue = Queue() # 创建主处理线程, 从api和策略进程收数据处理 self._startMainThread() # 创建_pyApi对象 self._pyApi = PyAPI(self.logger, self._api2egQueue) # 策略编号,自增 self._maxStrategyId = 1 # 创建策略管理器 self._strategyMgr = StartegyManager(self.logger, self._st2egQueue) # 策略进程队列列表 self._eg2stQueueDict = {} #{strategy_id, queue} # 即时行情订阅列表 self._contStrategyDict = {} #{'contractNo' : [strategyId1, strategyId2...]} # 历史K线订阅列表 self._hisContStrategyDict = {} #{'contractNo' : [strategyId1, strategyId2...]} self.logger.debug('Initialize strategy engine ok!') def _regApiCallback(self): self._apiCallbackDict = { EEQU_SRVEVENT_CONNECT : self._onApiConnect , EEQU_SRVEVENT_DISCONNECT : self._onApiDisconnect , EEQU_SRVEVENT_EXCHANGE : self._onApiExchange , EEQU_SRVEVENT_COMMODITY : self._onApiCommodity , EEQU_SRVEVENT_CONTRACT : self._onApiContract , EEQU_SRVEVENT_TIMEBUCKET : self._onApiTimeBucket , EEQU_SRVEVENT_QUOTESNAP : self._onApiSnapshot , EEQU_SRVEVENT_QUOTESNAPLV2 : self._onApiDepthQuote , EEQU_SRVEVENT_HISQUOTEDATA : self._onApiKlinedataRsp , EEQU_SRVEVENT_HISQUOTENOTICE : self._onApiKlinedataNotice , EEQU_SRVEVENT_TRADE_LOGINQRY : self._onApiLoginInfo , EEQU_SRVEVENT_TRADE_USERQRY : self._onApiUserInfo , EEQU_SRVEVENT_TRADE_LOGINNOTICE : self._onApiLoginInfo , EEQU_SRVEVENT_TRADE_ORDERQRY : self._onApiOrderDataQry , EEQU_SRVEVENT_TRADE_ORDER : self._onApiOrderData , EEQU_SRVEVENT_TRADE_MATCHQRY : self._onApiMatchDataQry , EEQU_SRVEVENT_TRADE_MATCH : self._onApiMatchData , EEQU_SRVEVENT_TRADE_POSITQRY : self._onApiPosDataQry , EEQU_SRVEVENT_TRADE_POSITION : self._onApiPosData , EEQU_SRVEVENT_TRADE_FUNDQRY : self._onApiMoney , EV_EG2ST_ACTUAL_ORDER_SESSION_MAP : self._onOrderSessionMap, } def _regMainWorkFunc(self): self._mainWorkFuncDict = { EV_ST2EG_EXCHANGE_REQ : self._onExchange , EV_ST2EG_COMMODITY_REQ : self._reqCommodity , EV_ST2EG_SUB_QUOTE : self._reqSubQuote , EV_ST2EG_UNSUB_QUOTE : self._reqUnsubQuote , EV_ST2EG_SUB_HISQUOTE : self._reqSubHisquote , EV_ST2EG_UNSUB_HISQUOTE : self._reqUnsubHisquote , EV_ST2EG_SWITCH_STRATEGY : self._reqKLineStrategySwitch , # EV_ST2EG_NOTICE_KLINEDATA : self._sendKLineData, EV_ST2EG_UPDATE_KLINEDATA : self._sendKLineData, # k line series EV_ST2EG_ADD_KLINESERIES : self._addSeries, EV_ST2EG_NOTICE_KLINESERIES : self._sendKLineSeries, EV_ST2EG_UPDATE_KLINESERIES : self._sendKLineSeries, # k line signal EV_ST2EG_ADD_KLINESIGNAL : self._addSignal, EV_ST2EG_NOTICE_KLINESIGNAL : self._sendKLineSignal, EV_ST2EG_UPDATE_KLINESIGNAL : self._sendKLineSignal, # 暂停、恢复、与退出 EV_UI2EG_STRATEGY_PAUSE : self._onStrategyPause, EV_UI2EG_STRATEGY_RESUME : self._onStrategyResume, EV_UI2EG_EQUANT_EXIT : self._onEquantExit, EV_ST2EG_UPDATE_STRATEGYDATA : self._reqStrategyDataUpdateNotice, EV_EG2UI_REPORT_RESPONSE : self._reportResponse, EV_EG2UI_CHECK_RESULT : self._checkResponse, EV_EG2ST_MONITOR_INFO : self._monitorResponse, # load strategy EV_EG2UI_LOADSTRATEGY_RESPONSE : self._loadStrategyResponse, EV_EG2UI_STRATEGY_STATUS : self._starategyStatus, EV_ST2EG_STRATEGYTRADEINFO : self._reqTradeInfo, EV_ST2EG_ACTUAL_ORDER : self._sendOrder, EV_ST2EG_ACTUAL_CANCEL_ORDER : self._deleteOrder, EV_ST2EG_ACTUAL_MODIFY_ORDER : self._modifyOrder, } def run(self): # 在当前进程中初始化 self._initialize() while True: self._handleUIData() def _sendEvent2Strategy(self, strategyId, event): if strategyId not in self._eg2stQueueDict: return eg2stQueue = self._eg2stQueueDict[strategyId] eg2stQueue.put(event) def _sendEvent2AllStrategy(self, event): for id in self._eg2stQueueDict: self._eg2stQueueDict[id].put(event) def _dispathQuote2Strategy(self, code, apiEvent): '''分发即时行情''' apiData = apiEvent.getData() contractNo = apiEvent.getContractNo() contStList = self._contStrategyDict[contractNo] data = apiData[:] msg = { 'EventSrc' : EEQU_EVSRC_ENGINE, 'EventCode' : code, 'StrategyId' : 0, 'SessionId' : 0, 'UserNo' : '', 'ContractNo' : contractNo, 'Data' : data } event = Event(msg) for id in contStList: self._sendEvent2Strategy(id, event) # //////////////////////UI事件处理函数///////////////////// def _handleUIData(self): try: event = self._ui2egQueue.get() if type(event) is dict: event = Event(event) code = event.getEventCode() if code == EV_UI2EG_LOADSTRATEGY: # 加载策略事件 self._loadStrategy(event) elif code == EV_UI2EG_REPORT: self._noticeStrategyReport(event) elif code == EV_UI2EG_STRATEGY_PAUSE: self._onStrategyPause(event) elif code == EV_UI2EG_STRATEGY_RESUME: self._onStrategyResume(event) elif code == EV_UI2EG_EQUANT_EXIT: self._onEquantExit(event) except queue.Empty as e: pass # def _noticeStrategyReport(self, event): self._strategyMgr.sendEvent2Strategy(event.getStrategyId(), event) def _getStrategyId(self): id = self._maxStrategyId self._maxStrategyId += 1 return id def _loadStrategy(self, event): id = self._getStrategyId() eg2stQueue = Queue(2000) self._eg2stQueueDict[id] = eg2stQueue self._strategyMgr.create(id, eg2stQueue, event) # ================= self._strategyMgr.sendEvent2Strategy(id, event) def _loadStrategyResponse(self, event): self._eg2uiQueue.put(event) def _starategyStatus(self, event): self._eg2uiQueue.put(event) #////////////////api回调及策略请求事件处理////////////////// def _handleApiData(self): try: apiEvent = self._api2egQueue.get_nowait() code = apiEvent.getEventCode() # print("c api code =", code) if code not in self._apiCallbackDict: return self._apiCallbackDict[code](apiEvent) except queue.Empty as e: pass def _handelStData(self): try: event = self._st2egQueue.get_nowait() code = event.getEventCode() if code not in self._mainWorkFuncDict: self.logger.debug('Event %d not register in _mainWorkFuncDict'%code) #print("未处理的event code =",code) return self._mainWorkFuncDict[code](event) except (queue.Empty, KeyError) as e: if e is KeyError: event.printTool() print(" now code is ", code) pass def _mainThreadFunc(self): while True: self._handleApiData() self._handelStData() #time.sleep(0.01) def _startMainThread(self): '''从api队列及策略队列中接收数据''' self._apiThreadH = Thread(target=self._mainThreadFunc) self._apiThreadH.start() def _moneyThreadFunc(self): while True: eventList = self._trdModel.getMoneyEvent() #查询所有账户下的资金 for event in eventList: self._reqMoney(event) time.sleep(60) def _createMoneyTimer(self): '''资金查询线程''' self._moneyThreadH = Thread(target=self._moneyThreadFunc) self._moneyThreadH.start() #////////////////api回调事件////////////////////////////// def _onApiConnect(self, apiEvent): self._pyApi.reqExchange(Event({'StrategyId':0, 'Data':''})) def _onApiDisconnect(self, apiEvent): ''' 断连事件:区分与9.5/交易/即时行情/历史行情 1. 与9.5断连: a. 停止所有策略(包括回测与运行) b. 通知界面断连状态 c. 设置引擎状态为与9.5断连 d. 清理所有数据,重置数据状态 2. 与即时行情断连 a. 停止所有策略(运行) b 通知界面断连状态 c. 设置引擎状态为与即时行情断连 d. 清理所有即时行情数据 3. 与历史行情断连 a. 停止所有策略(包括回测和运行) b. 通知界面断连状态 c. 设置引擎状态为与历史行情断连 d. 清理所有历史K线数据 4. 与交易断连 a. 停止所有策略(运行) b. 通知界面断连状态 c. 设置引擎状态为与交易断开链接 d. 清理所有交易数据 说明:策略停止后,所有相关数据清理 ''' # def _onApiExchange(self, apiEvent): self._qteModel.updateExchange(apiEvent) self._sendEvent2Strategy(apiEvent.getStrategyId(), apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqCommodity(Event({'StrategyId':0, 'Data':''})) def _onApiCommodity(self, apiEvent): self._qteModel.updateCommodity(apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqContract(Event({'StrategyId':0, 'Data':''})) # 发送商品交易时间模板请求 dataList = apiEvent.getData() for dataDict in dataList: event = Event({ 'EventCode': EV_ST2EG_TIMEBUCKET_REQ, 'StrategyId': apiEvent.getStrategyId(), 'Data': dataDict['CommodityNo'], }) self._pyApi.reqTimebucket(event) def _onApiContract(self, apiEvent): self._qteModel.updateContract(apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqQryLoginInfo(Event({'StrategyId':0, 'Data':''})) def _onApiTimeBucket(self, apiEvent): self._qteModel.updateTimeBucket(apiEvent) def _onApiSnapshot(self, apiEvent): self._qteModel.updateLv1(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_SNAPSHOT_NOTICE, apiEvent) def _onApiDepthQuote(self, apiEvent): self._qteModel.updateLv2(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_DEPTH_NOTICE, apiEvent) def _onApiKlinedataRsp(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_RSP) def _onApiKlinedataNotice(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_NOTICE) def _onApiKlinedata(self, apiEvent, code): self._hisModel.updateKline(apiEvent) strategyId = apiEvent.getStrategyId() #策略号为0,认为是推送数据 apiData = apiEvent.getData() data = apiData[:] event = Event({ 'StrategyId' : strategyId, 'EventCode' : code, 'ChainEnd' : apiEvent.getChain(), 'ContractNo' : apiEvent.getContractNo(), 'KLineType' : apiEvent.getKLineType(), 'KLineSlice' : apiEvent.getKLineSlice(), 'Data' : data }) if strategyId > 0: self._sendEvent2Strategy(strategyId, event) return #推送数据,分发 contNo = apiEvent.getContractNo() if contNo not in self._hisContStrategyDict: return stDict = self._hisContStrategyDict[contNo] for key in stDict: event.setStrategyId(key) self._sendEvent2Strategy(key, event) # 用户登录信息 def _onApiLoginInfo(self, apiEvent): self._trdModel.updateLoginInfo(apiEvent) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_LOGIN) self._reqUserInfo(Event({'StrategyId':0, 'Data':''})) # 账户信息 def _onApiUserInfo(self, apiEvent): self._trdModel.updateUserInfo(apiEvent) self._eg2uiQueue.put(apiEvent) # print("++++++ 账户信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_USER) # 查询所有账户下委托信息 eventList = self._trdModel.getOrderEvent() for event in eventList: # print("====== 查询所有账户下委托信息 ======", event.getData()) self._reqOrder(event) def _onApiOrderDataQry(self, apiEvent): self._trdModel.updateOrderData(apiEvent) # print("++++++ 订单信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_ORDER) #查询所有账户下成交信息 eventList = self._trdModel.getMatchEvent() for event in eventList: self._reqMatch(event) def _onApiOrderData(self, apiEvent): # 订单信息 self._trdModel.updateOrderData(apiEvent) # print("++++++ 订单信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiMatchDataQry(self, apiEvent): self._trdModel.updateMatchData(apiEvent) # print("++++++ 成交信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_MATCH) #查询所有账户下成交信息 eventList = self._trdModel.getPositionEvent() for event in eventList: self._reqPosition(event) def _onApiMatchData(self, apiEvent): # 成交信息 self._trdModel.updateMatchData(apiEvent) # print("++++++ 成交信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiPosDataQry(self, apiEvent): self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_POSITION) #交易基础数据查询完成,定时查询资金 self._createMoneyTimer() def _onApiPosData(self, apiEvent): # 持仓信息 self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiMoney(self, apiEvent): # 资金信息 self._trdModel.updateMoney(apiEvent) # print("++++++ 资金信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) def _onOrderSessionMap(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) def _reqTradeInfo(self, event): ''' 查询账户信息,如果用户未登录,则Data返回为空 ''' stragetyId = event.getStrategyId() if len(self._trdModel._loginInfo) == 0: trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': '', }) self._sendEvent2Strategy(stragetyId, trdEvent) return 0 data = { 'loginInfo' : {}, # 登录账号信息 'userInfo' : {}, # 资金账号信息 } # 登录账号信息 loginInfoDict = {} for userNo, tLoginModel in self._trdModel._loginInfo.items(): loginInfoDict[userNo] = tLoginModel.copyLoginInfoMetaData() data['loginInfo'] = loginInfoDict # 资金账号信息 userInfoDict = {} for userNo, tUserInfoModel in self._trdModel._userInfo.items(): userInfoDict[userNo] = tUserInfoModel.formatUserInfo() data['userInfo'] = userInfoDict stragetyId = event.getStrategyId() trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': data, }) self._sendEvent2Strategy(stragetyId, trdEvent) #///////////////策略进程事件////////////////////////////// def _addSubscribe(self, contractNo, strategyId): stDict = self._contStrategyDict[contractNo] # 重复订阅 if strategyId in stDict: return stDict[strategyId] = None def _sendQuote(self, contractNo, strategyId): event = self._qteModel.getQuoteEvent(contractNo, strategyId) self._sendEvent2Strategy(strategyId, event) def _onExchange(self, event): '''查询交易所信息''' revent = self._qteModel.getExchange() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqCommodity(self, event): '''查询品种信息''' revent = self._qteModel.getCommodity() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqSubQuote(self, event): '''订阅即时行情''' contractList = event.getData() strategyId = event.getStrategyId() subList = [] for contractNo in contractList: if contractNo not in self._contStrategyDict: subList.append(contractNo) self._contStrategyDict[contractNo] = {strategyId:None} else: if strategyId in self._contStrategyDict[contractNo]: continue #重复订阅,不做任何处理 self._contStrategyDict[contractNo][strategyId] = None self._sendQuote(contractNo, strategyId) if len(subList) > 0: event.setData(subList) self._pyApi.reqSubQuote(event) def _reqUnsubQuote(self, event): '''退订即时行情''' strategyId = event.getStrategyId() contractList = event.getData() unSubList = [] for contNo in contractList: if contNo not in self._contStrategyDict: continue #该合约没有订阅 stDict = self._contStrategyDict[contNo] if strategyId not in stDict: continue #该策略没有订阅 stDict.pop(strategyId) #已经没有人订阅了,退订吧 if len(stDict) <= 0: unSubList.append(contNo) if len(unSubList) > 0: event.setData(unSubList) self._pyApi.reqUnsubQuote(event) # def _reqTimebucket(self, event): # '''查询时间模板''' # self._pyApi.reqTimebucket(event) def _reqSubHisquote(self, event): '''订阅历史行情''' data = event.getData() if data['NeedNotice'] == EEQU_NOTICE_NOTNEED: self._pyApi.reqSubHisquote(event) return strategyId = event.getStrategyId() data = event.getData() contNo = data['ContractNo'] if contNo not in self._hisContStrategyDict: self._hisContStrategyDict[contNo] = {strategyId:None} stDict = self._hisContStrategyDict[contNo] if strategyId not in stDict: stDict[strategyId] = None self._pyApi.reqSubHisquote(event) def _reqUnsubHisquote(self, event): '''退订历史行情''' strategyId = event.getStrategyId() data = event.getData() contNo = data['ContractNo'] if contNo not in self._hisContStrategyDict: return #该合约没有订阅 stDict = self._hisContStrategyDict[contNo] if strategyId not in stDict: return #该策略没有订阅 stDict.pop(strategyId) #已经没有人订阅了,退订吧 unSubList = [] if len(stDict) <= 0: unSubList.append(contNo) if len(unSubList) > 0: self._pyApi.reqUnsubHisquote(event) def _reqKLineStrategySwitch(self, event): '''切换策略图''' self._pyApi.reqKLineStrategySwitch(event) def _reqKLineDataResult(self, event): '''推送回测K线数据''' self._pyApi.reqKLineDataResult(event) def _reqKLineDataResultNotice(self, event): '''更新实盘K线数据''' self._pyApi.reqKLineDataResultNotice(event) def _reqAddKLineSeriesInfo(self, event): '''增加指标数据''' self._pyApi.addSeries(event) def _reqKLineSeriesResult(self, event): '''推送回测指标数据''' self._pyApi.sendSeries(event) def _reqAddKLineSignalInfo(self, event): '''增加信号数据''' self._pyApi.addSignal(event) def _reqKLineSignalResult(self, event): '''推送回测信号数据''' self._pyApi.sendSignal(event) def _reqStrategyDataUpdateNotice(self, event): '''刷新指标、信号通知''' self._pyApi.reqStrategyDataUpdateNotice(event) def _reportResponse(self, event): # print(" engine 进程,收到策略进程的report 结果,并向ui传递") # print(event.getData()) self._eg2uiQueue.put(event) def _checkResponse(self, event): #print(" engine 进程,收到策略进程的检查结果,并向ui传递") self._eg2uiQueue.put(event) def _monitorResponse(self, event): self._eg2uiQueue.put(event) ################################交易请求######################### def _reqUserInfo(self, event): self._pyApi.reqQryUserInfo(event) def _reqOrder(self, event): self._pyApi.reqQryOrder(event) def _reqMatch(self, event): self._pyApi.reqQryMatch(event) def _reqPosition(self, event): self._pyApi.reqQryPosition(event) def _reqMoney(self, event): self._pyApi.reqQryMoney(event) def _sendOrder(self, event): # 委托下单,发送委托单 self._pyApi.reqInsertOrder(event) def _deleteOrder(self, event): # 委托撤单 self._pyApi.reqCancelOrder(event) def _modifyOrder(self, event): # 委托改单 self._pyApi.reqModifyOrder(event) def _sendKLineData(self, event): '''推送K线数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINEDATA: self._pyApi.sendKLineData(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINEDATA: self._pyApi.sendKLineData(event, 'U') def _addSeries(self, event): '''增加指标线''' self._pyApi.addSeries(event) def _sendKLineSeries(self, event): '''推送指标数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'U') def _addSignal(self, event): '''增加信号线''' self._pyApi.addSignal(event) def _sendKLineSignal(self, event): '''推送信号数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'U') # 暂停当前策略 def _onStrategyPause(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) # 恢复当前策略 def _onStrategyResume(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) # 当量化退出时,发事件给所有的策略 def _onEquantExit(self, event): self._sendEvent2AllStrategy(event)
class StrategyEngine(object): '''策略引擎''' def __init__(self, logger, eg2uiQueue, ui2egQueue): self.logger = logger # Engine->Ui, 包括资金,权益等 self._eg2uiQueue = eg2uiQueue # Ui->Engine, 包括策略加载等 self._ui2egQueue = ui2egQueue def _initialize(self): '''进程中初始化函数''' self.logger.info('Initialize strategy engine!') # 数据模型 self._dataModel = DataModel(self.logger) self._qteModel = self._dataModel.getQuoteModel() self._hisModel = self._dataModel.getHisQuoteModel() self._trdModel = self._dataModel.getTradeModel() # api回调函数 self._regApiCallback() # 策略发送函数 self._regMainWorkFunc() # Api->Engine, 品种、行情、K线、交易等 self._api2egQueue = queue.Queue() # Strategy->Engine, 初始化、行情、K线、交易等 self._st2egQueue = Queue() # 创建_pyApi对象 self._pyApi = PyAPI(self.logger, self._api2egQueue) # 策略编号,自增 self._maxStrategyId = 1 # 创建策略管理器 self._strategyMgr = StartegyManager(self.logger, self._st2egQueue) # 策略进程队列列表 self._eg2stQueueDict = {} #{strategy_id, queue} self._isEffective = {} self._isSt2EngineDataEffective = {} # 策略虚拟持仓 self._strategyPosDict = {} # 即时行情订阅列表 self._quoteOberverDict = { } #{'contractNo' : [strategyId1, strategyId2...]} # 历史K线订阅列表 self._hisKLineOberverDict = { } #{'contractNo' : [strategyId1, strategyId2...]} self._lastMoneyTime = 0 #资金查询时间 self._lastPosTime = 0 #持仓同步时间 # 恢复上次推出时保存的结构 self._strategyOrder = {} try: self._resumeStrategy() except Exception as e: traceback.print_exc() self.logger.error(f"恢复策略失败") self._engineOrderModel = EngineOrderModel(self._strategyOrder) self._enginePosModel = EnginePosModel() # 创建主处理线程, 从api和策略进程收数据处理 self._startMainThread() # 启动1秒定时器 self._start1secondsTimer() self.logger.debug('Initialize strategy engine ok!') def _resumeStrategy(self): if not os.path.exists('config/StrategyContext.json'): return with open("config/StrategyContext.json", 'r', encoding="utf-8") as resumeFile: strategyContext = json.load(resumeFile) for k, v in strategyContext.items(): if k == "MaxStrategyId": self._maxStrategyId = int(v) self.logger.debug("恢复策略最大Id成功") elif k == "StrategyConfig": self.resumeAllStrategyConfig(v) self.logger.debug("恢复策略配置成功") elif k == "StrategyOrder": self._resumeStrategyOrder(v) self.logger.debug("恢复策略订单成功") else: pass def resumeAllStrategyConfig(self, strategyConfig): # self.logger.info(strategyConfig) copyConfig = {} for k, v in strategyConfig.items(): copyConfig[int(k)] = None sortedList = sorted(copyConfig) # self.logger.info(sortedList) for strategyId in sortedList: strategyIni = strategyConfig[str(strategyId)] config = StrategyConfig(strategyIni["Config"]) key = config.getKLineShowInfoSimple() fakeEvent = Event({ "EventCode": EV_EG2UI_LOADSTRATEGY_RESPONSE, "StrategyId": strategyId, "ErrorCode": 0, "ErrorText": "", "Data": { "StrategyId": strategyId, "StrategyName": strategyIni["StrategyName"], "StrategyState": ST_STATUS_QUIT, "ContractNo": key[0], "KLineType": key[1], "KLinceSlice": key[2], "IsActualRun": config.isActualRun(), "InitialFund": config.getInitCapital(), "Config": strategyIni["Config"], "Path": strategyIni["Path"], "Params": config.getParams(), } }) self._eg2uiQueue.put(fakeEvent) self._strategyMgr.insertResumedStrategy(strategyId, fakeEvent.getData()) def _resumeStrategyOrder(self, strategyOrder): if not strategyOrder: strategyOrder = {} self._strategyOrder = strategyOrder def _regApiCallback(self): self._apiCallbackDict = { EEQU_SRVEVENT_CONNECT: self._onApiConnect, EEQU_SRVEVENT_DISCONNECT: self._onApiDisconnect, EEQU_SRVEVENT_EXCHANGE: self._onApiExchange, EEQU_SRVEVENT_COMMODITY: self._onApiCommodity, EEQU_SRVEVENT_UNDERLAYMAPPING: self._onApiUnderlayMapping, EEQU_SRVEVENT_CONTRACT: self._onApiContract, EEQU_SRVEVENT_TIMEBUCKET: self._onApiTimeBucket, EEQU_SRVEVENT_QUOTESNAP: self._onApiSnapshot, EEQU_SRVEVENT_QUOTESNAPLV2: self._onApiDepthQuote, EEQU_SRVEVENT_HISQUOTEDATA: self._onApiKlinedataRsp, EEQU_SRVEVENT_HISQUOTENOTICE: self._onApiKlinedataNotice, EEQU_SRVEVENT_TRADE_LOGINQRY: self._onApiLoginInfo, EEQU_SRVEVENT_TRADE_USERQRY: self._onApiUserInfo, EEQU_SRVEVENT_TRADE_LOGINNOTICE: self._onApiLoginInfo, EEQU_SRVEVENT_TRADE_ORDERQRY: self._onApiOrderDataQry, EEQU_SRVEVENT_TRADE_ORDER: self._onApiOrderDataNotice, EEQU_SRVEVENT_TRADE_MATCHQRY: self._onApiMatchDataQry, EEQU_SRVEVENT_TRADE_MATCH: self._onApiMatchData, EEQU_SRVEVENT_TRADE_POSITQRY: self._onApiPosDataQry, EEQU_SRVEVENT_TRADE_POSITION: self._onApiPosData, EEQU_SRVEVENT_TRADE_FUNDQRY: self._onApiMoney, EEQU_SRVEVENT_TRADE_EXCSTATEQRY: self._onApiExchangeStateQry, EEQU_SRVEVENT_TRADE_EXCSTATE: self._onExchangeStateNotice, } def _regMainWorkFunc(self): self._mainWorkFuncDict = { EV_ST2EG_EXCHANGE_REQ: self._reqExchange, EV_ST2EG_COMMODITY_REQ: self._reqCommodity, EV_ST2EG_CONTRACT_REQ: self._reqContract, EV_ST2EG_UNDERLAYMAPPING_REQ: self._reqUnderlayMap, EV_ST2EG_SUB_QUOTE: self._reqSubQuote, EV_ST2EG_UNSUB_QUOTE: self._reqUnsubQuote, EV_ST2EG_SUB_HISQUOTE: self._reqSubHisquote, EV_ST2EG_UNSUB_HISQUOTE: self._reqUnsubHisquote, EV_ST2EG_SWITCH_STRATEGY: self._reqKLineStrategySwitch, # EV_ST2EG_NOTICE_KLINEDATA: self._sendKLineData, EV_ST2EG_UPDATE_KLINEDATA: self._sendKLineData, # k line series EV_ST2EG_ADD_KLINESERIES: self._addSeries, EV_ST2EG_NOTICE_KLINESERIES: self._sendKLineSeries, EV_ST2EG_UPDATE_KLINESERIES: self._sendKLineSeries, # k line signal EV_ST2EG_ADD_KLINESIGNAL: self._addSignal, EV_ST2EG_NOTICE_KLINESIGNAL: self._sendKLineSignal, EV_ST2EG_UPDATE_KLINESIGNAL: self._sendKLineSignal, ST_ST2EG_SYNC_CONFIG: self._syncStrategyConfig, EV_ST2EG_STRATEGYTRADEINFO: self._reqTradeInfo, EV_ST2EG_ACTUAL_ORDER: self._sendOrder, EV_ST2EG_ACTUAL_CANCEL_ORDER: self._deleteOrder, EV_ST2EG_ACTUAL_MODIFY_ORDER: self._modifyOrder, EV_ST2EG_UPDATE_STRATEGYDATA: self._reqStrategyDataUpdateNotice, EV_ST2EG_POSITION_NOTICE: self._noticeVirtualPos, # 暂停、恢复、与退出 EV_UI2EG_STRATEGY_QUIT: self._onStrategyQuit, EV_UI2EG_STRATEGY_RESUME: self._onStrategyResume, EV_UI2EG_EQUANT_EXIT: self._onEquantExit, EV_UI2EG_STRATEGY_FIGURE: self._switchStrategy, EV_UI2EG_STRATEGY_RESTART: self._restartStrategyWhenParamsChanged, EV_EG2UI_REPORT_RESPONSE: self._reportResponse, EV_EG2UI_CHECK_RESULT: self._checkResponse, EV_EG2ST_MONITOR_INFO: self._monitorResponse, # load strategy EV_EG2UI_LOADSTRATEGY_RESPONSE: self._loadStrategyResponse, EV_EG2UI_STRATEGY_STATUS: self._onStrategyStatus, } def run(self): # 在当前进程中初始化 self._initialize() while True: try: self._handleUIData() except Exception as e: errorText = traceback.format_exc() self.sendErrorMsg(-1, errorText) def _sendEvent2Strategy(self, strategyId, event): if strategyId not in self._eg2stQueueDict or strategyId not in self._isEffective or not self._isEffective[ strategyId]: return if event is None: return eg2stQueue = self._eg2stQueueDict[strategyId] while True: try: eg2stQueue.put_nowait(event) break except queue.Full: time.sleep(0.1) self.logger.warn( f"engine向策略发事件时阻塞,策略id:{strategyId}, 事件号: {event.getEventCode()}" ) def _sendEvent2StrategyForce(self, strategyId, event): eg2stQueue = self._eg2stQueueDict[strategyId] while True: try: eg2stQueue.put_nowait(event) break except queue.Full: time.sleep(0.1) self.logger.warn( f"engine向策略发事件时阻塞,策略id:{strategyId}, 事件号: {event.getEventCode()}" ) def _sendEvent2AllStrategy(self, event): for strategyId in self._eg2stQueueDict: eventCopy = copy.deepcopy(event) eventCopy.setStrategyId(strategyId) self._sendEvent2Strategy(strategyId, eventCopy) def _dispathQuote2Strategy(self, code, apiEvent): '''分发即时行情''' contractNo = apiEvent.getContractNo() contStList = self._quoteOberverDict[contractNo] apiEvent.setEventCode(code) for id in contStList: self._sendEvent2Strategy(id, apiEvent) # //////////////////////UI事件处理函数///////////////////// def _handleUIData(self): event = self._ui2egQueue.get() code = event.getEventCode() if code == EV_UI2EG_LOADSTRATEGY: # 加载策略事件 self._loadStrategy(event) elif code == EV_UI2EG_REPORT: self._noticeStrategyReport(event) elif code == EV_UI2EG_STRATEGY_QUIT: self._onStrategyQuit(event) elif code == EV_UI2EG_STRATEGY_RESUME: self._onStrategyResume(event) elif code == EV_UI2EG_EQUANT_EXIT: self._onEquantExit(event) elif code == EV_UI2EG_STRATEGY_REMOVE: self.logger.info(f"收到策略删除信号,策略id:{event.getStrategyId()}") self._onStrategyRemove(event) elif code == EV_UI2EG_STRATEGY_FIGURE: self._switchStrategy(event) elif code == EV_UI2EG_STRATEGY_RESTART: self._restartStrategyWhenParamsChanged(event) # def _noticeStrategyReport(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) def _getStrategyId(self): id = self._maxStrategyId self._maxStrategyId += 1 return id def _loadStrategy(self, event, strategyId=None): id = self._getStrategyId() if strategyId is None else strategyId eg2stQueue = Queue(20000) self._eg2stQueueDict[id] = eg2stQueue self._strategyMgr.create(id, eg2stQueue, self._eg2uiQueue, self._st2egQueue, event) # broken pip error 修复 self._isEffective[id] = True self._isSt2EngineDataEffective[id] = True # ================= self._sendEvent2Strategy(id, event) def _loadStrategyResponse(self, event): self._eg2uiQueue.put(event) def _onStrategyStatus(self, event): if event.getData()["Status"] == ST_STATUS_QUIT: self._onStrategyQuitCom(event) elif event.getData()["Status"] == EV_UI2EG_EQUANT_EXIT: self._singleStrategyExitComEquantExit(event) elif event.getData()["Status"] == ST_STATUS_CONTINUES: self._eg2uiQueue.put(event) elif event.getData()["Status"] == ST_STATUS_REMOVE: self._onStrategyRemoveCom(event) self.logger.info(f"策略删除完成,策略id:{event.getStrategyId()}") elif event.getData()["Status"] == ST_STATUS_EXCEPTION: self._onStrategyExceptionCom(event) def _onStrategyExceptionCom(self, event): self.sendEvent2UI(event) self._cleanStrategyInfo(event.getStrategyId()) self._strategyMgr.handleStrategyException(event) # ////////////////api回调及策略请求事件处理////////////////// def _handleApiData(self): try: apiEvent = self._api2egQueue.get_nowait() code = apiEvent.getEventCode() # print("c api code =", code) if code not in self._apiCallbackDict: return # 处理api event及异常 try: self._apiCallbackDict[code](apiEvent) except Exception as e: traceback.print_exc() self.logger.error( "处理 c api 发来的数据出现错误, event code = {}".format(code)) errorText = traceback.format_exc() errorText = errorText + "When handle C API in engine, EventCode: {}".format( code) self.sendErrorMsg(-1, errorText) self.maxContinuousIdleTimes = 0 except queue.Empty as e: self.maxContinuousIdleTimes += 1 pass def _handleStData(self): try: event = self._st2egQueue.get_nowait() code = event.getEventCode() strategyId = event.getStrategyId() if code not in self._mainWorkFuncDict: self.logger.debug( 'Event %d not register in _mainWorkFuncDict' % code) # print("未处理的event code =",code) return try: if strategyId in self._isSt2EngineDataEffective and not self._isSt2EngineDataEffective[ strategyId]: return self._mainWorkFuncDict[code](event) except Exception as e: # traceback.print_exc() errorText = traceback.format_exc() errorText = errorText + f"When handle strategy:{strategyId} in engine, EventCode: {code}. stop stratey {strategyId}!" self._handleEngineExceptionCausedByStrategy(strategyId) self.sendErrorMsg(-1, errorText) self.maxContinuousIdleTimes = 0 except queue.Empty as e: self.maxContinuousIdleTimes += 1 pass maxContinuousIdleTimes = 0 def _mainThreadFunc(self): while True: self._handleApiData() self._handleStData() if self.maxContinuousIdleTimes >= 1000: time.sleep(0.1) self.maxContinuousIdleTimes %= 1000 def _startMainThread(self): '''从api队列及策略队列中接收数据''' self._apiThreadH = Thread(target=self._mainThreadFunc) self._apiThreadH.start() def _1SecondsThreadFunc(self): '''1秒定时器''' while True: #60秒查一次资金 self._queryMoney() #10秒同步一次持仓 self._syncPosition() time.sleep(1) def _start1secondsTimer(self): '''资金查询线程''' self._1SecondsThreadH = Thread(target=self._1SecondsThreadFunc) self._1SecondsThreadH.start() def _queryMoney(self): nowTime = datetime.now() # 未登录,不查询资金 if not self._trdModel.isUserLogin(): self._lastMoneyTime = nowTime return if self._lastMoneyTime == 0 or ( nowTime - self._lastMoneyTime).total_seconds() >= 30: eventList = self._trdModel.getMoneyEvent() # 查询所有账户下的资金 allMoneyReqEvent = Event({"StrategyId": 0, "Data": {}}) self._reqMoney(allMoneyReqEvent) self._lastMoneyTime = nowTime def _syncPosition(self): nowTime = datetime.now() # 未登录,不同步持仓 if not self._trdModel.isUserLogin(): self._lastPosTime = nowTime return if self._lastPosTime == 0 or (nowTime - self._lastPosTime).total_seconds() >= 5: self._lastPosTime = nowTime accPos = {} #查询所有账户持仓情况 userInfo = self._trdModel.getUserInfo() for k, v in userInfo.items(): accPos[k] = v.getContPos() #获取所有策略的虚拟持仓 strategyPos = {} for id in self._strategyPosDict: if not self._isEffective[id]: continue if not self._isSt2EngineDataEffective[id]: continue strategyPos[id] = self._strategyPosDict[id] event = Event({ "EventCode": EV_EG2UI_POSITION_NOTICE, "Data": { "Account": accPos, "Strategy": strategyPos } }) #self.logger.info("Sync position to ui:%s"%event.getData()) self._send2uiQueue(event) def _send2uiQueue(self, event): #self.logger.info("[ENGINE] Send event(%d,%d) to UI!"%(event.getEventCode(), event.getStrategyId())) self._eg2uiQueue.put(event) #////////////////api回调事件////////////////////////////// def _onApiConnect(self, apiEvent): self._pyApi.reqSpreadContractMapping() self._pyApi.reqExchange(Event({'StrategyId': 0, 'Data': ''})) self._send2uiQueue(apiEvent) #self._eg2uiQueue.put(apiEvent) def _onApiDisconnect(self, apiEvent): #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) ''' 断连事件:区分与9.5/交易/即时行情/历史行情 1. 与9.5断连: a. 停止所有策略(包括回测与运行) b. 通知界面断连状态 c. 设置引擎状态为与9.5断连 d. 清理所有数据,重置数据状态 2. 与即时行情断连 a. 停止所有策略(运行) b 通知界面断连状态 c. 设置引擎状态为与即时行情断连 d. 清理所有即时行情数据 3. 与历史行情断连 a. 停止所有策略(包括回测和运行) b. 通知界面断连状态 c. 设置引擎状态为与历史行情断连 d. 清理所有历史K线数据 4. 与交易断连 a. 停止所有策略(运行) b. 通知界面断连状态 c. 设置引擎状态为与交易断开链接 d. 清理所有交易数据 说明:策略停止后,所有相关数据清理 ''' # def _onApiExchange(self, apiEvent): self._qteModel.updateExchange(apiEvent) self._sendEvent2Strategy(apiEvent.getStrategyId(), apiEvent) #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqExchangeStatus(Event({'StrategyId': 0, 'Data': ''})) def _onApiExchangeStateQry(self, apiEvent): self._onExchangeStateNotice(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqCommodity(Event({'StrategyId': 0, 'Data': ''})) def _onExchangeStateNotice(self, apiEvent): self._qteModel.updateExchangeStatus(apiEvent) #self._sendEvent2Strategy(apiEvent.getStrategyId(), apiEvent) self._sendEvent2AllStrategy(apiEvent) #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) def _onApiCommodity(self, apiEvent): self._qteModel.updateCommodity(apiEvent) #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) self._sendEvent2AllStrategy(apiEvent) if apiEvent.isChainEnd(): #self._pyApi.reqContract(Event({'StrategyId':0, 'Data':''})) self._pyApi.reqTrendContractMapping( Event({ 'StrategyId': 0, 'Data': '' })) # 发送商品交易时间模板请求 dataList = apiEvent.getData() for dataDict in dataList: event = Event({ 'EventCode': EV_ST2EG_TIMEBUCKET_REQ, 'StrategyId': apiEvent.getStrategyId(), 'Data': dataDict['CommodityNo'], }) self._pyApi.reqTimebucket(event) def _onApiUnderlayMapping(self, apiEvent): self._qteModel.updateUnderlayMap(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqContract(Event({'StrategyId': 0, 'Data': ''})) def _onApiContract(self, apiEvent): self._qteModel.updateContract(apiEvent) #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqQryLoginInfo(Event({'StrategyId': 0, 'Data': ''})) def _onApiTimeBucket(self, apiEvent): self._qteModel.updateTimeBucket(apiEvent) def _onApiSnapshot(self, apiEvent): self._qteModel.updateLv1(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_SNAPSHOT_NOTICE, apiEvent) def _onApiDepthQuote(self, apiEvent): self._qteModel.updateLv2(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_DEPTH_NOTICE, apiEvent) def _onApiKlinedataRsp(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_RSP) def _onApiKlinedataNotice(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_NOTICE) def _onApiKlinedata(self, apiEvent, code): self._hisModel.updateKline(apiEvent) strategyId = apiEvent.getStrategyId() # 策略号为0,认为是推送数据 apiEvent.setEventCode(code) if strategyId > 0: self._sendEvent2Strategy(strategyId, apiEvent) return # 推送数据,分发 key = (apiEvent.getContractNo(), apiEvent.getKLineType(), apiEvent.getKLineSlice()) if key not in self._hisKLineOberverDict: return stDict = self._hisKLineOberverDict[key] for someStrategy in stDict: self._sendEvent2Strategy(someStrategy, apiEvent) # 用户登录信息 def _onApiLoginInfo(self, apiEvent): self._trdModel.updateLoginInfo(apiEvent) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_LOGIN) self._reqUserInfo(Event({'StrategyId': 0, 'Data': ''})) # 账户信息 def _onApiUserInfo(self, apiEvent): self._trdModel.updateUserInfo(apiEvent) #self._eg2uiQueue.put(apiEvent) self._send2uiQueue(apiEvent) # print("++++++ 账户信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_USER) # 查询所有账户下的资金 allMoneyReqEvent = Event({"StrategyId": 0, "Data": {}}) self._reqMoney(allMoneyReqEvent) # 查询所有账户下委托信息 allOrderReqEvent = Event({"StrategyId": 0, "Data": {}}) self._reqOrder(allOrderReqEvent) def _onApiOrderDataQry(self, apiEvent): self._trdModel.updateOrderData(apiEvent) # self.logger.debug(f"sun --------------- engine qry : ") # for dataDict in apiEvent.getData(): # self.logger.debug(f"sun ------ OrderId : {dataDict['OrderId']} , OrderState : {dataDict['OrderState']}") self._sendEvent2AllStrategy(apiEvent) # 获取关联的策略id和订单id self._engineOrderModel.updateEpoleStarOrder(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_ORDER) # 查询所有账户下成交信息 allMatchReqEvent = Event({"StrategyId": 0, "Data": {}}) self._reqMatch(allMatchReqEvent) def _onApiOrderDataNotice(self, apiEvent): # 订单信息 self._trdModel.updateOrderData(apiEvent) self._engineOrderModel.updateEpoleStarOrder(apiEvent) contractNo = apiEvent.getContractNo() # print("contractNo = ", contractNo, apiEvent.getData()) # 客户端手动开仓平仓 # self.logger.debug(f"sun --------------- engine notice : ") # self.logger.debug(f"sun ------ contNo : {apiEvent.getContractNo()} , cont : {apiEvent.getData()[0]['Cont']}") if not contractNo: contractNo = apiEvent.getData()[0]["Cont"] if not contractNo: return apiEvent.setContractNo(contractNo) # for dataDict in apiEvent.getData(): # self.logger.debug(f"sun ------ OrderId : {dataDict['OrderId']} , OrderState : {dataDict['OrderState']}") self._sendEvent2AllStrategy(apiEvent) def _onApiMatchDataQry(self, apiEvent): self._engineOrderModel.updateEpoleStarOrder(apiEvent) self._trdModel.updateMatchData(apiEvent) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_MATCH) # 查询所有账户下持仓信息 allPosReqEvent = Event({"StrategyId": 0, "Data": {}}) self._reqPosition(allPosReqEvent) def _onApiMatchData(self, apiEvent): self._engineOrderModel.updateEpoleStarOrder(apiEvent) # 成交信息 self._trdModel.updateMatchData(apiEvent) # print("++++++ 成交信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiPosDataQry(self, apiEvent): self._enginePosModel.updatePosRsp(apiEvent) self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 查询 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_POSITION) def _onApiPosData(self, apiEvent): self._enginePosModel.updatePosNotice(apiEvent) # 持仓信息 self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiMoney(self, apiEvent): # 资金信息 self._trdModel.updateMoney(apiEvent) # print("++++++ 资金信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) def _reqTradeInfo(self, event): ''' 查询账户信息,如果用户未登录,则Data返回为空 ''' stragetyId = event.getStrategyId() if len(self._trdModel._loginInfo) == 0: trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': '', }) self._sendEvent2Strategy(stragetyId, trdEvent) return 0 data = { 'loginInfo': {}, # 登录账号信息 'userInfo': {}, # 资金账号信息 } # 登录账号信息 loginInfoDict = {} for userNo, tLoginModel in self._trdModel._loginInfo.items(): loginInfoDict[userNo] = tLoginModel.copyLoginInfoMetaData() data['loginInfo'] = loginInfoDict # 资金账号信息 userInfoDict = {} for userNo, tUserInfoModel in self._trdModel._userInfo.items(): userInfoDict[userNo] = tUserInfoModel.formatUserInfo() data['userInfo'] = userInfoDict stragetyId = event.getStrategyId() trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': data, }) self._sendEvent2Strategy(stragetyId, trdEvent) # 订单恢复, 获取当前所有订单 orderEvents = self._engineOrderModel.getStrategyOrder(0) for orderEvent in orderEvents: self._sendEvent2Strategy(stragetyId, orderEvent) # 持仓恢复 matchEvents = self._engineOrderModel.getStrategyMatch(0) for matchEvent in matchEvents: self._sendEvent2Strategy(stragetyId, matchEvent) # 策略最大订单id恢复, strategyMaxOrderId = self._engineOrderModel.getMaxOrderId(stragetyId) event = Event({ "EventCode": EV_EG2ST_STRATEGY_SYNC, "StrategyId": stragetyId, "Data": { "MaxOrderId": strategyMaxOrderId } }) self._sendEvent2Strategy(stragetyId, event) def _noticeVirtualPos(self, event): # 策略虚拟持仓变化通知 stragetyId = event.getStrategyId() self._strategyPosDict[stragetyId] = event.getData() # ///////////////策略进程事件////////////////////////////// def _addSubscribe(self, contractNo, strategyId): stDict = self._quoteOberverDict[contractNo] # 重复订阅 if strategyId in stDict: return stDict[strategyId] = None def _sendQuote(self, contractNo, strategyId): event = self._qteModel.getQuoteEvent(contractNo, strategyId) self._sendEvent2Strategy(strategyId, event) def _reqExchange(self, event): '''查询交易所信息''' revent = self._qteModel.getExchange() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqCommodity(self, event): '''查询品种信息''' revent = self._qteModel.getCommodity() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqContract(self, event): '''查询合约信息''' revent = self._qteModel.getContract() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqUnderlayMap(self, event): '''查询主力/近月合约映射关系''' revent = self._qteModel.getUnderlayMap() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqSubQuote(self, event): '''订阅即时行情''' contractList = self.getContractList(event.getData()) strategyId = event.getStrategyId() subList = [] for contractNo in contractList: if contractNo not in self._quoteOberverDict: subList.append(contractNo) self._quoteOberverDict[contractNo] = {strategyId: None} else: if strategyId in self._quoteOberverDict[contractNo]: continue # 重复订阅,不做任何处理 self._quoteOberverDict[contractNo][strategyId] = None self._sendQuote(contractNo, strategyId) if len(subList) > 0: event.setData(subList) self._pyApi.reqSubQuote(event) def _reqUnsubQuote(self, event): '''退订即时行情''' strategyId = event.getStrategyId() contractList = contractList = self.getContractList(event.getData()) unSubList = [] for contNo in contractList: if contNo not in self._quoteOberverDict: continue #该合约没有订阅 stDict = self._quoteOberverDict[contNo] if strategyId not in stDict: continue #该策略没有订阅 stDict.pop(strategyId) #已经没有人订阅了,退订吧 if len(stDict) <= 0: unSubList.append(contNo) if len(unSubList) > 0: event.setData(unSubList) self._pyApi.reqUnsubQuote(event) def getContractList(self, contList): contractList = [] for subContNo in contList: if subContNo in self._qteModel._contractData: contractList.append(subContNo) continue # 根据品种获取该品种的所有合约 for contractNo in list(self._qteModel._contractData.keys()): if subContNo in contractNo: contractList.append(contractNo) return contractList # def _reqTimebucket(self, event): # '''查询时间模板''' # self._pyApi.reqTimebucket(event) def _reqSubHisquote(self, event): '''订阅历史行情''' data = event.getData() if data['NeedNotice'] == EEQU_NOTICE_NOTNEED: self._pyApi.reqSubHisquote(event) return strategyId = event.getStrategyId() key = (data['ContractNo'], data['KLineType'], data['KLineSlice']) if key not in self._hisKLineOberverDict: self._hisKLineOberverDict[key] = {} self._hisKLineOberverDict[key].update({strategyId: True}) self._pyApi.reqSubHisquote(event) def _reqUnsubHisquote(self, event): '''退订历史行情''' strategyId = event.getStrategyId() data = event.getData() key = (data['ContractNo'], data['KLineType'], data['KLineSlice']) if key not in self._hisKLineOberverDict or strategyId not in self._hisKLineOberverDict[ key]: return stDict = self._hisKLineOberverDict[key] stDict.pop(strategyId) def _reqKLineStrategySwitch(self, event): '''切换策略图''' self._pyApi.reqKLineStrategySwitch(event) def _reqKLineDataResult(self, event): '''推送回测K线数据''' self._pyApi.reqKLineDataResult(event) def _reqKLineDataResultNotice(self, event): '''更新实盘K线数据''' self._pyApi.reqKLineDataResultNotice(event) def _reqAddKLineSeriesInfo(self, event): '''增加指标数据''' self._pyApi.addSeries(event) def _reqKLineSeriesResult(self, event): '''推送回测指标数据''' self._pyApi.sendSeries(event) def _reqAddKLineSignalInfo(self, event): '''增加信号数据''' self._pyApi.addSignal(event) def _reqKLineSignalResult(self, event): '''推送回测信号数据''' self._pyApi.sendSignal(event) def _reqStrategyDataUpdateNotice(self, event): '''刷新指标、信号通知''' self._pyApi.reqStrategyDataUpdateNotice(event) def _reportResponse(self, event): # print(" engine 进程,收到策略进程的report 结果,并向ui传递") # print(event.getData()) self._eg2uiQueue.put(event) def _checkResponse(self, event): #print(" engine 进程,收到策略进程的检查结果,并向ui传递") self._eg2uiQueue.put(event) def _monitorResponse(self, event): self._eg2uiQueue.put(event) ################################交易请求######################### def _reqUserInfo(self, event): self._pyApi.reqQryUserInfo(event) def _reqOrder(self, event): self._pyApi.reqQryOrder(event) def _reqMatch(self, event): self._pyApi.reqQryMatch(event) def _reqPosition(self, event): self._pyApi.reqQryPosition(event) def _reqMoney(self, event): self._pyApi.reqQryMoney(event) def _sendOrder(self, event): # 委托下单,发送委托单 self._pyApi.reqInsertOrder(event) self._engineOrderModel.updateLocalOrder(event) def _deleteOrder(self, event): # 委托撤单 self._pyApi.reqCancelOrder(event) def _modifyOrder(self, event): # 委托改单 self._pyApi.reqModifyOrder(event) def _sendKLineData(self, event): '''推送K线数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINEDATA: self._pyApi.sendKLineData(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINEDATA: self._pyApi.sendKLineData(event, 'U') def _addSeries(self, event): '''增加指标线''' self._pyApi.addSeries(event) def _sendKLineSeries(self, event): '''推送指标数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'U') def _addSignal(self, event): '''增加信号线''' self._pyApi.addSignal(event) def _sendKLineSignal(self, event): '''推送信号数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'U') # 停止当前策略 def _onStrategyQuit(self, event): # prevent other threads put data in the queue # make sure quit event is the last strategyId = event.getStrategyId() self.logger.info(f"策略{strategyId}收到停止信号") if strategyId not in self._eg2stQueueDict or self._isEffective[ strategyId] is False: return self._isEffective[strategyId] = False # to solve broken pip error eg2stQueue = self._eg2stQueueDict[strategyId] eg2stQueue.put(event) # 当策略退出成功时 def _cleanStrategyInfo(self, strategyId): self._isEffective[strategyId] = False self._isSt2EngineDataEffective[strategyId] = False # 清除即时行情数据观察者 for k, v in self._quoteOberverDict.items(): if strategyId in v: v.pop(strategyId) # 策略停止,通知9.5清理数据 apiEvent = Event({'StrategyId': strategyId, 'Data': EEQU_STATE_STOP}) self._pyApi.reqKLineStrategyStateNotice(apiEvent) # 队列里面不会有其他事件 def _onStrategyQuitCom(self, event): self.sendEvent2UI(event) self._cleanStrategyInfo(event.getStrategyId()) self._strategyMgr.quitStrategy(event) # 启动当前策略 def _onStrategyResume(self, event): strategyId = event.getStrategyId() if strategyId in self._eg2stQueueDict and strategyId in self._isEffective and self._isEffective[ strategyId]: self.logger.info("策略 %d 已经存在" % event.getStrategyId()) return self._strategyMgr.restartStrategy(self._loadStrategy, event) # 当量化退出时,发事件给所有的策略 def _onEquantExit(self, event): if self._strategyMgr.isAllStrategyQuit(): self.saveStrategyContext2File() else: self._sendEvent2AllStrategy(event) # 某个策略退出成功,当量化整个退出时 def _singleStrategyExitComEquantExit(self, event): self._cleanStrategyInfo(event.getStrategyId()) self._strategyMgr.singleStrategyExitComEquantExit(event) if self._strategyMgr.isAllStrategyQuit(): self.saveStrategyContext2File() def _onStrategyRemove(self, event): strategyId = event.getStrategyId() # 还在正常运行 if strategyId in self._isEffective and self._isEffective[strategyId]: self._isEffective[strategyId] = False self._sendEvent2StrategyForce(strategyId, event) # 停止 elif self._strategyMgr.getStrategyState(strategyId) == ST_STATUS_QUIT: self._strategyMgr.removeQuitedStrategy(event) # 异常状态 elif self._strategyMgr.getStrategyState( strategyId) == ST_STATUS_EXCEPTION: self._strategyMgr.removeExceptionStrategy(event) def _onStrategyRemoveCom(self, event): self.sendEvent2UI(event) self._cleanStrategyInfo(event.getStrategyId()) self._strategyMgr.removeRunningStrategy(event) def _switchStrategy(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) def _restartStrategyWhenParamsChanged(self, event): strategyId = event.getStrategyId() if strategyId in self._eg2stQueueDict and strategyId in self._isEffective and self._isEffective[ strategyId]: self._isEffective[strategyId] = False self._isSt2EngineDataEffective[strategyId] = False self._cleanStrategyInfo(strategyId) self._strategyMgr.destroyProcessByStrategyId(strategyId) allConfig = copy.deepcopy( self._strategyMgr.getStrategyAttribute(strategyId)["Config"]) allConfig["Params"] = event.getData()["Config"]["Params"] self._strategyMgr.getStrategyAttribute( strategyId)['Config'] = allConfig loadEvent = Event({ "EventCode": EV_UI2EG_LOADSTRATEGY, "StragetgyId": strategyId, "Data": { "Path": self._strategyMgr.getStrategyAttribute(strategyId)["Path"], "Args": allConfig, "NoInitialize": True } }) self._loadStrategy(loadEvent, strategyId) def saveStrategyContext2File(self): self.logger.debug("保存到文件") jsonFile = open('config/StrategyContext.json', 'w', encoding='utf-8') result = {} result["StrategyConfig"] = self._strategyMgr.getStrategyConfig() result["MaxStrategyId"] = self._maxStrategyId result["StrategyOrder"] = self._engineOrderModel.getData() json.dump(result, jsonFile, ensure_ascii=False, indent=4) for child in multiprocessing.active_children(): try: child.terminate() child.join(timeout=0.5) except Exception as e: pass self.logger.debug("engine和各策略完整退出") def sendErrorMsg(self, errorCode, errorText): event = Event({ "EventCode": EV_EG2UI_CHECK_RESULT, "StrategyId": 0, "Data": { "ErrorCode": errorCode, "ErrorText": errorText, } }) self._eg2uiQueue.put(event) def _clearQueue(self, someQueue): try: while True: someQueue.get_nowait() except queue.Empty: pass def _handleEngineExceptionCausedByStrategy(self, strategyId): self._cleanStrategyInfo(strategyId) self._strategyMgr._strategyInfo[strategyId][ 'StrategyState'] = ST_STATUS_EXCEPTION self._strategyMgr.destroyProcessByStrategyId(strategyId) quitEvent = Event({ "EventCode": EV_EG2UI_STRATEGY_STATUS, "StrategyId": strategyId, "Data": { "Status": ST_STATUS_EXCEPTION, } }) self._eg2uiQueue.put(quitEvent) def _syncStrategyConfig(self, event): self._strategyMgr.syncStrategyConfig(event) def sendEvent2UI(self, event): self._eg2uiQueue.put(event)
class StrategyEngine(object): '''策略引擎''' def __init__(self, logger, eg2uiQueue, ui2egQueue): self.logger = logger # Engine->Ui, 包括资金,权益等 self._eg2uiQueue = eg2uiQueue # Ui->Engine, 包括策略加载等 self._ui2egQueue = ui2egQueue def _initialize(self): '''进程中初始化函数''' self.logger.info('Initialize strategy engine!') # 数据模型 self._dataModel = DataModel(self.logger) self._qteModel = self._dataModel.getQuoteModel() self._hisModel = self._dataModel.getHisQuoteModel() self._trdModel = self._dataModel.getTradeModel() # api回调函数 self._regApiCallback() # 策略发送函数 self._regMainWorkFunc() # Api->Engine, 品种、行情、K线、交易等 self._api2egQueue = queue.Queue() # Strategy->Engine, 初始化、行情、K线、交易等 self._st2egQueue = Queue() # 创建主处理线程, 从api和策略进程收数据处理 self._startMainThread() # 创建_pyApi对象 self._pyApi = PyAPI(self.logger, self._api2egQueue) # 策略编号,自增 self._maxStrategyId = 1 # 创建策略管理器 self._strategyMgr = StartegyManager(self.logger, self._st2egQueue) # 策略进程队列列表 self._eg2stQueueDict = {} #{strategy_id, queue} self._isEffective = {} # 即时行情订阅列表 self._contStrategyDict = { } #{'contractNo' : [strategyId1, strategyId2...]} # 历史K线订阅列表 self._hisContStrategyDict = { } #{'contractNo' : [strategyId1, strategyId2...]} # 退出策略,整个量化不退出时,在内存中保存策略的配置等信息。 # 需要注意的是,退出策略时,配置信息需要也需要写入到量化退出的数据结构中。 self._onStrategyQuitData = {} # 量化退出时,在文件中保存策略的配置信息 self._onEquantExitData = {} # # 恢复上次推出时保存的结构 # self._resumeStrategy() self.logger.debug('Initialize strategy engine ok!') # def _resumeStrategy(self): # if not os.path.exists('config/StrategyContext.json'): # return # with open("config/StrategyContext.json", 'r') as resumeFile: # pythonDict = json.load(resumeFile) # for k,v in pythonDict.items(): # if k == "MaxStrategyId": # self._maxStrategyId = int(v) # else: # strategyId = int(k) # revent = Event({ # "EventCode": EV_EG2UI_LOADSTRATEGY_RESPONSE, # "StrategyId": strategyId, # "ErrorCode": 0, # "ErrorText": "", # "Data": { # "StrategyId": strategyId, # "StrategyName": v["StrategyName"], # "StrategyState": ST_STATUS_QUIT, # "Config": v["Config"], # } # }) # curStragegyInfo = { # "Path": v["Path"], # "Config": v["Config"], # "StrategyName": v["StrategyName"] # } # self._onStrategyQuitData[strategyId] = curStragegyInfo # self._onEquantExitData[strategyId] = curStragegyInfo # self._eg2uiQueue.put(revent) def _regApiCallback(self): self._apiCallbackDict = { EEQU_SRVEVENT_CONNECT: self._onApiConnect, EEQU_SRVEVENT_DISCONNECT: self._onApiDisconnect, EEQU_SRVEVENT_EXCHANGE: self._onApiExchange, EEQU_SRVEVENT_COMMODITY: self._onApiCommodity, EEQU_SRVEVENT_CONTRACT: self._onApiContract, EEQU_SRVEVENT_TIMEBUCKET: self._onApiTimeBucket, EEQU_SRVEVENT_QUOTESNAP: self._onApiSnapshot, EEQU_SRVEVENT_QUOTESNAPLV2: self._onApiDepthQuote, EEQU_SRVEVENT_HISQUOTEDATA: self._onApiKlinedataRsp, EEQU_SRVEVENT_HISQUOTENOTICE: self._onApiKlinedataNotice, EEQU_SRVEVENT_TRADE_LOGINQRY: self._onApiLoginInfo, EEQU_SRVEVENT_TRADE_USERQRY: self._onApiUserInfo, EEQU_SRVEVENT_TRADE_LOGINNOTICE: self._onApiLoginInfo, EEQU_SRVEVENT_TRADE_ORDERQRY: self._onApiOrderDataQry, EEQU_SRVEVENT_TRADE_ORDER: self._onApiOrderData, EEQU_SRVEVENT_TRADE_MATCHQRY: self._onApiMatchDataQry, EEQU_SRVEVENT_TRADE_MATCH: self._onApiMatchData, EEQU_SRVEVENT_TRADE_POSITQRY: self._onApiPosDataQry, EEQU_SRVEVENT_TRADE_POSITION: self._onApiPosData, EEQU_SRVEVENT_TRADE_FUNDQRY: self._onApiMoney, } def _regMainWorkFunc(self): self._mainWorkFuncDict = { EV_ST2EG_EXCHANGE_REQ: self._onExchange, EV_ST2EG_COMMODITY_REQ: self._reqCommodity, EV_ST2EG_SUB_QUOTE: self._reqSubQuote, EV_ST2EG_UNSUB_QUOTE: self._reqUnsubQuote, EV_ST2EG_SUB_HISQUOTE: self._reqSubHisquote, EV_ST2EG_UNSUB_HISQUOTE: self._reqUnsubHisquote, EV_ST2EG_SWITCH_STRATEGY: self._reqKLineStrategySwitch, # EV_ST2EG_NOTICE_KLINEDATA: self._sendKLineData, EV_ST2EG_UPDATE_KLINEDATA: self._sendKLineData, # k line series EV_ST2EG_ADD_KLINESERIES: self._addSeries, EV_ST2EG_NOTICE_KLINESERIES: self._sendKLineSeries, EV_ST2EG_UPDATE_KLINESERIES: self._sendKLineSeries, # k line signal EV_ST2EG_ADD_KLINESIGNAL: self._addSignal, EV_ST2EG_NOTICE_KLINESIGNAL: self._sendKLineSignal, EV_ST2EG_UPDATE_KLINESIGNAL: self._sendKLineSignal, # 暂停、恢复、与退出 EV_UI2EG_STRATEGY_QUIT: self._onStrategyQuit, EV_UI2EG_STRATEGY_RESUME: self._onStrategyResume, EV_UI2EG_EQUANT_EXIT: self._onEquantExit, EV_UI2EG_STRATEGY_FIGURE: self._switchStrategy, EV_ST2EG_UPDATE_STRATEGYDATA: self._reqStrategyDataUpdateNotice, EV_EG2UI_REPORT_RESPONSE: self._reportResponse, EV_EG2UI_CHECK_RESULT: self._checkResponse, EV_EG2ST_MONITOR_INFO: self._monitorResponse, # load strategy EV_EG2UI_LOADSTRATEGY_RESPONSE: self._loadStrategyResponse, EV_EG2UI_STRATEGY_STATUS: self._onStrategyStatus, EV_ST2EG_STRATEGYTRADEINFO: self._reqTradeInfo, EV_ST2EG_ACTUAL_ORDER: self._sendOrder, EV_ST2EG_ACTUAL_CANCEL_ORDER: self._deleteOrder, EV_ST2EG_ACTUAL_MODIFY_ORDER: self._modifyOrder, } def run(self): # 在当前进程中初始化 self._initialize() while True: self._handleUIData() time.sleep(0.1) def _sendEvent2Strategy(self, strategyId, event): if strategyId not in self._eg2stQueueDict or not self._isEffective[ strategyId]: return if event is None: return eg2stQueue = self._eg2stQueueDict[strategyId] eg2stQueue.put(event) def _sendEvent2AllStrategy(self, event): for id in self._eg2stQueueDict: self._sendEvent2Strategy(id, event) # self._eg2stQueueDict[id].put(event) def _dispathQuote2Strategy(self, code, apiEvent): '''分发即时行情''' apiData = apiEvent.getData() contractNo = apiEvent.getContractNo() contStList = self._contStrategyDict[contractNo] data = apiData[:] msg = { 'EventSrc': EEQU_EVSRC_ENGINE, 'EventCode': code, 'StrategyId': 0, 'SessionId': 0, 'UserNo': '', 'ContractNo': contractNo, 'Data': data } event = Event(msg) for id in contStList: self._sendEvent2Strategy(id, event) # //////////////////////UI事件处理函数///////////////////// def _handleUIData(self): event = self._ui2egQueue.get() code = event.getEventCode() if code == EV_UI2EG_LOADSTRATEGY: # 加载策略事件 self._loadStrategy(event) elif code == EV_UI2EG_REPORT: self._noticeStrategyReport(event) elif code == EV_UI2EG_STRATEGY_QUIT: self._onStrategyQuit(event) elif code == EV_UI2EG_STRATEGY_RESUME: self._onStrategyResume(event) elif code == EV_UI2EG_EQUANT_EXIT: self._onEquantExit(event) elif code == EV_UI2EG_STRATEGY_REMOVE: self._onStrategyRemove(event) elif code == EV_UI2EG_STRATEGY_FIGURE: self._switchStrategy(event) # def _noticeStrategyReport(self, event): self._strategyMgr.sendEvent2Strategy(event.getStrategyId(), event) def _getStrategyId(self): id = self._maxStrategyId self._maxStrategyId += 1 return id def _loadStrategy(self, event, strategyId=None): id = self._getStrategyId() if strategyId is None else strategyId eg2stQueue = Queue(2000) self._eg2stQueueDict[id] = eg2stQueue self._strategyMgr.create(id, eg2stQueue, self._eg2uiQueue, self._st2egQueue, event) # broken pip error 修复 self._isEffective[id] = True # ================= self._strategyMgr.sendEvent2Strategy(id, event) def _loadStrategyResponse(self, event): self._eg2uiQueue.put(event) def _onStrategyStatus(self, event): if event.getData()["Status"] == ST_STATUS_QUIT: curStragegyInfo = { "Path": event.getData()["Path"], "Config": event.getData()["Config"], "StrategyName": event.getData()["StrategyName"] } # 暂存当前策略的配置, self._onStrategyQuitData[event.getStrategyId()] = curStragegyInfo self._onEquantExitData[event.getStrategyId()] = curStragegyInfo self.destroyProcess(event.getData()["Pid"]) self._eg2uiQueue.put(event) elif event.getData()["Status"] == EV_UI2EG_EQUANT_EXIT: curStragegyInfo = { "Path": event.getData()["Path"], "Config": event.getData()["Config"], "StrategyName": event.getData()["StrategyName"] } self._onEquantExitData[event.getStrategyId()] = curStragegyInfo isAllStrategyExit = True for strategyId, _ in self._eg2stQueueDict.items(): if strategyId not in self._onEquantExitData: isAllStrategyExit = False # print("is all strategy exit: ", isAllStrategyExit) if isAllStrategyExit: self.saveStrategyContext2File() elif event.getData()["Status"] == ST_STATUS_CONTINUES: self._eg2uiQueue.put(event) elif event.getData()["Status"] == ST_STATUS_REMOVE: self._onEquantExitData[event.getStrategyId()] = None self._eg2uiQueue.put(event) self.destroyProcess(event.getData()["Pid"]) # ////////////////api回调及策略请求事件处理////////////////// def _handleApiData(self): try: apiEvent = self._api2egQueue.get_nowait() code = apiEvent.getEventCode() # print("c api code =", code) if code not in self._apiCallbackDict: return self._apiCallbackDict[code](apiEvent) self.maxContinuousIdleTimes = 0 except queue.Empty as e: self.maxContinuousIdleTimes += 1 pass def _handleStData(self): try: event = self._st2egQueue.get_nowait() code = event.getEventCode() if code not in self._mainWorkFuncDict: self.logger.debug( 'Event %d not register in _mainWorkFuncDict' % code) # print("未处理的event code =",code) return self._mainWorkFuncDict[code](event) self.maxContinuousIdleTimes = 0 except queue.Empty as e: self.maxContinuousIdleTimes += 1 pass maxContinuousIdleTimes = 0 def _mainThreadFunc(self): while True: self._handleApiData() self._handleStData() if self.maxContinuousIdleTimes >= 1000: time.sleep(0.1) self.maxContinuousIdleTimes %= 1000 def _startMainThread(self): '''从api队列及策略队列中接收数据''' self._apiThreadH = Thread(target=self._mainThreadFunc) self._apiThreadH.start() def _moneyThreadFunc(self): while True: eventList = self._trdModel.getMoneyEvent() #查询所有账户下的资金 for event in eventList: self._reqMoney(event) time.sleep(60) def _createMoneyTimer(self): '''资金查询线程''' self._moneyThreadH = Thread(target=self._moneyThreadFunc) self._moneyThreadH.start() #////////////////api回调事件////////////////////////////// def _onApiConnect(self, apiEvent): self._pyApi.reqExchange(Event({'StrategyId': 0, 'Data': ''})) def _onApiDisconnect(self, apiEvent): ''' 断连事件:区分与9.5/交易/即时行情/历史行情 1. 与9.5断连: a. 停止所有策略(包括回测与运行) b. 通知界面断连状态 c. 设置引擎状态为与9.5断连 d. 清理所有数据,重置数据状态 2. 与即时行情断连 a. 停止所有策略(运行) b 通知界面断连状态 c. 设置引擎状态为与即时行情断连 d. 清理所有即时行情数据 3. 与历史行情断连 a. 停止所有策略(包括回测和运行) b. 通知界面断连状态 c. 设置引擎状态为与历史行情断连 d. 清理所有历史K线数据 4. 与交易断连 a. 停止所有策略(运行) b. 通知界面断连状态 c. 设置引擎状态为与交易断开链接 d. 清理所有交易数据 说明:策略停止后,所有相关数据清理 ''' # def _onApiExchange(self, apiEvent): self._qteModel.updateExchange(apiEvent) self._sendEvent2Strategy(apiEvent.getStrategyId(), apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqCommodity(Event({'StrategyId': 0, 'Data': ''})) def _onApiCommodity(self, apiEvent): self._qteModel.updateCommodity(apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqContract(Event({'StrategyId': 0, 'Data': ''})) # 发送商品交易时间模板请求 dataList = apiEvent.getData() for dataDict in dataList: event = Event({ 'EventCode': EV_ST2EG_TIMEBUCKET_REQ, 'StrategyId': apiEvent.getStrategyId(), 'Data': dataDict['CommodityNo'], }) self._pyApi.reqTimebucket(event) def _onApiContract(self, apiEvent): self._qteModel.updateContract(apiEvent) self._eg2uiQueue.put(apiEvent) if apiEvent.isChainEnd(): self._pyApi.reqQryLoginInfo(Event({'StrategyId': 0, 'Data': ''})) def _onApiTimeBucket(self, apiEvent): self._qteModel.updateTimeBucket(apiEvent) def _onApiSnapshot(self, apiEvent): self._qteModel.updateLv1(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_SNAPSHOT_NOTICE, apiEvent) def _onApiDepthQuote(self, apiEvent): self._qteModel.updateLv2(apiEvent) self._dispathQuote2Strategy(EV_EG2ST_DEPTH_NOTICE, apiEvent) def _onApiKlinedataRsp(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_RSP) def _onApiKlinedataNotice(self, apiEvent): self._onApiKlinedata(apiEvent, EV_EG2ST_HISQUOTE_NOTICE) def _onApiKlinedata(self, apiEvent, code): self._hisModel.updateKline(apiEvent) strategyId = apiEvent.getStrategyId() # 策略号为0,认为是推送数据 apiData = apiEvent.getData() data = apiData[:] event = Event({ 'StrategyId': strategyId, 'EventCode': code, 'ChainEnd': apiEvent.getChain(), 'ContractNo': apiEvent.getContractNo(), 'KLineType': apiEvent.getKLineType(), 'KLineSlice': apiEvent.getKLineSlice(), 'Data': data }) if strategyId > 0: self._sendEvent2Strategy(strategyId, event) return # 推送数据,分发 key = (apiEvent.getContractNo(), apiEvent.getKLineType(), apiEvent.getKLineSlice()) if key not in self._hisContStrategyDict: return stDict = self._hisContStrategyDict[key] for key in stDict: event.setStrategyId(key) self._sendEvent2Strategy(key, event) # 用户登录信息 def _onApiLoginInfo(self, apiEvent): self._trdModel.updateLoginInfo(apiEvent) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_LOGIN) self._reqUserInfo(Event({'StrategyId': 0, 'Data': ''})) # 账户信息 def _onApiUserInfo(self, apiEvent): self._trdModel.updateUserInfo(apiEvent) self._eg2uiQueue.put(apiEvent) # print("++++++ 账户信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_USER) # 查询所有账户下委托信息 eventList = self._trdModel.getOrderEvent() for event in eventList: # print("====== 查询所有账户下委托信息 ======", event.getData()) self._reqOrder(event) def _onApiOrderDataQry(self, apiEvent): self._trdModel.updateOrderData(apiEvent) # print("++++++ 订单信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_ORDER) # 查询所有账户下成交信息 eventList = self._trdModel.getMatchEvent() for event in eventList: self._reqMatch(event) def _onApiOrderData(self, apiEvent): # 订单信息 self._trdModel.updateOrderData(apiEvent) # print("++++++ 订单信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 strategyId = apiEvent.getStrategyId() if strategyId > 0: self._sendEvent2Strategy(strategyId, apiEvent) else: self._sendEvent2AllStrategy(apiEvent) def _onApiMatchDataQry(self, apiEvent): self._trdModel.updateMatchData(apiEvent) # print("++++++ 成交信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_MATCH) #查询所有账户下成交信息 eventList = self._trdModel.getPositionEvent() for event in eventList: self._reqPosition(event) def _onApiMatchData(self, apiEvent): # 成交信息 self._trdModel.updateMatchData(apiEvent) # print("++++++ 成交信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiPosDataQry(self, apiEvent): self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 查询 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) if not apiEvent.isChainEnd(): return if not apiEvent.isSucceed(): return self._trdModel.setStatus(TM_STATUS_POSITION) # 交易基础数据查询完成,定时查询资金 self._createMoneyTimer() def _onApiPosData(self, apiEvent): # 持仓信息 self._trdModel.updatePosData(apiEvent) # print("++++++ 持仓信息 引擎 变化 ++++++", apiEvent.getData()) # TODO: 分块传递 self._sendEvent2AllStrategy(apiEvent) def _onApiMoney(self, apiEvent): # 资金信息 self._trdModel.updateMoney(apiEvent) # print("++++++ 资金信息 引擎 ++++++", apiEvent.getData()) self._sendEvent2AllStrategy(apiEvent) def _reqTradeInfo(self, event): ''' 查询账户信息,如果用户未登录,则Data返回为空 ''' stragetyId = event.getStrategyId() if len(self._trdModel._loginInfo) == 0: trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': '', }) self._sendEvent2Strategy(stragetyId, trdEvent) return 0 data = { 'loginInfo': {}, # 登录账号信息 'userInfo': {}, # 资金账号信息 } # 登录账号信息 loginInfoDict = {} for userNo, tLoginModel in self._trdModel._loginInfo.items(): loginInfoDict[userNo] = tLoginModel.copyLoginInfoMetaData() data['loginInfo'] = loginInfoDict # 资金账号信息 userInfoDict = {} for userNo, tUserInfoModel in self._trdModel._userInfo.items(): userInfoDict[userNo] = tUserInfoModel.formatUserInfo() data['userInfo'] = userInfoDict stragetyId = event.getStrategyId() trdEvent = Event({ 'EventCode': EV_EG2ST_TRADEINFO_RSP, 'StrategyId': stragetyId, 'Data': data, }) self._sendEvent2Strategy(stragetyId, trdEvent) #///////////////策略进程事件////////////////////////////// def _addSubscribe(self, contractNo, strategyId): stDict = self._contStrategyDict[contractNo] # 重复订阅 if strategyId in stDict: return stDict[strategyId] = None def _sendQuote(self, contractNo, strategyId): event = self._qteModel.getQuoteEvent(contractNo, strategyId) self._sendEvent2Strategy(strategyId, event) def _onExchange(self, event): '''查询交易所信息''' revent = self._qteModel.getExchange() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqCommodity(self, event): '''查询品种信息''' revent = self._qteModel.getCommodity() self._sendEvent2Strategy(event.getStrategyId(), revent) def _reqSubQuote(self, event): '''订阅即时行情''' contractList = event.getData() strategyId = event.getStrategyId() subList = [] for contractNo in contractList: if contractNo not in self._contStrategyDict: subList.append(contractNo) self._contStrategyDict[contractNo] = {strategyId: None} else: if strategyId in self._contStrategyDict[contractNo]: continue #重复订阅,不做任何处理 self._contStrategyDict[contractNo][strategyId] = None self._sendQuote(contractNo, strategyId) if len(subList) > 0: event.setData(subList) self._pyApi.reqSubQuote(event) def _reqUnsubQuote(self, event): '''退订即时行情''' strategyId = event.getStrategyId() contractList = event.getData() unSubList = [] for contNo in contractList: if contNo not in self._contStrategyDict: continue #该合约没有订阅 stDict = self._contStrategyDict[contNo] if strategyId not in stDict: continue #该策略没有订阅 stDict.pop(strategyId) #已经没有人订阅了,退订吧 if len(stDict) <= 0: unSubList.append(contNo) if len(unSubList) > 0: event.setData(unSubList) self._pyApi.reqUnsubQuote(event) # def _reqTimebucket(self, event): # '''查询时间模板''' # self._pyApi.reqTimebucket(event) def _reqSubHisquote(self, event): '''订阅历史行情''' data = event.getData() if data['NeedNotice'] == EEQU_NOTICE_NOTNEED: self._pyApi.reqSubHisquote(event) return strategyId = event.getStrategyId() key = (data['ContractNo'], data['KLineType'], data['KLineSlice']) if key not in self._hisContStrategyDict: self._hisContStrategyDict[key] = {} self._hisContStrategyDict[key].update({strategyId: True}) self._pyApi.reqSubHisquote(event) def _reqUnsubHisquote(self, event): '''退订历史行情''' strategyId = event.getStrategyId() data = event.getData() key = (data['ContractNo'], data['KLineType'], data['KLineSlice']) if key not in self._hisContStrategyDict or strategyId not in self._hisContStrategyDict[ key]: return stDict = self._hisContStrategyDict[key] stDict.pop(strategyId) def _reqKLineStrategySwitch(self, event): '''切换策略图''' self._pyApi.reqKLineStrategySwitch(event) def _reqKLineDataResult(self, event): '''推送回测K线数据''' self._pyApi.reqKLineDataResult(event) def _reqKLineDataResultNotice(self, event): '''更新实盘K线数据''' self._pyApi.reqKLineDataResultNotice(event) def _reqAddKLineSeriesInfo(self, event): '''增加指标数据''' self._pyApi.addSeries(event) def _reqKLineSeriesResult(self, event): '''推送回测指标数据''' self._pyApi.sendSeries(event) def _reqAddKLineSignalInfo(self, event): '''增加信号数据''' self._pyApi.addSignal(event) def _reqKLineSignalResult(self, event): '''推送回测信号数据''' self._pyApi.sendSignal(event) def _reqStrategyDataUpdateNotice(self, event): '''刷新指标、信号通知''' self._pyApi.reqStrategyDataUpdateNotice(event) def _reportResponse(self, event): # print(" engine 进程,收到策略进程的report 结果,并向ui传递") # print(event.getData()) self._eg2uiQueue.put(event) def _checkResponse(self, event): #print(" engine 进程,收到策略进程的检查结果,并向ui传递") self._eg2uiQueue.put(event) def _monitorResponse(self, event): self._eg2uiQueue.put(event) ################################交易请求######################### def _reqUserInfo(self, event): self._pyApi.reqQryUserInfo(event) def _reqOrder(self, event): self._pyApi.reqQryOrder(event) def _reqMatch(self, event): self._pyApi.reqQryMatch(event) def _reqPosition(self, event): self._pyApi.reqQryPosition(event) def _reqMoney(self, event): self._pyApi.reqQryMoney(event) def _sendOrder(self, event): # 委托下单,发送委托单 self._pyApi.reqInsertOrder(event) def _deleteOrder(self, event): # 委托撤单 self._pyApi.reqCancelOrder(event) def _modifyOrder(self, event): # 委托改单 self._pyApi.reqModifyOrder(event) def _sendKLineData(self, event): '''推送K线数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINEDATA: self._pyApi.sendKLineData(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINEDATA: self._pyApi.sendKLineData(event, 'U') def _addSeries(self, event): '''增加指标线''' self._pyApi.addSeries(event) def _sendKLineSeries(self, event): '''推送指标数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESERIES: self._pyApi.sendKLineSeries(event, 'U') def _addSignal(self, event): '''增加信号线''' self._pyApi.addSignal(event) def _sendKLineSignal(self, event): '''推送信号数据''' if event.getEventCode() == EV_ST2EG_NOTICE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'N') elif event.getEventCode() == EV_ST2EG_UPDATE_KLINESIGNAL: self._pyApi.sendKLineSignal(event, 'U') # 停止当前策略 def _onStrategyQuit(self, event): # prevent other threads put data in the queue # make sure quit event is the last strategyId = event.getStrategyId() if strategyId not in self._eg2stQueueDict or self._isEffective[ strategyId] is False: return self._isEffective[event.getStrategyId()] = False # to solve broken pip error eg2stQueue = self._eg2stQueueDict[strategyId] eg2stQueue.put(event) #策略停止,通知9.5清理数据 apiEvent = Event({'StrategyId': strategyId, 'Data': EEQU_STATE_STOP}) self._pyApi.reqKLineStrategyStateNotice(apiEvent) # 启动当前策略 def _onStrategyResume(self, event): strategyId = event.getStrategyId() if strategyId in self._eg2stQueueDict and strategyId in self._isEffective and self._isEffective[ strategyId]: self.logger.info("策略 %d 已经存在" % event.getStrategyId()) return path = self._onStrategyQuitData[event.getStrategyId()]["Path"] config = self._onStrategyQuitData[event.getStrategyId()]["Config"] loadStrategyEvent = Event({ 'EventSrc': EEQU_EVSRC_UI, 'EventCode': EV_UI2EG_LOADSTRATEGY, 'SessionId': None, 'StrategyId': 0, 'UserNo': '', 'Data': { 'Path': path, 'Args': config, } }) self._loadStrategy(loadStrategyEvent, strategyId=event.getStrategyId()) # 删除信息 self._onStrategyQuitData[event.getStrategyId()] = None # self._onEquantExitData[event.getStrategyId()] = None # 当量化退出时,发事件给所有的策略 def _onEquantExit(self, event): # if all strategies quit if len(self._onEquantExitData) >= len(self._eg2stQueueDict): self.saveStrategyContext2File() else: self._sendEvent2AllStrategy(event) for id in self._eg2stQueueDict: apiEvent = Event({'StrategyId': id, 'Data': EEQU_STATE_STOP}) self._pyApi.reqKLineStrategyStateNotice(apiEvent) def _onStrategyRemove(self, event): strategyId = event.getStrategyId() # 如果已经停止 if strategyId in self._onStrategyQuitData and self._onStrategyQuitData[ strategyId] is not None: self._onEquantExitData[event.getStrategyId()] = None # 如果还在运行中 else: self._isEffective[event.getStrategyId()] = False eg2stQueue = self._eg2stQueueDict[event.getStrategyId()] eg2stQueue.put(event) def _switchStrategy(self, event): self._sendEvent2Strategy(event.getStrategyId(), event) def saveStrategyContext2File(self): jsonFile = open('config/StrategyContext.json', 'w', encoding='utf-8') self._onEquantExitData.update({"MaxStrategyId": self._maxStrategyId}) tmpOrderedDict = {} for k, v in self._onEquantExitData.items(): if v is not None: tmpOrderedDict[k] = v tmpOrderedDict = OrderedDict( sorted(tmpOrderedDict.items(), key=lambda obj: str(obj[0]))) json.dump(tmpOrderedDict, jsonFile, ensure_ascii=False, indent=4) for child in multiprocessing.active_children(): child.terminate() child.join() def destroyProcess(self, pid): try: strategyProcess = psutil.Process(pid) strategyProcess.terminate() strategyProcess.wait(timeout=0.1) # print("策略进程已经退出", strategyProcess.name) except (psutil.NoSuchProcess, psutil.AccessDenied) as e: traceback.print_exc() self.logger.info("pid %d exit fail" % pid)