diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index 8b325d13..7db76642 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -19,6 +19,7 @@ OM_DB_NAME = 'VnTrader_OptionMaster_Db' # 事件定义 EVENT_OM_LOG = 'eOmLog' +EVENT_OM_STRATEGY = 'eOmStrategy' ######################################################################## diff --git a/vnpy/trader/app/optionMaster/omEngine.py b/vnpy/trader/app/optionMaster/omEngine.py index d3aa6a41..b2f90c65 100644 --- a/vnpy/trader/app/optionMaster/omEngine.py +++ b/vnpy/trader/app/optionMaster/omEngine.py @@ -20,7 +20,7 @@ from vnpy.trader.vtConstant import (PRODUCT_OPTION, OPTION_CALL, OPTION_PUT, from vnpy.pricing import black, bs, crr from .omBase import (OmOption, OmUnderlying, OmChain, OmPortfolio, - EVENT_OM_LOG, + EVENT_OM_LOG, EVENT_OM_STRATEGY, OM_DB_NAME) from .strategy import STRATEGY_CLASS @@ -50,6 +50,8 @@ class OmEngine(object): self.portfolio = None self.optionContractDict = {} # symbol:contract + self.strategyEngine = OmStrategyEngine(self, eventEngine) + self.registerEvent() #---------------------------------------------------------------------- @@ -226,7 +228,7 @@ class OmEngine(object): ######################################################################## class OmStrategyEngine(object): """策略引擎""" - settingFileName = 'OM_setting.json' + settingFileName = 'strategy_setting.json' settingfilePath = getJsonPath(settingFileName, __file__) #---------------------------------------------------------------------- @@ -249,7 +251,7 @@ class OmStrategyEngine(object): """注册事件监听""" self.eventEngine.register(EVENT_TICK, self.processTickEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) - self.eventEngine.register(EVENT_ORDER, self.processOrdervent) + self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) self.eventEngine.register(EVENT_TIMER, self.processTimerEvent) #---------------------------------------------------------------------- @@ -449,5 +451,57 @@ class OmStrategyEngine(object): def getPortfolio(self): """获取持仓组合信息""" return self.portfolio - + #---------------------------------------------------------------------- + def putStrategyEvent(self, name): + """触发策略状态变化事件(通常用于通知GUI更新)""" + event = Event(EVENT_OM_STRATEGY+name) + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def getStrategyVar(self, name): + """获取策略当前的变量字典""" + if name in self.strategyDict: + strategy = self.strategyDict[name] + varDict = OrderedDict() + + for key in strategy.varList: + varDict[key] = strategy.__getattribute__(key) + + return varDict + else: + self.writeLog(u'策略实例不存在:' + name) + return None + + #---------------------------------------------------------------------- + def getStrategyParam(self, name): + """获取策略的参数字典""" + if name in self.strategyDict: + strategy = self.strategyDict[name] + paramDict = OrderedDict() + + for key in strategy.paramList: + paramDict[key] = strategy.__getattribute__(key) + + return paramDict + else: + self.writeLog(u'策略实例不存在:' + name) + return None + + #---------------------------------------------------------------------- + def initAll(self): + """全部初始化""" + for name in self.strategyDict.keys(): + self.initStrategy(name) + + #---------------------------------------------------------------------- + def startAll(self): + """全部启动""" + for name in self.strategyDict.keys(): + self.startStrategy(name) + + #---------------------------------------------------------------------- + def stopAll(self): + """全部停止""" + for name in self.strategyDict.keys(): + self.stopStrategy(name) \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/omStrategy.py b/vnpy/trader/app/optionMaster/omStrategy.py index 12778ebc..06ca4cee 100644 --- a/vnpy/trader/app/optionMaster/omStrategy.py +++ b/vnpy/trader/app/optionMaster/omStrategy.py @@ -127,4 +127,11 @@ class OmStrategyTemplate(object): """获取持仓组合信息""" return self.engine.getPortfolio() + #---------------------------------------------------------------------- + def putEvent(self): + """发出GUI更新通知""" + self.engine.putStrategyEvent(self.name) + + + diff --git a/vnpy/trader/app/optionMaster/strategy_setting.json b/vnpy/trader/app/optionMaster/strategy_setting.json new file mode 100644 index 00000000..f353fe60 --- /dev/null +++ b/vnpy/trader/app/optionMaster/strategy_setting.json @@ -0,0 +1,7 @@ +[ + { + "name": "double ema", + "className": "EmaDemoStrategy", + "vtSymbol": "IF1706" + } +] \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/uiOmStrategyManager.py b/vnpy/trader/app/optionMaster/uiOmStrategyManager.py new file mode 100644 index 00000000..924d39cc --- /dev/null +++ b/vnpy/trader/app/optionMaster/uiOmStrategyManager.py @@ -0,0 +1,269 @@ +# encoding: UTF-8 + +''' +OM策略引擎的GUI控制组件 +''' + + +from vnpy.event import Event +from vnpy.trader.vtEvent import * +from vnpy.trader.uiBasicWidget import QtGui, QtCore, QtWidgets, BasicCell + +from .omBase import EVENT_OM_LOG, EVENT_OM_STRATEGY + + +######################################################################## +class ValueMonitor(QtWidgets.QTableWidget): + """参数监控""" + + #---------------------------------------------------------------------- + def __init__(self, parent=None): + """Constructor""" + super(ValueMonitor, self).__init__(parent) + + self.keyCellDict = {} + self.data = None + self.inited = False + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setRowCount(1) + self.verticalHeader().setVisible(False) + self.setEditTriggers(self.NoEditTriggers) + + self.setMaximumHeight(self.sizeHint().height()) + + #---------------------------------------------------------------------- + def updateData(self, data): + """更新数据""" + if not self.inited: + self.setColumnCount(len(data)) + self.setHorizontalHeaderLabels(data.keys()) + + col = 0 + for k, v in data.items(): + cell = QtWidgets.QTableWidgetItem(unicode(v)) + self.keyCellDict[k] = cell + self.setItem(0, col, cell) + col += 1 + + self.inited = True + else: + for k, v in data.items(): + cell = self.keyCellDict[k] + cell.setText(unicode(v)) + + +######################################################################## +class StrategyManager(QtWidgets.QGroupBox): + """策略管理组件""" + signal = QtCore.Signal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, engine, eventEngine, name, parent=None): + """Constructor""" + super(StrategyManager, self).__init__(parent) + + self.engine = engine + self.eventEngine = eventEngine + self.name = name + + self.initUi() + self.updateMonitor() + self.registerEvent() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setTitle(self.name) + + self.paramMonitor = ValueMonitor(self) + self.varMonitor = ValueMonitor(self) + + height = 65 + self.paramMonitor.setFixedHeight(height) + self.varMonitor.setFixedHeight(height) + + buttonInit = QtWidgets.QPushButton(u'初始化') + buttonStart = QtWidgets.QPushButton(u'启动') + buttonStop = QtWidgets.QPushButton(u'停止') + buttonInit.clicked.connect(self.init) + buttonStart.clicked.connect(self.start) + buttonStop.clicked.connect(self.stop) + + hbox1 = QtWidgets.QHBoxLayout() + hbox1.addWidget(buttonInit) + hbox1.addWidget(buttonStart) + hbox1.addWidget(buttonStop) + hbox1.addStretch() + + hbox2 = QtWidgets.QHBoxLayout() + hbox2.addWidget(self.paramMonitor) + + hbox3 = QtWidgets.QHBoxLayout() + hbox3.addWidget(self.varMonitor) + + vbox = QtWidgets.QVBoxLayout() + vbox.addLayout(hbox1) + vbox.addLayout(hbox2) + vbox.addLayout(hbox3) + + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def updateMonitor(self, event=None): + """显示策略最新状态""" + paramDict = self.engine.getStrategyParam(self.name) + if paramDict: + self.paramMonitor.updateData(paramDict) + + varDict = self.engine.getStrategyVar(self.name) + if varDict: + self.varMonitor.updateData(varDict) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.updateMonitor) + self.eventEngine.register(EVENT_OM_STRATEGY+self.name, self.signal.emit) + + #---------------------------------------------------------------------- + def init(self): + """初始化策略""" + self.engine.initStrategy(self.name) + + #---------------------------------------------------------------------- + def start(self): + """启动策略""" + self.engine.startStrategy(self.name) + + #---------------------------------------------------------------------- + def stop(self): + """停止策略""" + self.engine.stopStrategy(self.name) + + +######################################################################## +class StrategyEngineManager(QtWidgets.QWidget): + """引擎管理组件""" + signal = QtCore.Signal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, omEngine, parent=None): + """Constructor""" + super(StrategyEngineManager, self).__init__(parent) + + self.engine = omEngine.strategyEngine + self.eventEngine = omEngine.eventEngine + + self.strategyLoaded = False + + self.initUi() + self.registerEvent() + + # 记录日志 + self.engine.writeLog(u'期权策略引擎启动') + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setWindowTitle(u'期权策略') + + # 按钮 + loadButton = QtWidgets.QPushButton(u'加载策略') + initAllButton = QtWidgets.QPushButton(u'全部初始化') + startAllButton = QtWidgets.QPushButton(u'全部启动') + stopAllButton = QtWidgets.QPushButton(u'全部停止') + + loadButton.clicked.connect(self.load) + initAllButton.clicked.connect(self.initAll) + startAllButton.clicked.connect(self.startAll) + stopAllButton.clicked.connect(self.stopAll) + + # 滚动区域,放置所有的StrategyManager + self.scrollArea = QtWidgets.QScrollArea() + self.scrollArea.setWidgetResizable(True) + + # 日志监控 + self.ctaLogMonitor = QtWidgets.QTextEdit() + self.ctaLogMonitor.setReadOnly(True) + self.ctaLogMonitor.setMaximumHeight(200) + + # 设置布局 + hbox2 = QtWidgets.QHBoxLayout() + hbox2.addWidget(loadButton) + hbox2.addWidget(initAllButton) + hbox2.addWidget(startAllButton) + hbox2.addWidget(stopAllButton) + hbox2.addStretch() + + vbox = QtWidgets.QVBoxLayout() + vbox.addLayout(hbox2) + vbox.addWidget(self.scrollArea) + vbox.addWidget(self.ctaLogMonitor) + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def initStrategyManager(self): + """初始化策略管理组件界面""" + w = QtWidgets.QWidget() + vbox = QtWidgets.QVBoxLayout() + + for name in self.engine.strategyDict.keys(): + strategyManager = StrategyManager(self.engine, self.eventEngine, name) + vbox.addWidget(strategyManager) + + vbox.addStretch() + + w.setLayout(vbox) + self.scrollArea.setWidget(w) + + #---------------------------------------------------------------------- + def initAll(self): + """全部初始化""" + self.engine.initAll() + + #---------------------------------------------------------------------- + def startAll(self): + """全部启动""" + self.engine.startAll() + + #---------------------------------------------------------------------- + def stopAll(self): + """全部停止""" + self.engine.stopAll() + + #---------------------------------------------------------------------- + def load(self): + """加载策略""" + if not self.strategyLoaded: + self.engine.loadSetting() + self.initStrategyManager() + self.strategyLoaded = True + self.engine.writeLog(u'策略加载成功') + + #---------------------------------------------------------------------- + def updateLog(self, event): + """更新相关日志""" + log = event.dict_['data'] + content = '\t'.join([log.logTime, log.logContent]) + self.ctaLogMonitor.append(content) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.updateLog) + self.eventEngine.register(EVENT_OM_LOG, self.signal.emit) + + + + + + + + + + \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/uiOmWidget.py b/vnpy/trader/app/optionMaster/uiOmWidget.py index f34d0069..f8764a58 100644 --- a/vnpy/trader/app/optionMaster/uiOmWidget.py +++ b/vnpy/trader/app/optionMaster/uiOmWidget.py @@ -13,6 +13,7 @@ from .uiOmManualTrader import ManualTrader from .uiOmGreeksMonitor import GreeksMonitor from .uiOmVolatilityManager import VolatilityChart, VolatilityManager from .uiOmAnalysisManager import AnalysisManager +from .uiOmStrategyManager import StrategyEngineManager ######################################################################## @@ -75,6 +76,10 @@ class OmManager(QtWidgets.QWidget): self.buttonAnalysisManager.clicked.connect(self.openAnalysisManager) self.buttonAnalysisManager.setDisabled(True) + self.buttonStrategyManager = QtWidgets.QPushButton(u'策略交易') + self.buttonStrategyManager.clicked.connect(self.openStrategyManager) + self.buttonStrategyManager.setDisabled(True) + self.logMonitor = QtWidgets.QTextEdit() self.logMonitor.setReadOnly(True) @@ -86,6 +91,7 @@ class OmManager(QtWidgets.QWidget): hbox.addWidget(self.buttonVolatilityChart) hbox.addWidget(self.buttonVolatilityManager) hbox.addWidget(self.buttonAnalysisManager) + hbox.addWidget(self.buttonStrategyManager) hbox.addStretch() hbox2 = QtWidgets.QHBoxLayout() @@ -123,6 +129,7 @@ class OmManager(QtWidgets.QWidget): self.buttonVolatilityChart.setEnabled(True) self.buttonVolatilityManager.setEnabled(True) self.buttonAnalysisManager.setEnabled(True) + self.buttonStrategyManager.setEnabled(True) #---------------------------------------------------------------------- def writeLog(self, content, time=''): @@ -182,7 +189,16 @@ class OmManager(QtWidgets.QWidget): self.widgetDict['analysisManager'].showMaximized() except KeyError: self.widgetDict['analysisManager'] = AnalysisManager(self.omEngine) - self.widgetDict['analysisManager'].showMaximized() + self.widgetDict['analysisManager'].showMaximized() + + #---------------------------------------------------------------------- + def openStrategyManager(self): + """打开策略交易组件""" + try: + self.widgetDict['strategyManager'].showMaximized() + except KeyError: + self.widgetDict['strategyManager'] = StrategyEngineManager(self.omEngine) + self.widgetDict['strategyManager'].showMaximized() #---------------------------------------------------------------------- def close(self):