From af311628493c69dff34dba20c73a5e981e939412 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Fri, 1 Dec 2017 10:27:15 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9E=E6=B3=A2=E5=8A=A8?= =?UTF-8?q?=E7=8E=87=E5=9B=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/optionMaster/etf_portfolio.json | 10 ++ .../app/optionMaster/uiOmVolatilityManager.py | 126 ++++++++++++++++++ vnpy/trader/app/optionMaster/uiOmWidget.py | 18 ++- 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 vnpy/trader/app/optionMaster/uiOmVolatilityManager.py diff --git a/vnpy/trader/app/optionMaster/etf_portfolio.json b/vnpy/trader/app/optionMaster/etf_portfolio.json index 029bdf0f..3c6a9923 100644 --- a/vnpy/trader/app/optionMaster/etf_portfolio.json +++ b/vnpy/trader/app/optionMaster/etf_portfolio.json @@ -14,6 +14,16 @@ "underlyingSymbol": "510050", "chainSymbol": "510050-1801", "r": 0.03 + }, + { + "underlyingSymbol": "510050", + "chainSymbol": "510050-1803", + "r": 0.03 + }, + { + "underlyingSymbol": "510050", + "chainSymbol": "510050-1806", + "r": 0.03 } ] } \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/uiOmVolatilityManager.py b/vnpy/trader/app/optionMaster/uiOmVolatilityManager.py new file mode 100644 index 00000000..db48a611 --- /dev/null +++ b/vnpy/trader/app/optionMaster/uiOmVolatilityManager.py @@ -0,0 +1,126 @@ +# encoding: UTF-8 + +import pyqtgraph as pg + +from vnpy.event import Event +from vnpy.trader.vtEvent import EVENT_TIMER +from .uiOmBase import * + + +######################################################################## +class VolatilityChart(pg.GraphicsWindow): + """持仓组合波动率图表""" + signal = QtCore.pyqtSignal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, omEngine, parent=None): + """Constructor""" + super(VolatilityChart, self).__init__(parent) + + self.omEngine = omEngine + self.portfolio = omEngine.portfolio + self.eventEngine = omEngine.eventEngine + + self.updateCount = 0 + self.updateTrigger = 2 + + self.bidCurveDict = {} + self.askCurveDict = {} + self.pricingCurveDict = {} + + self.initUi() + self.registerEvent() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + portfolio = self.portfolio + + self.setWindowTitle(u'波动率图表') + + pg.setConfigOptions(antialias=True) #启用抗锯齿 + + # 创建绘图区以及线 + for chain in portfolio.chainDict.values(): + symbol = chain.symbol + CALL_SUFFIX + + chart = self.addPlot(title=symbol) + chart.showGrid(x=True, y=True) + chart.setLabel('left', u'波动率') #设置左边标签 + chart.setLabel('bottom', u'行权价') #设置底部标签 + + self.bidCurveDict[symbol] = chart.plot(pen='r', symbol='t', symbolSize=8, symbolBrush='r') + self.askCurveDict[symbol] = chart.plot(pen='g', symbolSize=8, symbolBrush='g') + self.pricingCurveDict[symbol] = chart.plot(pen='w', symbol = 's', symbolSize=8, symbolBrush='w') + + self.nextRow() + + for chain in portfolio.chainDict.values(): + symbol = chain.symbol + PUT_SUFFIX + + chart = self.addPlot(title=symbol) + chart.showGrid(x=True, y=True) + chart.setLabel('left', u'波动率') + chart.setLabel('bottom', u'行权价') + + self.bidCurveDict[symbol] = chart.plot(pen='r', symbol='t', symbolSize=8, symbolBrush='r') + self.askCurveDict[symbol] = chart.plot(pen='g', symbolSize=8, symbolBrush='g') + self.pricingCurveDict[symbol] = chart.plot(pen='w', symbol = 's', symbolSize=8, symbolBrush='w') + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.processTimerEvent) + self.eventEngine.register(EVENT_TIMER, self.signal.emit) + + #---------------------------------------------------------------------- + def processTimerEvent(self, event): + """处理定时事件""" + self.updateCount += 1 + if self.updateCount >= self.updateTrigger: + self.updateCount = 0 + self.updateChart() + + #---------------------------------------------------------------------- + def updateChart(self): + """更新图表""" + for chain in self.portfolio.chainDict.values(): + strikeData = [option.k for option in chain.callDict.values()] + + # 看涨 + symbol = chain.symbol + CALL_SUFFIX + + bidImpvData = [] + askImpvData = [] + pricingImpvData = [] + + for option in chain.callDict.values(): + bidImpvData.append(option.bidImpv*100) + askImpvData.append(option.askImpv*100) + pricingImpvData.append(option.pricingImpv*100) + + self.bidCurveDict[symbol].setData(y=bidImpvData, x=strikeData) + self.askCurveDict[symbol].setData(y=askImpvData, x=strikeData) + self.pricingCurveDict[symbol].setData(y=pricingImpvData, x=strikeData) + + # 看跌 + symbol = chain.symbol + PUT_SUFFIX + + bidImpvData = [] + askImpvData = [] + pricingImpvData = [] + + for option in chain.putDict.values(): + bidImpvData.append(option.bidImpv*100) + askImpvData.append(option.askImpv*100) + pricingImpvData.append(option.pricingImpv*100) + + self.bidCurveDict[symbol].setData(y=bidImpvData, x=strikeData) + self.askCurveDict[symbol].setData(y=askImpvData, x=strikeData) + self.pricingCurveDict[symbol].setData(y=pricingImpvData, x=strikeData) + + #---------------------------------------------------------------------- + def closeEvent(self, event): + """关闭""" + self.eventEngine.unregister(EVENT_TIMER, 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 00545004..93b75f80 100644 --- a/vnpy/trader/app/optionMaster/uiOmWidget.py +++ b/vnpy/trader/app/optionMaster/uiOmWidget.py @@ -11,6 +11,7 @@ from .omBase import EVENT_OM_LOG from .uiOmBase import QtWidgets, QtCore from .uiOmManualTrader import ManualTrader from .uiOmGreeksMonitor import GreeksMonitor +from .uiOmVolatilityManager import VolatilityChart ######################################################################## @@ -59,6 +60,9 @@ class OmManager(QtWidgets.QWidget): self.buttonGreeksMonitor = QtWidgets.QPushButton(u'希腊值监控') self.buttonGreeksMonitor.clicked.connect(self.openGreeksMonitor) + self.buttonVolatilityChart = QtWidgets.QPushButton(u'波动率图表') + self.buttonVolatilityChart.clicked.connect(self.openVolatilityChart) + self.logMonitor = QtWidgets.QTextEdit() self.logMonitor.setReadOnly(True) @@ -67,6 +71,7 @@ class OmManager(QtWidgets.QWidget): hbox.addWidget(self.buttonInit) hbox.addWidget(self.buttonManualTrader) hbox.addWidget(self.buttonGreeksMonitor) + hbox.addWidget(self.buttonVolatilityChart) hbox.addStretch() hbox2 = QtWidgets.QHBoxLayout() @@ -123,7 +128,16 @@ class OmManager(QtWidgets.QWidget): self.widgetDict['greeksMonitor'].showMaximized() except KeyError: self.widgetDict['greeksMonitor'] = GreeksMonitor(self.omEngine) - self.widgetDict['greeksMonitor'].showMaximized() + self.widgetDict['greeksMonitor'].showMaximized() + + #---------------------------------------------------------------------- + def openVolatilityChart(self): + """打开波动率图表组件""" + try: + self.widgetDict['volatilityChart'].showMaximized() + except KeyError: + self.widgetDict['volatilityChart'] = VolatilityChart(self.omEngine) + self.widgetDict['volatilityChart'].showMaximized() #---------------------------------------------------------------------- def close(self): @@ -131,7 +145,7 @@ class OmManager(QtWidgets.QWidget): for widget in self.widgetDict.values(): widget.close() - super(OmManagerWidget, self).close() + super(OmManager, self).close() #---------------------------------------------------------------------- def registerEvent(self):