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

View File

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

View File

@ -156,7 +156,7 @@ class OmEngine(object):
underlying.addChain(chain) underlying.addChain(chain)
# 创建持仓组合对象并初始化 # 创建持仓组合对象并初始化
self.portfolio = OmPortfolio(setting['name'], underlyingDict.values(), chainList) self.portfolio = OmPortfolio(setting['name'], model, underlyingDict.values(), chainList)
# 载入波动率配置 # 载入波动率配置
self.loadImpvSetting() self.loadImpvSetting()
@ -198,7 +198,7 @@ class OmEngine(object):
f.close() f.close()
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def close(self): def stop(self):
"""关闭函数""" """关闭函数"""
self.saveImpvSetting() 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 .uiOmManualTrader import ManualTrader
from .uiOmGreeksMonitor import GreeksMonitor from .uiOmGreeksMonitor import GreeksMonitor
from .uiOmVolatilityManager import VolatilityChart, VolatilityManager 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.clicked.connect(self.openVolatilityManager)
self.buttonVolatilityManager.setDisabled(True) 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 = QtWidgets.QTextEdit()
self.logMonitor.setReadOnly(True) self.logMonitor.setReadOnly(True)
@ -80,6 +85,7 @@ class OmManager(QtWidgets.QWidget):
hbox.addWidget(self.buttonGreeksMonitor) hbox.addWidget(self.buttonGreeksMonitor)
hbox.addWidget(self.buttonVolatilityChart) hbox.addWidget(self.buttonVolatilityChart)
hbox.addWidget(self.buttonVolatilityManager) hbox.addWidget(self.buttonVolatilityManager)
hbox.addWidget(self.buttonAnalysisManager)
hbox.addStretch() hbox.addStretch()
hbox2 = QtWidgets.QHBoxLayout() hbox2 = QtWidgets.QHBoxLayout()
@ -116,6 +122,7 @@ class OmManager(QtWidgets.QWidget):
self.buttonGreeksMonitor.setEnabled(True) self.buttonGreeksMonitor.setEnabled(True)
self.buttonVolatilityChart.setEnabled(True) self.buttonVolatilityChart.setEnabled(True)
self.buttonVolatilityManager.setEnabled(True) self.buttonVolatilityManager.setEnabled(True)
self.buttonAnalysisManager.setEnabled(True)
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def writeLog(self, content, time=''): def writeLog(self, content, time=''):
@ -166,7 +173,16 @@ class OmManager(QtWidgets.QWidget):
self.widgetDict['volatilityManager'].show() self.widgetDict['volatilityManager'].show()
except KeyError: except KeyError:
self.widgetDict['volatilityManager'] = VolatilityManager(self.omEngine) 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): def close(self):