[Add]添加持仓情景分析功能

This commit is contained in:
vn.py 2017-12-01 13:54:19 +08:00
parent dfb23ab2f4
commit 20bae552d6
6 changed files with 232 additions and 7 deletions

View File

@ -1 +1 @@
1akdYJY+uYtFOYGtWEJkKg==
3PhIldq+vwFT0Ap6unvLxA==

View File

@ -130,7 +130,7 @@ def calculateImpv(price, f, k, r, t, cp):
# 如果vega过小接近0则直接返回
if not vega:
return v
break
# 计算误差
dx = (price - p) / vega
@ -143,7 +143,7 @@ def calculateImpv(price, f, k, r, t, cp):
v += dx
# 检查波动率计算结果非负
if v < 0:
if v <= 0:
return 0
# 保留4位小数

View File

@ -368,9 +368,10 @@ class OmPortfolio(object):
"""持仓组合"""
#----------------------------------------------------------------------
def __init__(self, name, underlyingList, chainList):
def __init__(self, name, model, underlyingList, chainList):
"""Constructor"""
self.name = name
self.model = model
# 原始容器
self.underlyingDict = OrderedDict()

View File

@ -156,7 +156,7 @@ class OmEngine(object):
underlying.addChain(chain)
# 创建持仓组合对象并初始化
self.portfolio = OmPortfolio(setting['name'], underlyingDict.values(), chainList)
self.portfolio = OmPortfolio(setting['name'], model, underlyingDict.values(), chainList)
# 载入波动率配置
self.loadImpvSetting()
@ -198,7 +198,7 @@ class OmEngine(object):
f.close()
#----------------------------------------------------------------------
def close(self):
def stop(self):
"""关闭函数"""
self.saveImpvSetting()

View File

@ -0,0 +1,208 @@
# encoding: UTF-8
from __future__ import division
import numpy as np
from .uiOmBase import *
########################################################################
class ScenarioValueMonitor(QtWidgets.QTableWidget):
"""情景分析监控工具,某一个数值"""
#----------------------------------------------------------------------
def __init__(self, key, parent=None):
"""Constructor"""
super(ScenarioValueMonitor, self).__init__(parent)
self.key = key
self.initUi()
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
self.setEditTriggers(self.NoEditTriggers)
self.setMinimumHeight(600)
#----------------------------------------------------------------------
def updateData(self, result, priceChangeArray, impvChangeArray):
"""更新界面"""
# 清空表格
self.clearContents()
# 设置表头
self.setColumnCount(len(priceChangeArray))
priceChangeHeaders = [('%s%%' %(priceChange*100)) for priceChange in priceChangeArray]
self.setHorizontalHeaderLabels(priceChangeHeaders)
self.setRowCount(len(impvChangeArray))
impvChangeHeaders = [('%s%%' %(impvChange*100)) for impvChange in impvChangeArray]
self.setVerticalHeaderLabels(impvChangeHeaders)
# 设置数据
l = [d[self.key] for d in result.values()]
maxValue = max(l)
minValue = min(l)
# 最大和最小值相等,则说明计算逻辑有问题
if maxValue == minValue:
return
midValue = (maxValue + minValue) / 2
colorRatio = 255*2/(maxValue-minValue)
for column, priceChange in enumerate(priceChangeArray):
for row, impvChange in enumerate(impvChangeArray):
value = result[(priceChange, impvChange)][self.key]
# 计算颜色
red = 255
green = 255
colorValue = (value - midValue) * colorRatio
if colorValue <= 0:
red -= abs(colorValue)
else:
green -= abs(colorValue)
color = QtGui.QColor(red, green, 0)
# 插入单元格到表格中
cell = QtWidgets.QTableWidgetItem('%.1f' %value)
cell.setBackground(color)
cell.setForeground(COLOR_BLACK)
self.setItem(row, column, cell)
self.resizeColumnsToContents()
self.resizeRowsToContents()
########################################################################
class ScenarioAnalysisMonitor(QtWidgets.QTabWidget):
"""情景分析监控组件"""
#----------------------------------------------------------------------
def __init__(self, parent=None):
"""Constructor"""
super(ScenarioAnalysisMonitor, self).__init__(parent)
self.initUi()
#----------------------------------------------------------------------
def initUi(self):
""""""
self.valueMonitorList = []
for key in ['pnl', 'delta', 'gamma', 'theta', 'vega']:
valueMonitor = ScenarioValueMonitor(key)
self.addTab(valueMonitor, key)
self.valueMonitorList.append(valueMonitor)
#----------------------------------------------------------------------
def updateData(self, result, priceChangeArray, impvChangeArray):
"""更新数据"""
for valueMonitor in self.valueMonitorList:
valueMonitor.updateData(result, priceChangeArray, impvChangeArray)
########################################################################
class AnalysisManager(QtWidgets.QWidget):
"""研究分析管理"""
#----------------------------------------------------------------------
def __init__(self, omEngine, parent=None):
"""Constructor"""
super(AnalysisManager, self).__init__(parent)
self.omEngine = omEngine
self.portfolio = omEngine.portfolio
self.initUi()
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
self.setWindowTitle(u'持仓分析')
self.scenarioAnalysisMonitor = ScenarioAnalysisMonitor()
self.buttonScenarioAnalysis = QtWidgets.QPushButton(u'情景分析')
self.buttonScenarioAnalysis.clicked.connect(self.updateData)
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.buttonScenarioAnalysis)
hbox.addStretch()
vbox = QtWidgets.QVBoxLayout()
vbox.addLayout(hbox)
vbox.addWidget(self.scenarioAnalysisMonitor)
self.setLayout(vbox)
#----------------------------------------------------------------------
def updateData(self):
"""更新数据"""
result, priceChangeArray, impvChangeArray = self.runScenarioAnalysis()
if result:
self.scenarioAnalysisMonitor.updateData(result, priceChangeArray, impvChangeArray)
#----------------------------------------------------------------------
def runScenarioAnalysis(self):
"""运行情景分析"""
portfolio = self.portfolio
calculateGreeks = portfolio.model.calculateGreeks
if not portfolio:
return None, None, None
changeRange = 5
priceChangeArray = np.arange(-changeRange, changeRange+1) / 100
impvChangeArray = np.arange(-changeRange, changeRange+1) / 100
expiryChange = 1/240 # 一个交易日对应的时间变化
result = {} # 分析结果
for priceChange in priceChangeArray:
for impvChange in impvChangeArray:
print priceChange, impvChange
portfolioPnl = 0
portfolioDelta = 0
portfolioGamma = 0
portfolioTheta = 0
portfolioVega = 0
for underlying in portfolio.underlyingDict.values():
portfolioPnl += underlying.midPrice * underlying.netPos * priceChange
portfolioDelta += underlying.theoDelta * underlying.netPos
try:
for option in portfolio.optionDict.values():
if not option.netPos:
continue
price, delta, gamma, theta, vega = calculateGreeks(option.underlying.midPrice*(1+priceChange),
option.k,
option.r,
max(option.t-expiryChange, 0),
option.pricingImpv*(1+impvChange),
option.cp)
portfolioPnl += (price - option.theoPrice) * option.netPos * option.size
portfolioDelta += delta * option.netPos * option.size
portfolioGamma += gamma * option.netPos * option.size
portfolioTheta += theta * option.netPos * option.size
portfolioVega += vega * option.netPos * option.size
except ZeroDivisionError:
return None, None, None
d = {
'pnl': portfolioPnl,
'delta': portfolioDelta,
'gamma': portfolioGamma,
'theta': portfolioTheta,
'vega': portfolioVega
}
result[(priceChange, impvChange)] = d
return result, priceChangeArray, impvChangeArray

