diff --git a/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat b/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat index 0ca5e675..f85b1e8e 100644 --- a/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat +++ b/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat @@ -1 +1 @@ -HqLpRXdyn/k8CK6bQvjTlg== \ No newline at end of file +4kpJoMUXCPNmN66luTh0Lg== \ No newline at end of file diff --git a/vnpy/pricing/black.py b/vnpy/pricing/black.py index 0df9c35f..22d59f72 100644 --- a/vnpy/pricing/black.py +++ b/vnpy/pricing/black.py @@ -79,7 +79,7 @@ def calculateTheta(f, k, r, t, v, cp): #---------------------------------------------------------------------- def calculateVega(f, k, r, t, v, cp): """计算Vega值""" - vega = calculateVega(f, k, r, t, v, cp) / 100 + vega = calculateOriginalVega(f, k, r, t, v, cp) / 100 return vega #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index 394e5657..94887789 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -145,7 +145,7 @@ class OmUnderlying(OmInstrument): #---------------------------------------------------------------------- def calculatePosGreeks(self): """计算持仓希腊值""" - self.posDelta = self.theoDelta * self.netPos + self.posDelta = self.theoDelta * self.netPos * self.size ######################################################################## @@ -210,6 +210,8 @@ class OmOption(OmInstrument): self.bidImpv = self.calculateImpv(self.bidPrice1, underlyingPrice, self.k, self.r, self.t, self.cp) self.midImpv = (self.askImpv + self.bidImpv) / 2 + + self.pricingImpv = self.midImpv #---------------------------------------------------------------------- def calculateTheoGreeks(self): @@ -228,11 +230,11 @@ class OmOption(OmInstrument): #---------------------------------------------------------------------- def calculatePosGreeks(self): """计算持仓希腊值""" - self.posValue = self.theoPrice * self.netPos - self.posDelta = self.theoDelta * self.netPos - self.posGamma = self.theoGamma * self.netPos - self.posTheta = self.theoTheta * self.netPos - self.posVega = self.theoVega * self.netPos + self.posValue = self.theoPrice * self.netPos * self.size + self.posDelta = self.theoDelta * self.netPos * self.size + self.posGamma = self.theoGamma * self.netPos * self.size + self.posTheta = self.theoTheta * self.netPos * self.size + self.posVega = self.theoVega * self.netPos * self.size #---------------------------------------------------------------------- def newTick(self, tick): diff --git a/vnpy/trader/app/optionMaster/uiOmGreeksMonitor.py b/vnpy/trader/app/optionMaster/uiOmGreeksMonitor.py new file mode 100644 index 00000000..949fbd0a --- /dev/null +++ b/vnpy/trader/app/optionMaster/uiOmGreeksMonitor.py @@ -0,0 +1,294 @@ +# encoding: UTF-8 + +from vnpy.event import Event +from vnpy.trader.vtEvent import EVENT_TIMER + +from .uiOmBase import * + + +######################################################################## +class GreeksMonitor(QtWidgets.QTableWidget): + """希腊值监控""" + headers = [ + u'代码', + u'多仓', + u'空仓', + u'净仓', + u'Delta', + u'Gamma', + u'Theta', + u'Vega', + u'持仓Delta', + u'持仓Gamma', + u'持仓Theta', + u'持仓Vega' + ] + + signal = QtCore.pyqtSignal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, omEngine, parent=None): + """Constructor""" + super(GreeksMonitor, self).__init__() + + self.portfolio = omEngine.portfolio + self.eventEngine = omEngine.eventEngine + + self.cellDict = {} # key:symbol, value:cell dict + self.updateTrigger = 2 + self.updateCount = 0 + + self.initUi() + self.initCells() + self.registerEvent() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + portfolio = self.portfolio + + self.setWindowTitle(u'希腊值监控') + + # 计算所需行数 + totalRow = 1 + totalRow += len(portfolio.underlyingDict) + 1 + totalRow += len(portfolio.chainDict) + 1 + + for chain in portfolio.chainDict.values(): + totalRow += len(chain.optionDict) + 1 + + # 初始化表格 + self.setColumnCount(len(self.headers)) + self.setHorizontalHeaderLabels(self.headers) + self.setRowCount(totalRow) + self.verticalHeader().setVisible(False) + self.setEditTriggers(self.NoEditTriggers) + + for i in range(self.columnCount()): + self.horizontalHeader().setResizeMode(i, QtWidgets.QHeaderView.Stretch) + self.horizontalHeader().setResizeMode(0, QtWidgets.QHeaderView.ResizeToContents) + + #---------------------------------------------------------------------- + def initCells(self): + """初始化单元格""" + portfolio = self.portfolio + row = 0 + + # 组合 + cellSymbol = OmCell(portfolio.name, COLOR_SYMBOL, COLOR_BLACK) + cellLongPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellShortPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellNetPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellPosDelta = OmCell(0, COLOR_STRIKE) + cellPosGamma = OmCell(0, COLOR_STRIKE) + cellPosTheta = OmCell(0, COLOR_STRIKE) + cellPosVega = OmCell(0, COLOR_STRIKE) + + self.setItem(row, 0, cellSymbol) + self.setItem(row, 1, cellLongPos) + self.setItem(row, 2, cellShortPos) + self.setItem(row, 3, cellNetPos) + self.setItem(row, 8, cellPosDelta) + self.setItem(row, 9, cellPosGamma) + self.setItem(row, 10, cellPosTheta) + self.setItem(row, 11, cellPosVega) + + d = {} + d['longPos'] = cellLongPos + d['shortPos'] = cellShortPos + d['netPos'] = cellNetPos + d['posDelta'] = cellPosDelta + d['posGamma'] = cellPosGamma + d['posTheta'] = cellPosTheta + d['posVega'] = cellPosVega + self.cellDict[portfolio.name] = d + + row += 1 + + # 标的 + row += 1 # 空行 + + for underlying in portfolio.underlyingDict.values(): + cellSymbol = OmCell(underlying.symbol, COLOR_SYMBOL, COLOR_BLACK) + cellLongPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellShortPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellNetPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellTheoDelta = OmCell('%.3f' %underlying.theoDelta) + cellPosDelta = OmCell(0, COLOR_STRIKE) + + self.setItem(row, 0, cellSymbol) + self.setItem(row, 1, cellLongPos) + self.setItem(row, 2, cellShortPos) + self.setItem(row, 3, cellNetPos) + self.setItem(row, 4, cellTheoDelta) + self.setItem(row, 8, cellPosDelta) + + d = {} + d['longPos'] = cellLongPos + d['shortPos'] = cellShortPos + d['netPos'] = cellNetPos + d['theoDelta'] = cellTheoDelta + d['posDelta'] = cellPosDelta + self.cellDict[underlying.symbol] = d + + row += 1 + + # 期权链 + row += 1 + + for chain in portfolio.chainDict.values(): + cellSymbol = OmCell(chain.symbol, COLOR_SYMBOL, COLOR_BLACK) + cellLongPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellShortPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellNetPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellTheoDelta = OmCell(0) + cellTheoGamma = OmCell(0) + cellTheoTheta = OmCell(0) + cellTheoVega = OmCell(0) + cellPosDelta = OmCell(0, COLOR_STRIKE) + cellPosGamma = OmCell(0, COLOR_STRIKE) + cellPosTheta = OmCell(0, COLOR_STRIKE) + cellPosVega = OmCell(0, COLOR_STRIKE) + + self.setItem(row, 0, cellSymbol) + self.setItem(row, 1, cellLongPos) + self.setItem(row, 2, cellShortPos) + self.setItem(row, 3, cellNetPos) + self.setItem(row, 4, cellTheoDelta) + self.setItem(row, 5, cellTheoGamma) + self.setItem(row, 6, cellTheoTheta) + self.setItem(row, 7, cellTheoVega) + self.setItem(row, 8, cellPosDelta) + self.setItem(row, 9, cellPosGamma) + self.setItem(row, 10, cellPosTheta) + self.setItem(row, 11, cellPosVega) + + d = {} + d['longPos'] = cellLongPos + d['shortPos'] = cellShortPos + d['netPos'] = cellNetPos + d['theoDelta'] = cellTheoDelta + d['theoGamma'] = cellTheoGamma + d['theoTheta'] = cellTheoTheta + d['theoVega'] = cellTheoVega + d['posDelta'] = cellPosDelta + d['posGamma'] = cellPosGamma + d['posTheta'] = cellPosTheta + d['posVega'] = cellPosVega + self.cellDict[chain.symbol + '_chain'] = d + + row += 1 + + # 期权 + for chain in portfolio.chainDict.values(): + row += 1 + + for option in chain.optionDict.values(): + cellSymbol = OmCell(option.symbol, COLOR_SYMBOL, COLOR_BLACK) + cellLongPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellShortPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellNetPos = OmCell(0, COLOR_POS, COLOR_BLACK) + cellTheoDelta = OmCell(0) + cellTheoGamma = OmCell(0) + cellTheoTheta = OmCell(0) + cellTheoVega = OmCell(0) + cellPosDelta = OmCell(0, COLOR_STRIKE) + cellPosGamma = OmCell(0, COLOR_STRIKE) + cellPosTheta = OmCell(0, COLOR_STRIKE) + cellPosVega = OmCell(0, COLOR_STRIKE) + + self.setItem(row, 0, cellSymbol) + self.setItem(row, 1, cellLongPos) + self.setItem(row, 2, cellShortPos) + self.setItem(row, 3, cellNetPos) + self.setItem(row, 4, cellTheoDelta) + self.setItem(row, 5, cellTheoGamma) + self.setItem(row, 6, cellTheoTheta) + self.setItem(row, 7, cellTheoVega) + self.setItem(row, 8, cellPosDelta) + self.setItem(row, 9, cellPosGamma) + self.setItem(row, 10, cellPosTheta) + self.setItem(row, 11, cellPosVega) + + d = {} + d['longPos'] = cellLongPos + d['shortPos'] = cellShortPos + d['netPos'] = cellNetPos + d['theoDelta'] = cellTheoDelta + d['theoGamma'] = cellTheoGamma + d['theoTheta'] = cellTheoTheta + d['theoVega'] = cellTheoVega + d['posDelta'] = cellPosDelta + d['posGamma'] = cellPosGamma + d['posTheta'] = cellPosTheta + d['posVega'] = cellPosVega + self.cellDict[option.symbol] = d + + row += 1 + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.updateTable) + self.eventEngine.register(EVENT_TIMER, self.signal.emit) + + #---------------------------------------------------------------------- + def processTimerEvent(self, event): + """处理定时事件""" + self.updateCount += 1 + + if self.updateCount >= self.updateTrigger: + self.updateCount = 0 + self.updateTable() + + #---------------------------------------------------------------------- + def updateTable(self): + """更新表格""" + # 更新组合 + portfolio = self.portfolio + + d = self.cellDict[portfolio.name] + d['longPos'].setText(str(portfolio.longPos)) + d['shortPos'].setText(str(portfolio.shortPos)) + d['netPos'].setText(str(portfolio.netPos)) + d['posDelta'].setText('%.1f' %portfolio.posDelta) + d['posGamma'].setText('%.1f' %portfolio.posGamma) + d['posTheta'].setText('%.1f' %portfolio.posTheta) + d['posVega'].setText('%.1f' %portfolio.posVega) + + # 更新标的 + for underlying in portfolio.underlyingDict.values(): + d = self.cellDict[underlying.symbol] + d['longPos'].setText(str(underlying.longPos)) + d['shortPos'].setText(str(underlying.shortPos)) + d['netPos'].setText(str(underlying.netPos)) + d['posDelta'].setText('%.1f' %underlying.posDelta) + + # 更新期权链 + for chain in portfolio.chainDict.values(): + d = self.cellDict[chain.symbol + '_chain'] + d['longPos'].setText(str(chain.longPos)) + d['shortPos'].setText(str(chain.shortPos)) + d['netPos'].setText(str(chain.netPos)) + d['posDelta'].setText('%.1f' %chain.posDelta) + d['posGamma'].setText('%.1f' %chain.posGamma) + d['posTheta'].setText('%.1f' %chain.posTheta) + d['posVega'].setText('%.1f' %chain.posVega) + + # 更新期权 + for chain in portfolio.chainDict.values(): + for option in chain.optionDict.values(): + d = self.cellDict[option.symbol] + d['longPos'].setText(str(option.longPos)) + d['shortPos'].setText(str(option.shortPos)) + d['netPos'].setText(str(option.netPos)) + d['theoDelta'].setText('%.3f' %option.theoDelta) + d['theoGamma'].setText('%.3f' %option.theoGamma) + d['theoTheta'].setText('%.3f' %option.theoTheta) + d['theoVega'].setText('%.3f' %option.theoVega) + d['posDelta'].setText('%.1f' %option.posDelta) + d['posGamma'].setText('%.1f' %option.posGamma) + d['posTheta'].setText('%.1f' %option.posTheta) + d['posVega'].setText('%.1f' %option.posVega) + + \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/uiOmWidget.py b/vnpy/trader/app/optionMaster/uiOmWidget.py index 74f2b308..00545004 100644 --- a/vnpy/trader/app/optionMaster/uiOmWidget.py +++ b/vnpy/trader/app/optionMaster/uiOmWidget.py @@ -6,10 +6,11 @@ import os from datetime import datetime from vnpy.event import Event -from vnpy.trader.uiQt import QtWidgets, QtCore from .omBase import EVENT_OM_LOG +from .uiOmBase import QtWidgets, QtCore from .uiOmManualTrader import ManualTrader +from .uiOmGreeksMonitor import GreeksMonitor ######################################################################## @@ -55,6 +56,9 @@ class OmManager(QtWidgets.QWidget): self.buttonManualTrader = QtWidgets.QPushButton(u'手动交易') self.buttonManualTrader.clicked.connect(self.openManualTrader) + self.buttonGreeksMonitor = QtWidgets.QPushButton(u'希腊值监控') + self.buttonGreeksMonitor.clicked.connect(self.openGreeksMonitor) + self.logMonitor = QtWidgets.QTextEdit() self.logMonitor.setReadOnly(True) @@ -62,6 +66,7 @@ class OmManager(QtWidgets.QWidget): hbox.addWidget(self.comboSettingFile) hbox.addWidget(self.buttonInit) hbox.addWidget(self.buttonManualTrader) + hbox.addWidget(self.buttonGreeksMonitor) hbox.addStretch() hbox2 = QtWidgets.QHBoxLayout() @@ -110,6 +115,15 @@ class OmManager(QtWidgets.QWidget): except KeyError: self.widgetDict['manualTrader'] = ManualTrader(self.omEngine) self.widgetDict['manualTrader'].showMaximized() + + #---------------------------------------------------------------------- + def openGreeksMonitor(self): + """打开希腊值监控组件""" + try: + self.widgetDict['greeksMonitor'].showMaximized() + except KeyError: + self.widgetDict['greeksMonitor'] = GreeksMonitor(self.omEngine) + self.widgetDict['greeksMonitor'].showMaximized() #---------------------------------------------------------------------- def close(self):