def _createReportWin(self): self.reportWnd = FramelessWindow() self.reportWnd.setObjectName("ReportWnd") self.reportWnd.resize(1000, 600) self.reportWnd.setMinimumSize(600, 600) self.reportWnd.setMaximumSize(1000, 600) self.reportWnd.hideTheseBtn() self.reportWnd.disabledMaximumBtn() self.reportWnd.setWindowTitle("回测报告") self.reportWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) self.reportView = ReportView(self.reportWnd) self.reportView.setObjectName("ReportView") self.reportWnd.setWidget(self.reportView)
class Controller(object): '''程序化入口类''' def __init__(self, logger, ui2eg_q, eg2ui_q): # 日志对象 self.logger = logger # 初始化多语言 # load_language("config") self._ui2egQueue = ui2eg_q self._eg2uiQueue = eg2ui_q # UI2EG发送请求对象 self._request = SendRequest(self._ui2egQueue, self.logger) # 高分辨率支持 QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) qInstallMessageHandler(lambda x, y, z: None) self.mainApp = QApplication(sys.argv) # 根据分辨率调整字体 font = QFont("Microsoft YaHei UI", 11) pointsize = font.pointSize() font.setPixelSize(pointsize * 96 / 72) self.mainApp.setFont(font) ################创建回测报告#################### self._createReportWin() ################################################ version = '' if os.path.exists('../Version.txt'): with open('../Version.txt', 'r', encoding='utf-8-sig') as f: version = f.readline() if ' ' in version: version = version.split(' ')[1] if len(version) > 0: version = ' - ' + version self.mainWnd = FramelessWindow() self.mainWnd.setWindowTitle('极星量化' + version) self.app = QuantApplication(self, master=self.mainWnd) if self.app.settings.contains('theme') and self.app.settings.value( 'theme') == 'vs-dark': theme = THESE_STATE_DARK else: theme = THESE_STATE_WHITE self.mainWnd.setWinThese(theme) self.mainWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) screen = QDesktopWidget().screenGeometry() self.mainWnd.setGeometry(screen.width() * 0.1, screen.height() * 0.1, screen.width() * 0.8, screen.height() * 0.8) # self.mainWnd.titleBar.buttonClose.clicked.connect(self.quitThread) self.mainWnd.titleBar.buttonClose.clicked.disconnect( self.mainWnd.titleBar.closeWindow) self.mainWnd.titleBar.buttonClose.clicked.connect( self.app.save_edit_strategy) self.mainWnd.setWidget(self.app) # 创建模块 self.model = QuantModel(self.app, self._ui2egQueue, self._eg2uiQueue, self.logger) self.app.init_control() self.logger.info("Create quant model!") # 策略管理器 self.strategyManager = self.getStManager() # 创建接收引擎数据线程 self.receiveEgThread = ChildThread(self.model.receiveEgEvent) # 设置日志更新 # self.update_log() # self.update_mon() def _createReportWin(self): self.reportWnd = FramelessWindow() self.reportWnd.setObjectName("ReportWnd") self.reportWnd.resize(1000, 600) self.reportWnd.setMinimumSize(600, 600) self.reportWnd.setMaximumSize(1000, 600) self.reportWnd.hideTheseBtn() self.reportWnd.disabledMaximumBtn() self.reportWnd.setWindowTitle("回测报告") self.reportWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) self.reportView = ReportView(self.reportWnd) self.reportView.setObjectName("ReportView") self.reportWnd.setWidget(self.reportView) def get_logger(self): return self.logger def update_log(self): try: self.app.updateLogText() except Exception as e: # self.logger.warn("异常", "程序退出异常") pass def update_mon(self): try: self.updateMonitor() except Exception as e: pass # def updateSig(self): # self.app.updateSigText() # # def updateUsr(self): # self.app.updateUsrText() def updateMonitor(self): # 更新监控界面策略信息 try: strategyDict = self.strategyManager.getStrategyDict() # TODO: strategyDict的异常策略应该怎么处理? for stId in strategyDict: if "RunningData" not in strategyDict[stId]: continue try: # TODO:StrategyState为什么会不存在呢? if strategyDict[stId][ "StrategyState"] == ST_STATUS_PAUSE or strategyDict[ stId]["StrategyState"] == ST_STATUS_QUIT or strategyDict[ stId][ "StrategyState"] == ST_STATUS_EXCEPTION: continue except KeyError as e: self.logger.warn(f"策略数据错误: {stId}, {strategyDict[stId]}") self.app.updateValue(stId, strategyDict[stId]["RunningData"]) except PermissionError as e: self.logger.error("更新监控信息时出错") def quitThread(self): self.logger.info("quitThread exit") # 停止更新界面子线程 # self.monitorThread.stop() # self.monitorThread.join() # 停止更新信号记录 # self.sigThread.stop() # self.sigThread.join() # 停止更新用户日志 # self.usrThread.stop() # self.usrThread.join() # 向引擎发送退出事件 self.sendExitRequest() # 停止接收策略引擎队列数据 self.receiveEgThread.stop() self.model.receiveExit() self.receiveEgThread.join() self.logger.info("before app.close") self.reportWnd.close() # self.mainApp.quit() self.mainApp.closeAllWindows() self.logger.info("after app.close") def run(self): # 启动监控策略线程 # self.monitorThread.start() # 启动接收数据线程 self.receiveEgThread.start() # self.sigThread.start() # self.usrThread.start() #启动主界面线程 self.mainWnd.show() self.mainApp.exec_() def set_help_text(self, funcName, text): self.app.set_help_text(funcName, text) def setEditorTextCode(self, path): """设置当前编辑的策略路径和代码信息""" self.model.setEditorTextCode(path) def getEditorText(self): return self.model.getEditorText() def getStManager(self): """获取策略管理器""" return self.model.getStrategyManager() def saveStrategy(self): """保存当前策略""" self.app.quant_editor.saveEditor() def parseStrategtParam(self, strategyPath): """解析策略中的用户参数""" g_params = {} with open(strategyPath, 'r', encoding="utf-8") as f: content = [line.strip() for line in f] for c in content: # regex = re.compile(r"^g_params[\[][\"\'](.*)[\"\'][\]]\s*=[\s]*([^\s]*)[\s]*(#[\s]*(.*))?") regex1 = re.compile( r"^g_params[\[][\"\'](.*)[\"\'][\]]\s*=[\s]*(.*)[\s]*#[\s]*(.*)?" ) regex2 = re.compile( r"^g_params[\[][\"\'](.*)[\"\'][\]]\s*=[\s]*(.*)[\s]*#?[\s]*(.*)?" ) reg1 = regex1.search(c) reg2 = regex2.search(c) if reg1 or reg2: reg = reg1 if reg1 else reg2 ret = [reg.groups()[1], reg.groups()[2]] # if ret[1] is None: ret[1] = "" try: ret[0] = eval(ret[0]) except: pass g_params.update({reg.groups()[0]: ret}) return g_params def load(self, strategyPath, param={}): # TODO:新增param参数,用于接收用户策略的参数 """ 加载合约事件 :param strategyPath: 策略路径 :param param: 策略参数信息 :return: """ # 运行策略前将用户修改保存 self.saveStrategy() # 解析策略参数 param = self.parseStrategtParam(strategyPath) self.app.create_strategy_policy_win(param=param) config = self.app.getConfig() if config: # 获取到config self._request.loadRequest(strategyPath, config) self.logger.info("load strategy") def paramLoad(self, id): """用户参数修改后策略重新启动""" param = self.getUserParam(id) strategyPath = self.strategyManager.getSingleStrategy(id)["Path"] self.app.create_strategy_policy_win(param, strategyPath, id) def generateReportReq(self, strategyIdList): """发送生成报告请求""" # 量化启动时的恢复策略列表中的策略没有回测数据 # 策略停止之后的报告数据从本地获取,不发送请求 # 策略启动时查看数据发送报告请求,从engine获取数据 # 查看策略的投资报告(不支持查看多个) if len(strategyIdList) >= 1: id = strategyIdList[0] status = self.strategyManager.queryStrategyStatus(id) strategyData = self.strategyManager.getSingleStrategy(id) if status == ST_STATUS_QUIT: # 策略已停止,从本地获取数据 if "ResultData" not in strategyData: # 程序启动时恢复的策略没有回测数据 QMessageBox.warning(None, '警告', '策略未启动,报告数据不存在') return reportData = strategyData["ResultData"] self.app.reportDisplay(reportData, id) return self._request.reportRequest(id) def newDir(self, path): """策略目录右键新建文件夹""" if not os.path.exists(path): os.makedirs(path) self.app.updateStrategyTree(path) def updateEditor(self, path): """ 更新策略编辑的内容和表头 :param path: 策略路径,为空则将编辑界面内容置为空 :return: """ editor = self.getEditorText() fileName = os.path.basename(path) self.updateEditorHead(fileName) self.app.updateEditorText(editor["code"]) def updateEditorHead(self, text): """更新策略表头""" self.app.updateEditorHead(text) def sendExitRequest(self): """发送量化界面退出请求""" self._request.quantExitRequest() def pauseRequest(self, strategyIdList): """ 发送所选策略暂停请求 :param strategyId: 所选策略Id列表 :return: """ for id in strategyIdList: self._request.strategyPause(id) def resumeRequest(self, strategyIdList): """ 发送所选策略恢复运行请求 :param strategyId: 所选策略Id列表 :return: """ for id in strategyIdList: # 策略如果是启动状态,则忽略此次启动请求 strategyDict = self.strategyManager.getStrategyDict() if id in strategyDict: status = self.strategyManager.queryStrategyStatus(id) if status == ST_STATUS_HISTORY or status == ST_STATUS_CONTINUES: self.logger.info("策略重复启动!") continue self._request.strategyResume(id) def quitRequest(self, strategyIdList): """ 发送所选策略停止请求 :param strategyId: 所选策略Id列表 :return: """ for id in strategyIdList: strategyDict = self.strategyManager.getStrategyDict() if id in strategyDict: status = self.strategyManager.queryStrategyStatus(id) if status == ST_STATUS_QUIT: self.logger.info("策略%s已停止!" % (id)) continue self._request.strategyQuit(id) else: self.logger.info("策略管理器中不存在策略%s" % (id)) def delStrategy(self, strategyIdList): # 获取策略管理器 for id in strategyIdList: strategyDict = self.strategyManager.getStrategyDict() if id in strategyDict: if strategyDict[id]["StrategyState"] == ST_STATUS_QUIT or \ strategyDict[id]["StrategyState"] == ST_STATUS_EXCEPTION: # 策略已经停止或策略异常 self.strategyManager.removeStrategy(id) self.app.delUIStrategy(id) self._request.strategyRemove(id) else: self.app.delUIStrategy(id) def signalDisplay(self, strategyIdList): """查看策略的信号及指标图(默认查看一个)""" if len(strategyIdList) >= 1: id = strategyIdList[0] self._request.strategySignal(id) def getUserParam(self, id): """获取用户设置的参数信息""" return self.strategyManager.getStrategyParamData(id) def paramSetting(self, strategyIdList): """发送属性设置事件""" if len(strategyIdList) >= 1: id = strategyIdList[0] self.paramLoad(id)
def __init__(self, logger, ui2eg_q, eg2ui_q): # 日志对象 self.logger = logger # 初始化多语言 # load_language("config") self._ui2egQueue = ui2eg_q self._eg2uiQueue = eg2ui_q # UI2EG发送请求对象 self._request = SendRequest(self._ui2egQueue, self.logger) # 高分辨率支持 QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) qInstallMessageHandler(lambda x, y, z: None) self.mainApp = QApplication(sys.argv) # 根据分辨率调整字体 font = QFont("Microsoft YaHei UI", 11) pointsize = font.pointSize() font.setPixelSize(pointsize * 96 / 72) self.mainApp.setFont(font) ################创建回测报告#################### self._createReportWin() ################################################ version = '' if os.path.exists('../Version.txt'): with open('../Version.txt', 'r', encoding='utf-8-sig') as f: version = f.readline() if ' ' in version: version = version.split(' ')[1] if len(version) > 0: version = ' - ' + version self.mainWnd = FramelessWindow() self.mainWnd.setWindowTitle('极星量化' + version) self.app = QuantApplication(self, master=self.mainWnd) if self.app.settings.contains('theme') and self.app.settings.value( 'theme') == 'vs-dark': theme = THESE_STATE_DARK else: theme = THESE_STATE_WHITE self.mainWnd.setWinThese(theme) self.mainWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) screen = QDesktopWidget().screenGeometry() self.mainWnd.setGeometry(screen.width() * 0.1, screen.height() * 0.1, screen.width() * 0.8, screen.height() * 0.8) # self.mainWnd.titleBar.buttonClose.clicked.connect(self.quitThread) self.mainWnd.titleBar.buttonClose.clicked.disconnect( self.mainWnd.titleBar.closeWindow) self.mainWnd.titleBar.buttonClose.clicked.connect( self.app.save_edit_strategy) self.mainWnd.setWidget(self.app) # 创建模块 self.model = QuantModel(self.app, self._ui2egQueue, self._eg2uiQueue, self.logger) self.app.init_control() self.logger.info("Create quant model!") # 策略管理器 self.strategyManager = self.getStManager() # 创建接收引擎数据线程 self.receiveEgThread = ChildThread(self.model.receiveEgEvent)
def __init__(self, logger, ui2eg_q, eg2ui_q): # 日志对象 self.logger = logger # 初始化多语言 # load_language("config") self._ui2egQueue = ui2eg_q self._eg2uiQueue = eg2ui_q # UI2EG发送请求对象 self._request = SendRequest(self._ui2egQueue, self.logger) # 高分辨率支持 QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # 创建主窗口 QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # 高分辨率下适应屏幕 self.mainApp = QApplication(sys.argv) # 根据分辨率调整字体 font = QFont("Microsoft YaHei UI", 10) pointsize = font.pointSize() font.setPixelSize(pointsize * 90 / 72) self.mainApp.setFont(font) ###############回测报告##################### style = CommonHelper.readQss(DARKSTYLE) self.reportWnd = FramelessWindow() self.reportWnd.setStyleSheet(style) self.reportWnd.setWindowTitle("回测报告") self.reportWnd.setWinThese(THESE_STATE_DARK) self.reportWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) self.reportView = ReportView() self.reportWnd.setWidget(self.reportView) ############################################## self.app = QuantApplication(self) if self.app.settings.contains('theme') and self.app.settings.value( 'theme') == 'vs-dark': qss_path = DARKSTYLE theme = THESE_STATE_DARK else: qss_path = WHITESTYLE theme = THESE_STATE_WHITE # 回测报告窗口(主线程中创建) self.mainWnd = FramelessWindow() style = CommonHelper.readQss(qss_path) self.mainWnd.setStyleSheet(style) self.mainWnd.setWindowTitle('极星量化') self.mainWnd.setWinThese(theme) self.mainWnd.setWindowIcon(QIcon('icon/epolestar ix2.ico')) screen = QDesktopWidget().screenGeometry() self.mainWnd.setGeometry(screen.width() * 0.1, screen.height() * 0.1, screen.width() * 0.8, screen.height() * 0.8) self.mainWnd.titleBar.buttonClose.clicked.connect(self.quitThread) self.mainWnd.setWidget(self.app) # 创建模块 self.model = QuantModel(self.app, self._ui2egQueue, self._eg2uiQueue, self.logger) self.app.init_control() self.logger.info("Create quant model!") # 策略管理器 self.strategyManager = self.getStManager() # 创建接收引擎数据线程 self.receiveEgThread = ChildThread(self.model.receiveEgEvent)