目录
效果:
代码:
使用:
数据
效果:
1. 绿色线段为CML线,即最优投资组合,也叫切线组合
2. 红色星星是GMVP点,即最小方差组合
3. 玫瑰色是鼠标单击该点,获取当前点的风险与收益
代码:
import sys
import pandas as pd
from PyQt5 import QtGui,QtWidgets
from PyQt5.QtCore import Qt
from typing import Any,Dict
import pyqtgraph as pg
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
class PyQtGraphWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.init_data()
self.init_ui()
def init_data(self):
self.color_line = (30, 144, 255)
self.color_scatter = (0,0,128)
self.color_star = (220,20,60)
self.color_hover = (0,191,255)
self.color_circle = (255,0,255)
self.color_cml = (0,128,128)
pass
def init_ui(self):
self.title_label = QtWidgets.QLabel('最小方差边界')
self.title_label.setAlignment(Qt.AlignCenter)
self.pw = pg.PlotWidget()
self.pw.setMouseEnabled(x=True, y=False)
# self.pw.enableAutoRange(x=False,y=True)
self.pw.setAutoVisible(x=False, y=True)
self.pw.setLabel('left', 'R')
self.pw.setLabel('bottom', 'Var')
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.title_label)
layout.addWidget(self.pw)
self.setLayout(layout)
pass
def set_data(self,data:Dict[str,Any]):
# 绘制最小方差边界
ef = data['ef']
gmvp = data['gmvp']
cml = data['cml']
cml_start = cml[0]
cml_end = cml[1]
x_var = ef['Var'].values.tolist()
y_r = ef['R'].values.tolist()
# 计算横轴覆盖点的半径
x_temp_min = ef['Var'].min()
x_temp_max = ef['Var'].max()
x_unique_len = len(ef['Var'].unique())
x_radius = (x_temp_max-x_temp_min)/(x_unique_len*2)
y_temp_min = ef['R'].min()
y_temp_max = ef['R'].max()
y_unique_len = len(ef['R'].unique())
y_radius = (y_temp_max - y_temp_min)/(y_unique_len*2)
self.cover_xy = []
self.center_circle = []
for x,y in zip(x_var,y_r):
self.center_circle.append([x,y])
self.cover_xy.append([[x-x_radius,x+x_radius],[y-y_radius,y+y_radius]])
font = QtGui.QFont()
font.setPixelSize(9)
self.label = pg.TextItem()
self.label.setFont(font)
self.label.setPos(x_var[0],y_r[0])
self.label.setZValue(-90)
self.pw.addItem(self.label)
self.pw.plot(x_var, y_r, connect='finite', pen=pg.mkPen({'color': self.color_line, 'width': 4}),symbol='o')
gmvp_targetItem = pg.TargetItem(
pos=gmvp,
movable=False,
size=30,
symbol='star',
pen=self.color_star,
brush=self.color_star,
label=f"GMVP:Var={gmvp[0]}\nR={gmvp[1]}",
labelOpts={'color':self.color_star}
)
self.pw.addItem(gmvp_targetItem)
# cml
cml_x = [cml_start[0],cml_end[0]]
cml_y = [cml_start[1],cml_end[1]]
cml_lr = pg.PlotCurveItem(x=cml_x,y=cml_y,pen=pg.mkPen({'color':self.color_cml,'width':2}),symbol='o')
self.pw.addItem(cml_lr)
cml_targetItem = pg.TargetItem(
pos=(cml_end[0],cml_end[1]),
movable=False,
size=30,
# symbol='star',
pen=self.color_cml,
brush=self.color_cml,
label=f"CML:Var={cml_end[0]}\nR={cml_end[1]}",
labelOpts={'color': self.color_cml}
)
self.pw.addItem(cml_targetItem)
self.current_point_targetItem = pg.TargetItem(
pos=(cml_end[0], cml_end[1]),
movable=False,
size=20,
symbol='o',
pen=self.color_circle,
brush=self.color_circle,
label=f"Var:{cml_end[0]}\nR:{cml_end[1]}",
labelOpts={'color': self.color_circle}
)
self.pw.addItem(self.current_point_targetItem)
self.vb = self.pw.getViewBox()
self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
self.proxy_clicked = pg.SignalProxy(self.pw.scene().sigMouseClicked,rateLimit=60, slot=self.mouseClicked)
self.pw.enableAutoRange()
pass
def mouseMoved(self,evt):
pos = evt[0]
if self.pw.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
cur_x = mousePoint.x()
cur_y = mousePoint.y()
# print(mousePoint.x(),mousePoint.y())
for xy_i,item in enumerate(self.cover_xy):
cur_x_radius = item[0]
cur_y_radius = item[1]
if cur_x >= cur_x_radius[0] and cur_x <= cur_x_radius[1]:
if cur_y >= cur_y_radius[0] and cur_y <= cur_y_radius[1]:
cur_center_circle = self.center_circle[xy_i]
self.label.setPos(cur_center_circle[0],cur_center_circle[1])
self.label.setText(text=f"Var:{cur_center_circle[0]}\nR:{cur_center_circle[1]}",color=self.color_line)
pass
pass
def mouseClicked(self,evt):
pos = evt[0].pos()
cur_x = pos[0]
cur_y = pos[1]
for xy_i, item in enumerate(self.cover_xy):
cur_x_radius = item[0]
cur_y_radius = item[1]
if cur_x >= cur_x_radius[0] and cur_x <= cur_x_radius[1]:
if cur_y >= cur_y_radius[0] and cur_y <= cur_y_radius[1]:
cur_center_circle = self.center_circle[xy_i]
self.current_point_targetItem.setPos(cur_center_circle[0], cur_center_circle[1])
self.current_point_targetItem.setLabel(text=f"Var:{cur_center_circle[0]}\nR:{cur_center_circle[1]}",labelOpts={'color': self.color_circle})
if self.pw.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
cur_x = mousePoint.x()
cur_y = mousePoint.y()
使用:
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
temp_csv = r'E:/temp000/ef.csv'
ef = pd.read_csv(temp_csv,encoding='utf-8')
pre_data = {
'ef':ef,
'gmvp': (0.2848851343955465, 0.0839279326985379),
'cml':[(0,0.0135),(0.39621410853251293, 0.17920659296170613)]
}
temp_w = PyQtGraphWidget()
temp_w.show()
temp_w.set_data(pre_data)
sys.exit(app.exec_())
pass
数据
ef.csv中的数据为
R | Var | -0.016004007 | 0.435932686 | -0.009190957 | 0.408593056 | -0.002377907 | 0.385133031 | 0.004435143 | 0.364447366 | 0.011248193 | 0.346697221 | 0.018061244 | 0.331717701 | 0.024874294 | 0.319874604 | 0.031687344 | 0.3115225 | 0.038500394 | 0.305240296 | 0.045313444 | 0.299729682 | 0.052126494 | 0.295033655 | 0.058939544 | 0.29119161 | 0.065752594 | 0.288237708 | 0.072565644 | 0.286199423 | 0.079378694 | 0.285095621 | 0.086191744 | 0.284938658 | 0.093004794 | 0.285728847 | 0.099817844 | 0.287459369 | 0.106630894 | 0.290112941 | 0.113443944 | 0.293664542 | 0.120256994 | 0.298463038 | 0.127070044 | 0.304887331 | 0.133883094 | 0.312838281 | 0.140696144 | 0.322202888 | 0.147509194 | 0.332861855 | 0.154322244 | 0.344695126 | 0.161135294 | 0.357586136 | 0.167948344 | 0.371424054 | 0.174761395 | 0.386108372 | 0.181574444 | 0.401902036 |
|