def print(self, description, type=DyLogData.info): if not self._enabled and type != DyLogData.error and type != DyLogData.warning: return event = DyEvent(DyEventType.subLog_ + '_' + str(self._paramGroupNo) + str(self._period)) event.data = DyLogData(description, type) self._outQueue.put(event)
def handle_msg_all(self, msg): if msg['user']['name'] == 'self': event = DyEvent(DyEventType.wxQueryStockStrategy) event.data = msg['content']['data'] self._eventEngine.put(event)
def _updateStockHistDays_Handler(self, event): # unpack codes = event.data # check stop flag firstly if self._isStopped: self._printCount() self._eventEngine.put(DyEvent(DyEventType.stopAck)) return # update one code each time code = sorted(codes)[0] self._updateOneCode(code, codes[code]) # update progress self._progress.update() # delete updated code del codes[code] if not codes: # all codes are are updated self._printCount() self._eventEngine.put(DyEvent(DyEventType.finish)) return # send for next updating event = DyEvent(DyEventType.updateStockHistDays_) event.data = codes self._eventEngine.put(event)
def _histDaysMannualUpdate(self): if self._histDaysMannualUpdateAction.text() == '停止': self._mainEngine._info.print('停止股票(指数)历史日线数据手动更新...', DyLogData.ind) # change UI self._stopRunningMutexAction() event = DyEvent(DyEventType.stopUpdateStockHistDaysReq) self._mainEngine.eventEngine.put(event) else: # 开始手动更新 data = {} if DyStockDataHistDaysManualUpdateDlg(data, self).exec_(): self._mainEngine._info.print('开始股票(指数,基金)历史日线数据手动更新[{0}, {1}]...'.format(data['startDate'], data['endDate']), DyLogData.ind) # change UI self._startRunningMutexAction(self._histDaysMannualUpdateAction) event = DyEvent(DyEventType.updateStockHistDays) event.data = data event.data['codes'] = DyStockCommon.getDyStockCodes(event.data['codes']) # 是否要更新指数的日线数据 if event.data['index']: if event.data['codes'] is None: event.data['codes'] = [] event.data['codes'].extend(list(DyStockCommon.indexes)) self._mainEngine.eventEngine.put(event)
def _newEntrust(self, type, datetime, strategyCls, code, name, price, volume): """ 生成新的委托,并向交易接口发送委托事件 """ # check if there's same code and type of entrust not done for different strategy entrusts = self._curEntrusts.get(code) if entrusts is not None: for entrust in entrusts: if (not entrust.isDone()) and entrust.type == type and entrust.strategyCls != strategyCls: self._info.print('{}: 策略[{}]委托失败({}, {}, {}, 价格={}, 数量={}): 策略[{}]有未完成的委托'.format(self.__class__.__name__, strategyCls.chName, code, name, type, price, volume, entrust.strategyCls.chName), DyLogData.warning) return None # create a new entrust curEntrustCount = self.newCurEntrustCount() entrust = DyStockEntrust(datetime, type, code, name, price, volume) entrust.dyEntrustId = '{0}.{1}_{2}'.format(self.broker, self._curTDay, curEntrustCount) entrust.strategyCls = strategyCls # add into 当日委托 self._curEntrusts.setdefault(code, []) self._curEntrusts[code].append(copy.copy(entrust)) # put buy/sell event eventType = DyEventType.stockBuy if type == DyStockOpType.buy else DyEventType.stockSell event = DyEvent(eventType + self.broker) event.data = copy.copy(entrust) self._eventEngine.put(event) return entrust
def cancel(self, cancelEntrust): """ 取消委托 """ # find corresponding entrust entrusts = self._curEntrusts.get(cancelEntrust.code) if entrusts is None: return False for entrust in entrusts: if entrust.dyEntrustId == cancelEntrust.dyEntrustId: break else: return False if entrust.isDone(): self._info.print('{}: 撤销委托失败: {}'.format(self.__class__.__name__, entrust.__dict__, DyLogData.warning)) return False if entrust.brokerEntrustId is None: self._curWorkingCancelEntrusts.append(entrust) return True # put cancel event event = DyEvent(DyEventType.stockCancel + self.broker) event.data = copy.copy(entrust) self._eventEngine.put(event) return True
def progressSingle(self, percent): if self._progressSingle != percent: self._progressSingle = percent event = DyEvent(DyEventType.progressSingle) event.data = percent self._eventEngine.put(event)
def progressTotal(self, percent): if self._progressTotal != percent: self._progressTotal = percent event = DyEvent(DyEventType.progressTotal) event.data = percent self._eventEngine.put(event)
def _putTickEvent(self, ctaTickDatas): if not ctaTickDatas: return event = DyEvent(DyEventType.stockMarketTicks) event.data = ctaTickDatas self._eventEngine.put(event)
def _updateStrategyDeal(self, deal): """ 向UI推送策略成交事件 """ event = DyEvent(DyEventType.stockStrategyDealsUpdate + deal.strategyCls.name) event.data = [deal] self._eventEngine.put(event)
def handle_msg_all(self, msg): try: if msg['user']['name'] == 'self': event = DyEvent(DyEventType.wxQueryStockStrategy) event.data = msg['content']['data'] self._eventEngine.put(event) except: pass
def _updateStrategyPos(self, strategy): """ 向UI推送策略持仓更新事件 """ # 持仓 event = DyEvent(DyEventType.stockStrategyPosUpdate + strategy.name) event.data = copy.deepcopy(strategy.curPos) self._eventEngine.put(event)
def _updateStrategyEntrust(self, entrust): """ 向UI推送策略委托事件 """ # because only one entrust, no need OrderedDict event = DyEvent(DyEventType.stockStrategyEntrustsUpdate + entrust.strategyCls.name) event.data = {entrust.dyEntrustId: copy.copy(entrust)} self._eventEngine.put(event)
def _startStockCtaStrategyHandler(self, event): """ 启动策略, 创建唯一策略实例 """ strategyCls = event.data['class'] state = event.data['state'] self._info.print('开始启动策略: {0}, 状态: {1},...'.format(strategyCls.chName, state.state), DyLogData.ind) # 是否是唯一策略实例 if strategyCls.name in self._strategies: self._info.print('重复启动策略: {0}'.format(strategyCls.chName), DyLogData.error) return # !!!It's tricky for live trading but not accurate. sleep(1) # sleep so that UI related dynamic windows can be created firstly. # 实例化策略 strategy = strategyCls(self, self._info, state) # 策略开盘前初始化 if not strategy.onOpen(datetime.now().strftime("%Y-%m-%d"), strategy.onOpenCodes()): self._info.print('策略: {0}启动失败'.format(strategyCls.chName), DyLogData.error) return # 启动策略的账户管理 if state.isState(DyStockStrategyState.running): if strategy.broker is not None: # Strategy has configured the broker if not self._startAccountManager(strategyCls): return # 从券商管理类同步策略持仓 self._accountManagers[strategy.broker].syncStrategyPos(strategy) # 获取策略要监控的股票池 monitoredStocks = strategy.onMonitor() # 添加到策略字典 self._strategies[strategyCls.name] = (strategy, DyStockMarketFilter(monitoredStocks)) # 添加到bar聚合字典 if 'bar' in strategyCls.liveMode: if strategyCls.liveMode not in self._barAggs: self._barAggs[strategyCls.liveMode] = DyStockCtaBarAggFast(strategyCls.liveMode, monitoredStocks) else: self._barAggs[strategyCls.liveMode].add(monitoredStocks) # 向股票市场发送监控的股票池 monitoredStocks = monitoredStocks + [DyStockCommon.etf300, DyStockCommon.etf500] # always add ETF300 and ETF500 for 大盘参考。主要原因是历史分笔数据没有指数的,所以只能用ETF替代。 if monitoredStocks: event = DyEvent(DyEventType.stockMarketMonitor) event.data = monitoredStocks self._eventEngine.put(event) # 向UI推送策略的账户相关事件 self._updateStrategyAccount(strategy) self._info.print('策略: {0}启动成功'.format(strategyCls.chName), DyLogData.ind)
def _highLowDistAct(self): data = {} if not DyDateDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'highLowDist' self._mainEngine.eventEngine.put(event)
def putEvent(self, type, data): """ 推送一个事件到事件引擎 @type: 事件类型 @data: 事件数据,一般为dict """ event = DyEvent(type) event.data = data self._eventEngine.put(event)
def _updateStrategyAccount(self, strategy): """ 向UI推送策略的账户相关事件 只有不改变的对象内容可以在多线程之间传递。策略账户相关的对象可能会改变,所以做deepcopy或者copy """ # 持仓 self._updateStrategyPos(strategy) # 委托 event = DyEvent(DyEventType.stockStrategyEntrustsUpdate + strategy.name) event.data = copy.deepcopy(strategy.curEntrusts) self._eventEngine.put(event) # 成交 event = DyEvent(DyEventType.stockStrategyDealsUpdate + strategy.name) event.data = list(strategy.curDeals.values()) # [DyStockDeal] self._eventEngine.put(event)
def _bBandsStats(self): data = {} if not DyStockSelectBBandsStatsDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'bBandsStats' self._mainEngine.eventEngine.put(event)
def _limitUpStatsAct(self): data = {} if not DyDateDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'limitUpStats' self._mainEngine.eventEngine.put(event)
def progressTotal(self, percent): if not self._enabled: return if self._progressTotal != percent: self._progressTotal = percent event = DyEvent(DyEventType.subProgressTotal_ + '_' + str(self._paramGroupNo) + str(self._period)) event.data = percent self._outQueue.put(event)
def _focusAnalysisAct(self): data = {} if not DyDateDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'focusAnalysis' self._mainEngine.eventEngine.put(event)
def _putDealsEvent(self, deals): """ @deals: [deal object] """ # 向引擎推送成交回报 if deals: event = DyEvent(DyEventType.stockOnDeal) event.data = deals self._eventEngine.put(event)
def _jaccardIndexAct(self): data = {} if not DyStockSelectJaccardIndexDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'jaccardIndex' self._mainEngine.eventEngine.put(event)
def _stockHistTicksReqHandler(self, event): code = event.data.code date = event.data.date data = self._getTicks(code, date) # put ack event event = DyEvent(DyEventType.stockHistTicksAck) event.data = DyStockHistTicksAckData(code, date, data) self._eventEngine.put(event)
def _stockOneKeyUpdateHandler(self, event): if self._oneKeyUpdateState is None: # 自动更新日线数据 event = DyEvent(DyEventType.updateStockHistDays) event.data = None self._eventEngine.put(event) self._isStopped = False self._updateDates = None self._oneKeyUpdateState = DyStockDataEngine.State.sWaitingDays
def _stockStrategyPosReqHandler(self, event): strategyCls = event.data if strategyCls.name not in self._strategies: return strategy = self._strategies[strategyCls.name][0] event = DyEvent(DyEventType.stockStrategyPosAck) event.data = strategy.curPos self._eventEngine.put(event)
def _stockStrategyMonitoredCodesReqHandler(self, event): strategyCls = event.data if strategyCls.name not in self._strategies: return filter = self._strategies[strategyCls.name][1] event = DyEvent(DyEventType.stockStrategyMonitoredCodesAck) event.data = filter.codes self._eventEngine.put(event)
def dyStockBackTestingStrategyEngineProcess(outQueue, inQueue, reqData, config=None): """ 股票回测处理实体。每个回测处理实体由一个参数组合和一个回测周期组成。 每个交易日回测结束后向UI推送持仓和成交信息 """ paramGroupNo = reqData.paramGroupNo period = [reqData.tDays[0], reqData.tDays[-1]] if config is not None: DyStockConfig.setConfigForBackTesting(config) # set DB Cache useDbCache = __setDbCache(reqData) # Engines eventEngine = DyDummyEventEngine() info = DySubInfo(paramGroupNo, period, outQueue) dataEngine = DyStockDataEngine(eventEngine, info, False, dbCache=useDbCache) # create stock back testing CTA engine ctaEngine = DyStockBackTestingCtaEngine(eventEngine, info, dataEngine, reqData, dbCache=useDbCache) for tDay in reqData.tDays: try: event = inQueue.get_nowait() except queue.Empty: pass # 回测当日数据 if not ctaEngine.run(tDay): break # 发送当日回测结果数据事件 event = DyEvent(DyEventType.stockStrategyBackTestingAck) event.data = ctaEngine.getCurAckData() outQueue.put(event) # 发送'股票回测策略引擎处理结束'事件 event = DyEvent(DyEventType.stockBackTestingStrategyEngineProcessEnd) event.data[paramGroupNo] = period outQueue.put(event)
def _manualUpdateSectorCodeTableAct(self): data = {'codes': list(DyStockCommon.sectors)} if DyCodeDateDlg('板块代码', data, self).exec_(): self._mainEngine._info.print('开始{0}股票板块代码表更新[{1}, {2}]...'.format(data['codes'], data['startDate'], data['endDate']), DyLogData.ind) # change UI self._startRunningMutexAction(self._manualUpdateSectorCodeTableAction) event = DyEvent(DyEventType.updateStockSectorCodes) event.data = data event.data['sectorCode'] = data['codes'] self._mainEngine.eventEngine.put(event)
def _putStockMarketMonitorEvent(self): """ 向股票市场发送监控持仓的股票 Note: !!!实盘跟回测有不同之处,实盘没有实现@onMonitor接口。回测时,@onMonitor是由CTA Engine调用。实盘则根据券商的持仓信息来监控持仓股票实时信息。 """ if self._curPos: event = DyEvent(DyEventType.stockMarketMonitor) event.data = list(self._curPos) self._eventEngine.put(event) # 新的持仓Filter self._filter = DyStockMarketFilter(list(self._curPos))
def _backTesting(self): strategyCls, param = self._widgetStrategy.getStrategy() if strategyCls is None: return data = {} if not DyStockBackTestingSettingDlg(data).exec_(): return # change UI self._startRunningMutexAction(self._backTestingAction) event = DyEvent(DyEventType.stockStrategyBackTestingReq) event.data = DyStockBackTestingStrategyReqData(strategyCls, [data['startDate'], data['endDate']], data, param) self._mainEngine.eventEngine.put(event)
def _testedStocks(self): isTested = self._testedStocksAction.isChecked() codes = None if isTested: data = {} if DyStockSelectTestedStocksDlg(data).exec_(): codes = data['codes'] else: self._testedStocksAction.setChecked(False) # put event event = DyEvent(DyEventType.stockSelectTestedCodes) event.data = codes self._mainEngine.eventEngine.put(event)
def _insert2Db(self, code, date, data): if self._mongoDbEngine.insertTicks(code, date, data): # insert into DB successfully # count firstly self._inserted2DbCount += 1 self._updateProgress() self._updateWindow() else: # failed into DB # send to Gateway to get ticks again, 2016/7/1 #self._sendTicksReq(code, date, self._progress.totalReqCount) # just use @self._progress.totalReqCount as request count # simualte Ack event and push back to insert into DB again event = DyEvent(DyEventType.stockHistTicksAck) event.data = DyStockHistTicksAckData(code, date, data) self._eventEngine.put(event)
def _updateHistDays(self, startDate, endDate, indicators, isForced=False, codes=None): # get updated codes data info codes = self._getUpdatedCodes(startDate, endDate, indicators, isForced, codes) if codes is None: return # init self._isStopped = False self._updatedCodeCount = 0 self._progress.init(len(codes), 10) self._info.print("开始更新{0}只股票(指数,基金)的历史日线数据...".format(len(codes))) # send for updating event = DyEvent(DyEventType.updateStockHistDays_) event.data = codes self._eventEngine.put(event)
def _indexConsecutiveDayLineStatsAct(self): if self._greenLineStatsAction.isChecked(): greenLine = True self._greenLineStatsAction.setChecked(False) else: greenLine = False self._redLineStatsAction.setChecked(False) data = {} if not DyDateDlg(data).exec_(): return event = DyEvent(DyEventType.plotReq) event.data = data event.data['type'] = 'indexConsecutiveDayLineStats' event.data['greenLine'] = greenLine self._mainEngine.eventEngine.put(event)
def _stockCurEntrustsUpdateHandler(self, event): """ 收到来自券商接口的当日委托更新事件 """ # unpack header = event.data['header'] rows = event.data['rows'] updatedEntrusts = [] for data in rows[::-1]: # 从券商最近的委托开始匹配 # unpack from 券商接口当日委托 code = DyStockCommon.getDyStockCode(data[header.index( self.headerNameMap['curEntrust']['code'])]) price = float(data[header.index( self.headerNameMap['curEntrust']['price'])]) totalVolume = float(data[header.index( self.headerNameMap['curEntrust']['totalVolume'])]) dealedVolume = float(data[header.index( self.headerNameMap['curEntrust']['dealedVolume'])]) type = data[header.index(self.headerNameMap['curEntrust']['type'])] status = data[header.index( self.headerNameMap['curEntrust']['status'])] brokerEntrustId = data[header.index( self.headerNameMap['curEntrust']['entrustId'])] # get matched entrust from saved DevilYuan entrusts entrust = self._getEntrust(code, type, price, totalVolume, brokerEntrustId) if entrust is None: # 不是通过策略发出的委托 continue # update entrust if self._updateEntrust(entrust, dealedVolume, status, brokerEntrustId): updatedEntrusts.append(copy.copy(entrust)) # 向引擎推送委托回报事件 if updatedEntrusts: event = DyEvent(DyEventType.stockOnEntrust) event.data = updatedEntrusts self._eventEngine.put(event)