目录

效果:

代码:

使用:

数据


效果:

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
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