View File

@ -12,6 +12,7 @@ from .uiOmBase import QtWidgets, QtCore
from .uiOmManualTrader import ManualTrader
from .uiOmGreeksMonitor import GreeksMonitor
from .uiOmVolatilityManager import VolatilityChart, VolatilityManager
from .uiOmAnalysisManager import AnalysisManager
########################################################################
@ -70,6 +71,10 @@ class OmManager(QtWidgets.QWidget):
self.buttonVolatilityManager.clicked.connect(self.openVolatilityManager)
self.buttonVolatilityManager.setDisabled(True)
self.buttonAnalysisManager = QtWidgets.QPushButton(u'持仓分析')
self.buttonAnalysisManager.clicked.connect(self.openAnalysisManager)
self.buttonAnalysisManager.setDisabled(True)
self.logMonitor = QtWidgets.QTextEdit()
self.logMonitor.setReadOnly(True)
@ -80,6 +85,7 @@ class OmManager(QtWidgets.QWidget):
hbox.addWidget(self.buttonGreeksMonitor)
hbox.addWidget(self.buttonVolatilityChart)
hbox.addWidget(self.buttonVolatilityManager)
hbox.addWidget(self.buttonAnalysisManager)
hbox.addStretch()
hbox2 = QtWidgets.QHBoxLayout()
@ -116,6 +122,7 @@ class OmManager(QtWidgets.QWidget):
self.buttonGreeksMonitor.setEnabled(True)
self.buttonVolatilityChart.setEnabled(True)
self.buttonVolatilityManager.setEnabled(True)
self.buttonAnalysisManager.setEnabled(True)
#----------------------------------------------------------------------
def writeLog(self, content, time=''):
@ -166,7 +173,16 @@ class OmManager(QtWidgets.QWidget):
self.widgetDict['volatilityManager'].show()
except KeyError:
self.widgetDict['volatilityManager'] = VolatilityManager(self.omEngine)
self.widgetDict['volatilityManager'].show()
self.widgetDict['volatilityManager'].show()
#----------------------------------------------------------------------
def openAnalysisManager(self):
"""打开持仓分析组件"""
try:
self.widgetDict['analysisManager'].showMaximized()
except KeyError:
self.widgetDict['analysisManager'] = AnalysisManager(self.omEngine)
self.widgetDict['analysisManager'].showMaximized()
#----------------------------------------------------------------------
def close(self):