首页 > 数据库 >基于Python3.11及SQL Server实现股票组合价值曲线相关计算分析

基于Python3.11及SQL Server实现股票组合价值曲线相关计算分析

时间:2024-06-14 10:01:33浏览次数:8  
标签:Python3.11 code df self value Server ui SQL date

     本文中Python的版本使用的是3.11,数据库使用的是SQL SERVER 2008,项目运行效果图如下:

蒙特卡洛相关:

突出风险最小点:

夏普比率相关

夏普比率无风险最大点

文章中的股票每日交易数据摘取自:英为财情 https://cn.investing.com/

蒙特卡洛及夏普相关计算参考【胖哥真不错】的一片csdn文章:Python对5支股票的投资组合进行分析_每天买入板块中股价最低5只股票python-CSDN博客

界面代码如下:

界面设计使用pyqt5design,设计界面如下图:

ui代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1116</width>
    <height>909</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QGroupBox" name="groupBox_2">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>140</y>
      <width>1111</width>
      <height>331</height>
     </rect>
    </property>
    <property name="title">
     <string>数据展示</string>
    </property>
    <widget class="QTableWidget" name="Dt_View">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>1091</width>
       <height>301</height>
      </rect>
     </property>
    </widget>
   </widget>
   <widget class="QTabWidget" name="tabWidget">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>470</y>
      <width>1111</width>
      <height>381</height>
     </rect>
    </property>
    <property name="currentIndex">
     <number>0</number>
    </property>
    <widget class="QWidget" name="tab">
     <attribute name="title">
      <string>条件筛选数据与行业第一股票组合相关</string>
     </attribute>
     <widget class="QGroupBox" name="groupBox_3">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>1101</width>
        <height>341</height>
       </rect>
      </property>
      <property name="title">
       <string>条件筛选</string>
      </property>
      <widget class="QListView" name="LV_Plate">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>20</y>
         <width>191</width>
         <height>301</height>
        </rect>
       </property>
      </widget>
      <widget class="QLabel" name="label_8">
       <property name="geometry">
        <rect>
         <x>260</x>
         <y>160</y>
         <width>72</width>
         <height>15</height>
        </rect>
       </property>
       <property name="text">
        <string>MOMENTUM:</string>
       </property>
      </widget>
      <widget class="QComboBox" name="cbox_momentum">
       <property name="geometry">
        <rect>
         <x>350</x>
         <y>160</y>
         <width>71</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QComboBox" name="cbox_profitability">
       <property name="geometry">
        <rect>
         <x>350</x>
         <y>120</y>
         <width>71</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QComboBox" name="cbox_esp">
       <property name="geometry">
        <rect>
         <x>350</x>
         <y>210</y>
         <width>71</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QComboBox" name="cbox_value">
       <property name="geometry">
        <rect>
         <x>350</x>
         <y>40</y>
         <width>71</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QLabel" name="label_9">
       <property name="geometry">
        <rect>
         <x>240</x>
         <y>210</y>
         <width>111</width>
         <height>16</height>
        </rect>
       </property>
       <property name="text">
        <string>EPSREVISION:</string>
       </property>
      </widget>
      <widget class="QLabel" name="label_10">
       <property name="geometry">
        <rect>
         <x>220</x>
         <y>120</y>
         <width>121</width>
         <height>16</height>
        </rect>
       </property>
       <property name="text">
        <string>PROFITABILITY:</string>
       </property>
      </widget>
      <widget class="QComboBox" name="cbox_growth">
       <property name="geometry">
        <rect>
         <x>350</x>
         <y>80</y>
         <width>71</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QLabel" name="label_11">
       <property name="geometry">
        <rect>
         <x>290</x>
         <y>40</y>
         <width>72</width>
         <height>15</height>
        </rect>
       </property>
       <property name="text">
        <string>VALUE:</string>
       </property>
      </widget>
      <widget class="QLabel" name="label_12">
       <property name="geometry">
        <rect>
         <x>280</x>
         <y>80</y>
         <width>72</width>
         <height>15</height>
        </rect>
       </property>
       <property name="text">
        <string>GROWTH:</string>
       </property>
      </widget>
      <widget class="QPushButton" name="pushButton">
       <property name="geometry">
        <rect>
         <x>440</x>
         <y>40</y>
         <width>171</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>条件筛选生成图表</string>
       </property>
      </widget>
      <widget class="QPushButton" name="export_megred_data">
       <property name="geometry">
        <rect>
         <x>440</x>
         <y>100</y>
         <width>171</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>导出本次图表数据</string>
       </property>
      </widget>
      <widget class="QTableWidget" name="tw_top_one_data">
       <property name="geometry">
        <rect>
         <x>610</x>
         <y>130</y>
         <width>481</width>
         <height>211</height>
        </rect>
       </property>
      </widget>
      <widget class="QPushButton" name="load_top_one_tickets_data">
       <property name="geometry">
        <rect>
         <x>620</x>
         <y>40</y>
         <width>221</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>加载行业第一市值股票数据</string>
       </property>
      </widget>
      <widget class="QPushButton" name="btn_draw_info">
       <property name="geometry">
        <rect>
         <x>850</x>
         <y>40</y>
         <width>221</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>行业第一市值与组合的图表</string>
       </property>
      </widget>
      <widget class="QPushButton" name="btn_export_top_one_and_portfolio">
       <property name="geometry">
        <rect>
         <x>860</x>
         <y>90</y>
         <width>211</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>导出第一市值与组合的数据</string>
       </property>
      </widget>
      <widget class="QPushButton" name="btn_top_one_and_select_option">
       <property name="geometry">
        <rect>
         <x>620</x>
         <y>90</y>
         <width>221</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>第一市值与条件筛选图表</string>
       </property>
      </widget>
     </widget>
    </widget>
    <widget class="QWidget" name="tab_2">
     <attribute name="title">
      <string>蒙特卡洛及夏普相关</string>
     </attribute>
     <widget class="QPushButton" name="btn_get_mtkl_data">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>10</y>
        <width>281</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>获取当前日期的股票每日收益率</string>
      </property>
     </widget>
     <widget class="QTableWidget" name="tw_mtkl_data">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>50</y>
        <width>421</width>
        <height>251</height>
       </rect>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_xie_fang_cha_ju_zhen">
      <property name="geometry">
       <rect>
        <x>440</x>
        <y>10</y>
        <width>171</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>斜方差矩阵</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_year_xie_fang_cha_ju_zhen">
      <property name="geometry">
       <rect>
        <x>770</x>
        <y>10</y>
        <width>171</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>年化斜方差矩阵</string>
      </property>
     </widget>
     <widget class="QTableWidget" name="tw_xie_fang_cha_ju_zhen">
      <property name="geometry">
       <rect>
        <x>440</x>
        <y>50</y>
        <width>331</width>
        <height>251</height>
       </rect>
      </property>
     </widget>
     <widget class="QTableWidget" name="tw_year_xie_fang_cha_ju_zhen">
      <property name="geometry">
       <rect>
        <x>780</x>
        <y>50</y>
        <width>311</width>
        <height>251</height>
       </rect>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_mtkl_points_view">
      <property name="geometry">
       <rect>
        <x>50</x>
        <y>310</y>
        <width>181</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>蒙特卡洛散点图</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_mtkl_min_point">
      <property name="geometry">
       <rect>
        <x>250</x>
        <y>310</y>
        <width>191</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>突出风险最小点</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_shap_point_view">
      <property name="geometry">
       <rect>
        <x>490</x>
        <y>310</y>
        <width>221</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>夏普比率</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_shap_point_max">
      <property name="geometry">
       <rect>
        <x>760</x>
        <y>310</y>
        <width>171</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>夏普比率最大点</string>
      </property>
     </widget>
    </widget>
   </widget>
   <widget class="QTabWidget" name="tabWidget_2">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>10</y>
      <width>1111</width>
      <height>131</height>
     </rect>
    </property>
    <property name="currentIndex">
     <number>0</number>
    </property>
    <widget class="QWidget" name="tab_4">
     <attribute name="title">
      <string>数据查询</string>
     </attribute>
     <widget class="QGroupBox" name="groupBox">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>10</y>
        <width>1101</width>
        <height>80</height>
       </rect>
      </property>
      <property name="title">
       <string>查询条件</string>
      </property>
      <widget class="QLabel" name="label">
       <property name="geometry">
        <rect>
         <x>20</x>
         <y>30</y>
         <width>72</width>
         <height>15</height>
        </rect>
       </property>
       <property name="text">
        <string>开始日期:</string>
       </property>
      </widget>
      <widget class="QLabel" name="label_2">
       <property name="geometry">
        <rect>
         <x>250</x>
         <y>30</y>
         <width>72</width>
         <height>15</height>
        </rect>
       </property>
       <property name="text">
        <string>结束日期:</string>
       </property>
      </widget>
      <widget class="QPushButton" name="Search_Data">
       <property name="geometry">
        <rect>
         <x>490</x>
         <y>30</y>
         <width>221</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>获取当前日期区间股票数据</string>
       </property>
      </widget>
      <widget class="QDateEdit" name="start_date">
       <property name="geometry">
        <rect>
         <x>100</x>
         <y>30</y>
         <width>141</width>
         <height>22</height>
        </rect>
       </property>
       <property name="dateTime">
        <datetime>
         <hour>0</hour>
         <minute>0</minute>
         <second>0</second>
         <year>2022</year>
         <month>1</month>
         <day>1</day>
        </datetime>
       </property>
       <property name="displayFormat">
        <string notr="true">yyyy-MM-dd</string>
       </property>
       <property name="calendarPopup">
        <bool>true</bool>
       </property>
      </widget>
      <widget class="QDateEdit" name="end_date">
       <property name="geometry">
        <rect>
         <x>340</x>
         <y>30</y>
         <width>141</width>
         <height>22</height>
        </rect>
       </property>
       <property name="dateTime">
        <datetime>
         <hour>0</hour>
         <minute>0</minute>
         <second>0</second>
         <year>2024</year>
         <month>5</month>
         <day>1</day>
        </datetime>
       </property>
       <property name="displayFormat">
        <string>yyyy-MM-dd</string>
       </property>
       <property name="calendarPopup">
        <bool>true</bool>
       </property>
       <property name="date">
        <date>
         <year>2024</year>
         <month>5</month>
         <day>1</day>
        </date>
       </property>
      </widget>
      <widget class="QPushButton" name="Search_Data_2">
       <property name="geometry">
        <rect>
         <x>720</x>
         <y>30</y>
         <width>131</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>组合价值曲线</string>
       </property>
      </widget>
      <widget class="QPushButton" name="btn_export_data">
       <property name="geometry">
        <rect>
         <x>880</x>
         <y>30</y>
         <width>141</width>
         <height>28</height>
        </rect>
       </property>
       <property name="text">
        <string>导出下表数据</string>
       </property>
      </widget>
     </widget>
    </widget>
    <widget class="QWidget" name="tab_5">
     <attribute name="title">
      <string>历史数据导入</string>
     </attribute>
     <widget class="QPushButton" name="btn_ticket_history_data">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>10</y>
        <width>261</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>组合股票历史数据导入</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_top_one_ticket_data">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>57</y>
        <width>261</width>
        <height>31</height>
       </rect>
      </property>
      <property name="text">
       <string>行业市值第一的股票历史数据导入</string>
      </property>
     </widget>
    </widget>
    <widget class="QWidget" name="tab_6">
     <attribute name="title">
      <string>未来数据获取</string>
     </attribute>
     <widget class="QPushButton" name="get_new_StockInfo">
      <property name="geometry">
       <rect>
        <x>190</x>
        <y>0</y>
        <width>151</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>获取最新股票数据</string>
      </property>
     </widget>
     <widget class="QPushButton" name="get_new_indexValue">
      <property name="geometry">
       <rect>
        <x>30</x>
        <y>0</y>
        <width>131</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>获取最新指数</string>
      </property>
     </widget>
     <widget class="QPushButton" name="btn_get_new_top_one_ticket_data">
      <property name="geometry">
       <rect>
        <x>360</x>
        <y>0</y>
        <width>281</width>
        <height>28</height>
       </rect>
      </property>
      <property name="text">
       <string>获取行业市值第一最新股票数据</string>
      </property>
     </widget>
    </widget>
   </widget>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1116</width>
     <height>26</height>
    </rect>
   </property>
   <property name="nativeMenuBar">
    <bool>false</bool>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

使用pychrm外部工具可将UI界面的xml可转换为.py文件

转换为MainForm.py代码如下:

# -*- coding: utf-8 -*-
from PyQt5.QtCore import QStringListModel

# Form implementation generated from reading ui file 'MainForm.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def __init__(self):
        self.df = None
        self.stockcode_df = None
        self.index_value_df = None
        self.portfolio_value_daily = None
        self.old_merged_df = None
        self.top_one_tickets_value_df = None
        self.top_one_portfolio_value = None
        self.top_one_portfolio_value_df = None
        self.stock_return = None
        self.xie_fang_cha = None
        self.year_xie_fang_cha = None
        self.randomp_ortfolios = None
        self.lv_model=QStringListModel()
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1116, 909)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(0, 140, 1111, 331))
        self.groupBox_2.setObjectName("groupBox_2")
        self.Dt_View = QtWidgets.QTableWidget(self.groupBox_2)
        self.Dt_View.setGeometry(QtCore.QRect(10, 20, 1091, 301))
        self.Dt_View.setObjectName("Dt_View")
        self.Dt_View.setColumnCount(0)
        self.Dt_View.setRowCount(0)
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(0, 470, 1111, 381))
        self.tabWidget.setObjectName("tabWidget")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.groupBox_3 = QtWidgets.QGroupBox(self.tab)
        self.groupBox_3.setGeometry(QtCore.QRect(0, 0, 1101, 341))
        self.groupBox_3.setObjectName("groupBox_3")
        self.LV_Plate = QtWidgets.QListView(self.groupBox_3)
        self.LV_Plate.setGeometry(QtCore.QRect(10, 20, 191, 301))
        self.LV_Plate.setObjectName("LV_Plate")
        self.label_8 = QtWidgets.QLabel(self.groupBox_3)
        self.label_8.setGeometry(QtCore.QRect(260, 160, 72, 15))
        self.label_8.setObjectName("label_8")
        self.cbox_momentum = QtWidgets.QComboBox(self.groupBox_3)
        self.cbox_momentum.setGeometry(QtCore.QRect(350, 160, 71, 22))
        self.cbox_momentum.setObjectName("cbox_momentum")
        self.cbox_profitability = QtWidgets.QComboBox(self.groupBox_3)
        self.cbox_profitability.setGeometry(QtCore.QRect(350, 120, 71, 22))
        self.cbox_profitability.setObjectName("cbox_profitability")
        self.cbox_esp = QtWidgets.QComboBox(self.groupBox_3)
        self.cbox_esp.setGeometry(QtCore.QRect(350, 210, 71, 22))
        self.cbox_esp.setObjectName("cbox_esp")
        self.cbox_value = QtWidgets.QComboBox(self.groupBox_3)
        self.cbox_value.setGeometry(QtCore.QRect(350, 40, 71, 22))
        self.cbox_value.setObjectName("cbox_value")
        self.label_9 = QtWidgets.QLabel(self.groupBox_3)
        self.label_9.setGeometry(QtCore.QRect(240, 210, 111, 16))
        self.label_9.setObjectName("label_9")
        self.label_10 = QtWidgets.QLabel(self.groupBox_3)
        self.label_10.setGeometry(QtCore.QRect(220, 120, 121, 16))
        self.label_10.setObjectName("label_10")
        self.cbox_growth = QtWidgets.QComboBox(self.groupBox_3)
        self.cbox_growth.setGeometry(QtCore.QRect(350, 80, 71, 22))
        self.cbox_growth.setObjectName("cbox_growth")
        self.label_11 = QtWidgets.QLabel(self.groupBox_3)
        self.label_11.setGeometry(QtCore.QRect(290, 40, 72, 15))
        self.label_11.setObjectName("label_11")
        self.label_12 = QtWidgets.QLabel(self.groupBox_3)
        self.label_12.setGeometry(QtCore.QRect(280, 80, 72, 15))
        self.label_12.setObjectName("label_12")
        self.pushButton = QtWidgets.QPushButton(self.groupBox_3)
        self.pushButton.setGeometry(QtCore.QRect(440, 40, 171, 28))
        self.pushButton.setObjectName("pushButton")
        self.export_megred_data = QtWidgets.QPushButton(self.groupBox_3)
        self.export_megred_data.setGeometry(QtCore.QRect(440, 100, 171, 28))
        self.export_megred_data.setObjectName("export_megred_data")
        self.tw_top_one_data = QtWidgets.QTableWidget(self.groupBox_3)
        self.tw_top_one_data.setGeometry(QtCore.QRect(610, 130, 481, 211))
        self.tw_top_one_data.setObjectName("tw_top_one_data")
        self.tw_top_one_data.setColumnCount(0)
        self.tw_top_one_data.setRowCount(0)
        self.load_top_one_tickets_data = QtWidgets.QPushButton(self.groupBox_3)
        self.load_top_one_tickets_data.setGeometry(QtCore.QRect(620, 40, 221, 28))
        self.load_top_one_tickets_data.setObjectName("load_top_one_tickets_data")
        self.btn_draw_info = QtWidgets.QPushButton(self.groupBox_3)
        self.btn_draw_info.setGeometry(QtCore.QRect(850, 40, 221, 28))
        self.btn_draw_info.setObjectName("btn_draw_info")
        self.btn_export_top_one_and_portfolio = QtWidgets.QPushButton(self.groupBox_3)
        self.btn_export_top_one_and_portfolio.setGeometry(QtCore.QRect(860, 90, 211, 28))
        self.btn_export_top_one_and_portfolio.setObjectName("btn_export_top_one_and_portfolio")
        self.btn_top_one_and_select_option = QtWidgets.QPushButton(self.groupBox_3)
        self.btn_top_one_and_select_option.setGeometry(QtCore.QRect(620, 90, 221, 28))
        self.btn_top_one_and_select_option.setObjectName("btn_top_one_and_select_option")
        self.tabWidget.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.btn_get_mtkl_data = QtWidgets.QPushButton(self.tab_2)
        self.btn_get_mtkl_data.setGeometry(QtCore.QRect(10, 10, 281, 28))
        self.btn_get_mtkl_data.setObjectName("btn_get_mtkl_data")
        self.tw_mtkl_data = QtWidgets.QTableWidget(self.tab_2)
        self.tw_mtkl_data.setGeometry(QtCore.QRect(10, 50, 421, 251))
        self.tw_mtkl_data.setObjectName("tw_mtkl_data")
        self.tw_mtkl_data.setColumnCount(0)
        self.tw_mtkl_data.setRowCount(0)
        self.btn_xie_fang_cha_ju_zhen = QtWidgets.QPushButton(self.tab_2)
        self.btn_xie_fang_cha_ju_zhen.setGeometry(QtCore.QRect(440, 10, 171, 28))
        self.btn_xie_fang_cha_ju_zhen.setObjectName("btn_xie_fang_cha_ju_zhen")
        self.btn_year_xie_fang_cha_ju_zhen = QtWidgets.QPushButton(self.tab_2)
        self.btn_year_xie_fang_cha_ju_zhen.setGeometry(QtCore.QRect(770, 10, 171, 28))
        self.btn_year_xie_fang_cha_ju_zhen.setObjectName("btn_year_xie_fang_cha_ju_zhen")
        self.tw_xie_fang_cha_ju_zhen = QtWidgets.QTableWidget(self.tab_2)
        self.tw_xie_fang_cha_ju_zhen.setGeometry(QtCore.QRect(440, 50, 331, 251))
        self.tw_xie_fang_cha_ju_zhen.setObjectName("tw_xie_fang_cha_ju_zhen")
        self.tw_xie_fang_cha_ju_zhen.setColumnCount(0)
        self.tw_xie_fang_cha_ju_zhen.setRowCount(0)
        self.tw_year_xie_fang_cha_ju_zhen = QtWidgets.QTableWidget(self.tab_2)
        self.tw_year_xie_fang_cha_ju_zhen.setGeometry(QtCore.QRect(780, 50, 311, 251))
        self.tw_year_xie_fang_cha_ju_zhen.setObjectName("tw_year_xie_fang_cha_ju_zhen")
        self.tw_year_xie_fang_cha_ju_zhen.setColumnCount(0)
        self.tw_year_xie_fang_cha_ju_zhen.setRowCount(0)
        self.btn_mtkl_points_view = QtWidgets.QPushButton(self.tab_2)
        self.btn_mtkl_points_view.setGeometry(QtCore.QRect(50, 310, 181, 28))
        self.btn_mtkl_points_view.setObjectName("btn_mtkl_points_view")
        self.btn_mtkl_min_point = QtWidgets.QPushButton(self.tab_2)
        self.btn_mtkl_min_point.setGeometry(QtCore.QRect(250, 310, 191, 28))
        self.btn_mtkl_min_point.setObjectName("btn_mtkl_min_point")
        self.btn_shap_point_view = QtWidgets.QPushButton(self.tab_2)
        self.btn_shap_point_view.setGeometry(QtCore.QRect(490, 310, 221, 28))
        self.btn_shap_point_view.setObjectName("btn_shap_point_view")
        self.btn_shap_point_max = QtWidgets.QPushButton(self.tab_2)
        self.btn_shap_point_max.setGeometry(QtCore.QRect(760, 310, 171, 28))
        self.btn_shap_point_max.setObjectName("btn_shap_point_max")
        self.tabWidget.addTab(self.tab_2, "")
        self.tabWidget_2 = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget_2.setGeometry(QtCore.QRect(0, 10, 1111, 131))
        self.tabWidget_2.setObjectName("tabWidget_2")
        self.tab_4 = QtWidgets.QWidget()
        self.tab_4.setObjectName("tab_4")
        self.groupBox = QtWidgets.QGroupBox(self.tab_4)
        self.groupBox.setGeometry(QtCore.QRect(0, 10, 1101, 80))
        self.groupBox.setObjectName("groupBox")
        self.label = QtWidgets.QLabel(self.groupBox)
        self.label.setGeometry(QtCore.QRect(20, 30, 72, 15))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setGeometry(QtCore.QRect(250, 30, 72, 15))
        self.label_2.setObjectName("label_2")
        self.Search_Data = QtWidgets.QPushButton(self.groupBox)
        self.Search_Data.setGeometry(QtCore.QRect(490, 30, 221, 28))
        self.Search_Data.setObjectName("Search_Data")
        self.start_date = QtWidgets.QDateEdit(self.groupBox)
        self.start_date.setGeometry(QtCore.QRect(100, 30, 141, 22))
        self.start_date.setDateTime(QtCore.QDateTime(QtCore.QDate(2022, 1, 1), QtCore.QTime(0, 0, 0)))
        self.start_date.setDisplayFormat("yyyy-MM-dd")
        self.start_date.setCalendarPopup(True)
        self.start_date.setObjectName("start_date")
        self.end_date = QtWidgets.QDateEdit(self.groupBox)
        self.end_date.setGeometry(QtCore.QRect(340, 30, 141, 22))
        self.end_date.setDateTime(QtCore.QDateTime(QtCore.QDate(2024, 5, 1), QtCore.QTime(0, 0, 0)))
        self.end_date.setCalendarPopup(True)
        self.end_date.setDate(QtCore.QDate(2024, 5, 1))
        self.end_date.setObjectName("end_date")
        self.Search_Data_2 = QtWidgets.QPushButton(self.groupBox)
        self.Search_Data_2.setGeometry(QtCore.QRect(720, 30, 131, 28))
        self.Search_Data_2.setObjectName("Search_Data_2")
        self.btn_export_data = QtWidgets.QPushButton(self.groupBox)
        self.btn_export_data.setGeometry(QtCore.QRect(880, 30, 141, 28))
        self.btn_export_data.setObjectName("btn_export_data")
        self.tabWidget_2.addTab(self.tab_4, "")
        self.tab_5 = QtWidgets.QWidget()
        self.tab_5.setObjectName("tab_5")
        self.btn_ticket_history_data = QtWidgets.QPushButton(self.tab_5)
        self.btn_ticket_history_data.setGeometry(QtCore.QRect(10, 10, 261, 28))
        self.btn_ticket_history_data.setObjectName("btn_ticket_history_data")
        self.btn_top_one_ticket_data = QtWidgets.QPushButton(self.tab_5)
        self.btn_top_one_ticket_data.setGeometry(QtCore.QRect(10, 57, 261, 31))
        self.btn_top_one_ticket_data.setObjectName("btn_top_one_ticket_data")
        self.tabWidget_2.addTab(self.tab_5, "")
        self.tab_6 = QtWidgets.QWidget()
        self.tab_6.setObjectName("tab_6")
        self.get_new_StockInfo = QtWidgets.QPushButton(self.tab_6)
        self.get_new_StockInfo.setGeometry(QtCore.QRect(190, 0, 151, 28))
        self.get_new_StockInfo.setObjectName("get_new_StockInfo")
        self.get_new_indexValue = QtWidgets.QPushButton(self.tab_6)
        self.get_new_indexValue.setGeometry(QtCore.QRect(30, 0, 131, 28))
        self.get_new_indexValue.setObjectName("get_new_indexValue")
        self.btn_get_new_top_one_ticket_data = QtWidgets.QPushButton(self.tab_6)
        self.btn_get_new_top_one_ticket_data.setGeometry(QtCore.QRect(360, 0, 281, 28))
        self.btn_get_new_top_one_ticket_data.setObjectName("btn_get_new_top_one_ticket_data")
        self.tabWidget_2.addTab(self.tab_6, "")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1116, 26))
        self.menubar.setNativeMenuBar(False)
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        self.tabWidget_2.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.groupBox_2.setTitle(_translate("MainWindow", "数据展示"))
        self.groupBox_3.setTitle(_translate("MainWindow", "条件筛选"))
        self.label_8.setText(_translate("MainWindow", "MOMENTUM:"))
        self.label_9.setText(_translate("MainWindow", "EPSREVISION:"))
        self.label_10.setText(_translate("MainWindow", "PROFITABILITY:"))
        self.label_11.setText(_translate("MainWindow", "VALUE:"))
        self.label_12.setText(_translate("MainWindow", "GROWTH:"))
        self.pushButton.setText(_translate("MainWindow", "条件筛选生成图表"))
        self.export_megred_data.setText(_translate("MainWindow", "导出本次图表数据"))
        self.load_top_one_tickets_data.setText(_translate("MainWindow", "加载行业第一市值股票数据"))
        self.btn_draw_info.setText(_translate("MainWindow", "行业第一市值与组合的图表"))
        self.btn_export_top_one_and_portfolio.setText(_translate("MainWindow", "导出第一市值与组合的数据"))
        self.btn_top_one_and_select_option.setText(_translate("MainWindow", "第一市值与条件筛选图表"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "条件筛选数据与行业第一股票组合相关"))
        self.btn_get_mtkl_data.setText(_translate("MainWindow", "获取当前日期的股票每日收益率"))
        self.btn_xie_fang_cha_ju_zhen.setText(_translate("MainWindow", "斜方差矩阵"))
        self.btn_year_xie_fang_cha_ju_zhen.setText(_translate("MainWindow", "年化斜方差矩阵"))
        self.btn_mtkl_points_view.setText(_translate("MainWindow", "蒙特卡洛散点图"))
        self.btn_mtkl_min_point.setText(_translate("MainWindow", "突出风险最小点"))
        self.btn_shap_point_view.setText(_translate("MainWindow", "夏普比率"))
        self.btn_shap_point_max.setText(_translate("MainWindow", "夏普比率最大点"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "蒙特卡洛及夏普相关"))
        self.groupBox.setTitle(_translate("MainWindow", "查询条件"))
        self.label.setText(_translate("MainWindow", "开始日期:"))
        self.label_2.setText(_translate("MainWindow", "结束日期:"))
        self.Search_Data.setText(_translate("MainWindow", "获取当前日期区间股票数据"))
        self.end_date.setDisplayFormat(_translate("MainWindow", "yyyy-MM-dd"))
        self.Search_Data_2.setText(_translate("MainWindow", "组合价值曲线"))
        self.btn_export_data.setText(_translate("MainWindow", "导出下表数据"))
        self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_4), _translate("MainWindow", "数据查询"))
        self.btn_ticket_history_data.setText(_translate("MainWindow", "组合股票历史数据导入"))
        self.btn_top_one_ticket_data.setText(_translate("MainWindow", "行业市值第一的股票历史数据导入"))
        self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_5), _translate("MainWindow", "历史数据导入"))
        self.get_new_StockInfo.setText(_translate("MainWindow", "获取最新股票数据"))
        self.get_new_indexValue.setText(_translate("MainWindow", "获取最新指数"))
        self.btn_get_new_top_one_ticket_data.setText(_translate("MainWindow", "获取行业市值第一最新股票数据"))
        self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_6), _translate("MainWindow", "未来数据获取"))

背后的数据库表如下:

TicketHistoryData(股票历史数据)

IndexValueHistoryData(指数历史数据)

Tickets(股票代码表)

数据库访问帮助:

import pyodbc
import pandas as pd


class MSSQL:
    def __init__(self, IP, UserID, Pwd, db):
        self.host = IP;
        self.user = UserID;
        self.password = Pwd;
        self.dbname = db;
    def __getConnect(self):
        if not self.dbname:
            raise (NameError, "db name undefine error")
        else:
            connSTR = "Driver={ODBC Driver 17 for SQL Server};SERVER=%s,1433;DATABASE=%s;UID=%s;PWD=%s" % (
            self.host, self.dbname, self.user, self.password)
            ##example: Driver={ODBC Driver 11 for SQL Server};SERVER=127.0.0.1,1433;DATABASE=MyTestDB;UID=sa;PWD=Abc123
            self.conn = pyodbc.connect(connSTR);
            cu = self.conn
        if not cu:
            raise (NameError, "db connect error");
        else:
            return cu;
    def ExecuteTableQuery(self, selectSql):
        cuu = self.__getConnect();
        selectRows = cuu.execute(selectSql);
        resList = selectRows.fetchall();
        self.conn.close();
        return resList;
    def ExecuteTableQueryHead(self,selectSql):
        connSTR = "Driver={ODBC Driver 17 for SQL Server};SERVER=%s,1433;DATABASE=%s;UID=%s;PWD=%s" % (
            self.host, self.dbname, self.user, self.password)
        conn =pyodbc.connect(connSTR)
        df=pd.read_sql(selectSql,conn)
        return df


        # 获取列名
        columns = [column[0] for column in cursor.description]
        # 将数据转换为DataFrame
        df = pd.DataFrame(cursor.fetchall())
        df.columns = columns

        # 关闭游标和连接
        cursor.close()
        conn.close()


        return df

    def ExecuteTableByProc(self,start_date,end_date):
        connSTR = "Driver={ODBC Driver 17 for SQL Server};SERVER=%s,1433;DATABASE=%s;UID=%s;PWD=%s" % (
            self.host, self.dbname, self.user, self.password)
        conn =pyodbc.connect(connSTR)
        #cursor=conn.cursor()

        sql="{CALL PIVOT_TicketsHisData (?, ?)}"
        # 读取数据到 Pandas DataFrame
        df = pd.read_sql_query(sql,params=(start_date,end_date),con=conn)  # 如果存储过程需要参数,这里需要传递参数列表



        # 关闭游标和连接
        #cursor.close()
        conn.close()


        return df


    def ExecuteNonQuery(self, sql):
        cuu = self.__getConnect();
        cuu.execute(sql);
        self.conn.commit();
        self.conn.close();

    def PrintODBCDrivers(self):
        print(pyodbc.drivers());

通用方法py文件




import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import DBHelper

import CommonHelper as common
import warnings
import configparser

warnings.filterwarnings('ignore', category=UserWarning)
warnings.filterwarnings('ignore', category=FutureWarning)

# 指定中文字体,例如使用微软雅黑
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 读取配置文件
configer = configparser.ConfigParser()

configer.read('config.ini')

Ip = configer.get('database','ip')


# 预定义数据库连接
db = DBHelper.MSSQL(IP=Ip, UserID="sa", Pwd="dj@1234", db="MGData")
# 初始投资额
initial_investment = 10000000
# 等级到数值的映射(你可以根据你的实际情况来调整这些值)
grade_to_value = {
    'A+': 6,
    'A': 5.5,
    'A-': 5,
    'B+': 4.5,
    'B': 4,
    'B-': 3.5,
    'C+': 3,
    'C': 2.5,
    'C-': 2,
    'D+': 1.5,
    'D': 1,
    'D-': 0.5,
    'E': 0
}


def select_index_value(start_date, end_date):
    """
    查询指数信息
    :param start_date: 开始日期
    :param end_date:  结束日期
    :return: 返回指数df
    """
    # 查询指数数据
    index_value_sql = (f"SELECT ExponentDate as date,isnull(DJI,0) as dji,isnull(NDX,0) as ndx,isnull(SPXINX,0) as inx "
                       f"FROM "
                       f"(  "
                       f"    SELECT ExponentDate, ExponentCode, ExponentADJClose  "
                       f"    FROM MG_ExponentHistoryData  "
                       f") AS SourceTable  "
                       f"PIVOT  "
                       f"(  "
                       f"    SUM(ExponentADJClose)  "
                       f"    FOR ExponentCode IN (DJI,NDX,SPXINX)  "
                       f") AS PivotTable "
                       f"where ExponentDate>='{start_date}' and ExponentDate<='{end_date}' order by ExponentDate asc")

    index_value_df = db.ExecuteTableQueryHead(index_value_sql)
    index_value_df = pd.DataFrame(index_value_df)
    index_value_df['date'] = pd.to_datetime(index_value_df['date'])
    index_value_df.set_index('date', inplace=True)
    return index_value_df


def select_stockcode_df(start_date, end_date):
    """
    查询股票代码及行业信息,其余指标信息
    :param start_date: 开始日期
    :param end_date:  结束日期
    :return: 返回stockcode_df
    """
    stockcode_sql = (f"select RTRIM(A.TicketCode) stockcode,B.PlateName,B.IndustryName,"
                     f"RTRIM(B.SValue) as SValue,RTRIM(B.GROWTH) as GROWTH,RTRIM(B.PROFITABILITY) as PROFITABILITY,"
                     f"RTRIM(B.MOMENTUM) as MOMENTUM,RTRIM(B.EPSREVISION) as EPSREVISION from "
                     f"(select distinct TicketCode from dbo.MG_TicketsHistoryData where "
                     f"TicketDate>='{start_date}' and TicketDate<='{end_date}' ) as A "
                     f"inner join MG_Tickets B on A.TicketCode=B.TicketCode order by A.TicketCode")

    data_stockcode = db.ExecuteTableQueryHead(stockcode_sql)
    stockcode_df = pd.DataFrame(data_stockcode)
    return stockcode_df


def select_stockcode_df_ex(stockcode_df):
    """
    等级映射方法
    :param stockcode_df:
    :return:
    """
    stockcode_df['SValue_grade'] = stockcode_df['SValue'].map(grade_to_value)
    stockcode_df['GROWTH_grade'] = stockcode_df['GROWTH'].map(grade_to_value)
    stockcode_df['PROFITABILITY_grade'] = stockcode_df['PROFITABILITY'].map(grade_to_value)
    stockcode_df['MOMENTUM_grade'] = stockcode_df['MOMENTUM'].map(grade_to_value)
    stockcode_df['EPSREVISION_grade'] = stockcode_df['EPSREVISION'].map(grade_to_value)
    return stockcode_df


def select_df(start_date, end_date):
    """
    计算组合价值
    :param start_date:
    :param end_date:
    :return:
    """
    # 查询数据库股票的数据:
    data_sql = (
        f"select T1.TicketDate as date,RTRIM(T1.TicketCode) as stockcode ,T1.TicketADJClose as price,T2.PlateName,"
        f"T2.IndustryName,T2.SValue,T2.GROWTH,T2.PROFITABILITY,T2.MOMENTUM,T2.EPSREVISION "
        f"from MG_TicketsHistoryData T1 inner join MG_Tickets T2 on T1.TicketCode=T2.TicketCode "
        f"where TicketDate>='{start_date}' and TicketDate<='{end_date}' order by TicketDate asc")
    data = db.ExecuteTableQueryHead(data_sql)
    df = pd.DataFrame(data)

    df['date'] = pd.to_datetime(df['date'])
    df = df.sort_values(by='date')
    return df


def select_portfolio_value(df):
    portfolio_value_daily = common.Calc_Portfolio(initial_investment=initial_investment, df=df)
    return portfolio_value_daily


def merge_index_value_and_portfolio_value(index_value_df, portfolio_value_daily):
    """
    返回指数与组合价值的组合表
    :param index_value_df:
    :param portfolio_value_daily:
    :return:
    """
    # 组合价值与指数的数据组合
    # df_pf_inx=common.return_df_value_index(index_value_df,portfolio_value_daily)
    df_pf_inx = index_value_df  # 指数时间序列
    pf_df = portfolio_value_daily[['date', 'portfolio_value']]  # 组合时间序列
    df_pf_inx = pd.merge(df_pf_inx, pf_df, on='date', how='left')  # 将指数,组合时间序列合并
    df_pf_inx = df_pf_inx.dropna()  # 删除有空值的行
    df_pf_inx.set_index('date', inplace=True)  # 设置date为索引

    return df_pf_inx


def draw_portfolio_value(df_pf_inx):
    common.Draw_plt(df_pf_inx, "股票组合价值及指数时间序列图")


def select_plate(start_date, end_date):
    """
    查询当前日期区间的股票板块信息
    :param start_date: 开始日期
    :param end_date: 结束日期
    :return: 返回plate_df
    """
    plate_sql = f"select PlateName from dbo.MG_Tickets group by PlateName"
    data_plate = db.ExecuteTableQueryHead(plate_sql)
    plate_df = pd.DataFrame(data_plate)
    return plate_df


def selct_data_by_input(df, stockcode_df, merged_df, plates, value, growth, profitability, momentum, eps):
    input_plate_list = []
    if plates is not None:
        input_plate_list = plates.split(',')
    df_plate = pd.DataFrame()  # 板块筛选的数据
    df_value = pd.DataFrame()  # value筛选的数据
    df_growth = pd.DataFrame()  # growth筛选的数据
    df_profitability = pd.DataFrame()  # profitability筛选的数据
    df_momentum = pd.DataFrame()  # momentum值筛选的数据
    df_eps = pd.DataFrame()  # eps值筛选的数据
    merged_df = merged_df
    df_input_flag = df
    code_df = stockcode_df
    if len(input_plate_list) > 0:  # 根据所属板块筛选数据
        code_df = code_df[code_df['PlateName'].isin(input_plate_list)]
        code_list = code_df.get('stockcode')

        if len(input_plate_list) > 1:
            for pl in input_plate_list:  # 将每一个板块对应的数据添加到df中
                code_df_pl = code_df[code_df['PlateName'] == pl]
                if len(code_df_pl) > 0:
                    code_list_pl = code_df_pl.get('stockcode')
                    condition_plat2 = df['stockcode'].isin(code_list_pl)
                    df_plate = df[condition_plat2]
                    df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                                     df=df_plate)
                    df_plate.rename(columns={'portfolio_value': 'portfolio_plateis' + pl},
                                    inplace=True)
                    df_plate = df_plate[['date', 'portfolio_plateis' + pl]]
                    merged_df = pd.merge(merged_df, df_plate, on='date', how='left')  # 合并每一个板块数据

            condition_plate = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_plate]
            condition_plate2 = df['stockcode'].isin(code_list)
            df_plate = df[condition_plate2]
            df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                             df=df_plate)

            df_plate.rename(columns={'portfolio_value': 'portfolio_plate' + plates.replace(',', '')},
                            inplace=True)

            df_plate = df_plate[['date', 'portfolio_plate' + plates.replace(',', '')]]

            merged_df = pd.merge(merged_df, df_plate, on='date', how='left')
        else:
            if len(code_list) > 0:
                condition_plate = df_input_flag['stockcode'].isin(code_list)
                df_input_flag = df_input_flag[condition_plate]
                condition_plate2 = df['stockcode'].isin(code_list)
                df_plate = df[condition_plate2]
                df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                                 df=df_plate)

                df_plate.rename(columns={'portfolio_value': 'portfolio_plate' + plates.replace(',', '')},
                                inplace=True)

                df_plate = df_plate[['date', 'portfolio_plate' + plates.replace(',', '')]]

                merged_df = pd.merge(merged_df, df_plate, on='date', how='left')

    if len(value) > 0:  # 根据value值筛选数据
        int_value = float(grade_to_value[value])
        code_df_value = code_df.copy()
        code_df_value = code_df_value[code_df_value['SValue_grade'] >= int_value]
        code_list = code_df_value.get('stockcode')
        if len(code_list) > 0:
            condition_value = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_value]
            df_value = df.copy()
            condition_value2 = df_value['stockcode'].isin(code_list)
            df_value = df_value[condition_value2]
            df_value = common.Calc_Portfolio(initial_investment=initial_investment,
                                             df=df_value)

            df_value.rename(columns={'portfolio_value': 'portfolio_svalue' + value},
                            inplace=True)
            df_value = df_value[['date', 'portfolio_svalue' + value]]

            merged_df = pd.merge(merged_df, df_value, on='date', how='left')

    if len(growth) > 0:  # 根据growth值筛选数据
        int_growth = float(grade_to_value[growth])
        code_df_growth = code_df.copy()
        code_df_growth = code_df_growth[code_df_growth['GROWTH_grade'] >= int_growth]
        code_list = code_df_growth.get('stockcode')
        if len(code_list) > 0:
            condition_growth = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_growth]
            df_growth = df.copy()
            condition_growth2 = df_growth['stockcode'].isin(code_list)
            df_growth = df_growth[condition_growth2]
            df_growth = common.Calc_Portfolio(initial_investment=initial_investment,
                                              df=df_growth)

            df_growth.rename(columns={'portfolio_value': 'portfolio_growth' + growth},
                             inplace=True)
            df_growth = df_growth[['date', 'portfolio_growth' + growth]]

            merged_df = pd.merge(merged_df, df_growth, on='date', how='left')
    if len(profitability) > 0:  # 根据PROFITABILITY_grade值筛选数据 MOMENTUM_grade
        int_profitability = float(grade_to_value[profitability])
        code_df_profitability = code_df.copy()
        code_df_profitability = code_df_profitability[code_df_profitability['PROFITABILITY_grade'] >= int_profitability]
        code_list = code_df_profitability.get('stockcode')
        if len(code_list) > 0:
            condition_profitability = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_profitability]
            df_profitability = df.copy()
            condition_profitability2 = df_profitability['stockcode'].isin(code_list)
            df_profitability = df_profitability[condition_profitability2]
            df_profitability = common.Calc_Portfolio(initial_investment=initial_investment,
                                                     df=df_profitability)

            df_profitability.rename(
                columns={'portfolio_value': 'portfolio_profitability' + profitability},
                inplace=True)
            df_profitability = df_profitability[
                ['date', 'portfolio_profitability' + profitability]]
            merged_df = pd.merge(merged_df, df_profitability, on='date', how='left')
    if len(momentum) > 0:  # 根据MOMENTUM_grade值筛选数据
        int_momentum = float(grade_to_value[momentum])
        code_df_momentum = code_df.copy()
        code_df_momentum = code_df_momentum[code_df_momentum['MOMENTUM_grade'] >= int_momentum]
        code_list = code_df_momentum.get('stockcode')
        if len(code_list) > 0:
            condition_momentum = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_momentum]
            df_momentum = df.copy()
            condition_momentum2 = df_momentum['stockcode'].isin(code_list)
            df_momentum = df_momentum[condition_momentum2]
            df_momentum = common.Calc_Portfolio(initial_investment=initial_investment,
                                                df=df_momentum)

            df_momentum.rename(
                columns={'portfolio_value': 'portfolio_momentum' + momentum},
                inplace=True)
            df_momentum = df_momentum[['date', 'portfolio_momentum' + momentum]]
            merged_df = pd.merge(merged_df, df_momentum, on='date', how='left')
    if len(eps) > 0:  # 根据EPSREVISION_grade值筛选数据
        int_eps_revision = float(grade_to_value[eps])
        code_df_eps = code_df.copy()
        code_df_eps = code_df_eps[code_df_eps['EPSREVISION_grade'] >= int_eps_revision]
        code_list = code_df_eps.get('stockcode')
        if len(code_list) > 0:
            condition_eps_revision = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_eps_revision]
            df_eps = df.copy()
            condition_eps_revision2 = df_eps['stockcode'].isin(code_list)
            df_eps = df_eps[condition_eps_revision2]
            df_eps = common.Calc_Portfolio(initial_investment=initial_investment,
                                           df=df_eps)

            df_eps.rename(
                columns={'portfolio_value': 'portfolio_eps' + eps},
                inplace=True)
            df_eps = df_eps[['date', 'portfolio_eps' + eps]]

            merged_df = pd.merge(merged_df, df_eps, on='date', how='left')

    portfolio_value_daily_flag = common.Calc_Portfolio(initial_investment=initial_investment,
                                                       df=df_input_flag)

    if len(portfolio_value_daily_flag) > 0:
        portfolio_value_daily_flag = portfolio_value_daily_flag.rename(
            columns={'portfolio_value': 'portfolio_value多条件筛选'})
        portfolio_value_daily_flag = portfolio_value_daily_flag[['date', 'portfolio_value多条件筛选']]
        merged_df = pd.merge(merged_df, portfolio_value_daily_flag, on='date', how='left')

    old_merged_df = merged_df.copy()

    # 创建一个集合来存储不重复的列名
    unique_cols = set()

    # 遍历所有列,检查是否已存在数值上完全相同的列
    for col in merged_df.columns:
        if not any(merged_df[col].equals(merged_df[other_col]) for other_col in unique_cols):
            unique_cols.add(col)

    # 对列名进行排序
    unique_cols = sorted(unique_cols)
    # 创建一个新的数据框,只包含不重复的列
    merged_df = merged_df[list(unique_cols)]

    merged_df.set_index('date', inplace=True)


    # 绘制指定日期区间内的组合价值及随机组合的价值对应的时间序列图
    common.Draw_plt(merged_df, "股票组合价值时间序列图")

    return old_merged_df

def selct_data_by_input_and_top_one(df, stockcode_df, merged_df, plates, value, growth, profitability, momentum, eps,top_one):
    input_plate_list = []
    if plates is not None:
        input_plate_list = plates.split(',')
    df_plate = pd.DataFrame()  # 板块筛选的数据
    df_value = pd.DataFrame()  # value筛选的数据
    df_growth = pd.DataFrame()  # growth筛选的数据
    df_profitability = pd.DataFrame()  # profitability筛选的数据
    df_momentum = pd.DataFrame()  # momentum值筛选的数据
    df_eps = pd.DataFrame()  # eps值筛选的数据
    merged_df = merged_df
    df_input_flag = df
    code_df = stockcode_df
    if len(input_plate_list) > 0:  # 根据所属板块筛选数据
        code_df = code_df[code_df['PlateName'].isin(input_plate_list)]
        code_list = code_df.get('stockcode')

        if len(input_plate_list) > 1:
            for pl in input_plate_list:  # 将每一个板块对应的数据添加到df中
                code_df_pl = code_df[code_df['PlateName'] == pl]
                if len(code_df_pl) > 0:
                    code_list_pl = code_df_pl.get('stockcode')
                    condition_plat2 = df['stockcode'].isin(code_list_pl)
                    df_plate = df[condition_plat2]
                    df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                                     df=df_plate)
                    df_plate.rename(columns={'portfolio_value': 'portfolio_plateis' + pl},
                                    inplace=True)
                    df_plate = df_plate[['date', 'portfolio_plateis' + pl]]
                    merged_df = pd.merge(merged_df, df_plate, on='date', how='left')  # 合并每一个板块数据

            condition_plate = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_plate]
            condition_plate2 = df['stockcode'].isin(code_list)
            df_plate = df[condition_plate2]
            df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                             df=df_plate)

            df_plate.rename(columns={'portfolio_value': 'portfolio_plate' + plates.replace(',', '')},
                            inplace=True)

            df_plate = df_plate[['date', 'portfolio_plate' + plates.replace(',', '')]]

            merged_df = pd.merge(merged_df, df_plate, on='date', how='left')
        else:
            if len(code_list) > 0:
                condition_plate = df_input_flag['stockcode'].isin(code_list)
                df_input_flag = df_input_flag[condition_plate]
                condition_plate2 = df['stockcode'].isin(code_list)
                df_plate = df[condition_plate2]
                df_plate = common.Calc_Portfolio(initial_investment=initial_investment,
                                                 df=df_plate)

                df_plate.rename(columns={'portfolio_value': 'portfolio_plate' + plates.replace(',', '')},
                                inplace=True)

                df_plate = df_plate[['date', 'portfolio_plate' + plates.replace(',', '')]]

                merged_df = pd.merge(merged_df, df_plate, on='date', how='left')

    if len(value) > 0:  # 根据value值筛选数据
        int_value = float(grade_to_value[value])
        code_df_value = code_df.copy()
        code_df_value = code_df_value[code_df_value['SValue_grade'] >= int_value]
        code_list = code_df_value.get('stockcode')
        if len(code_list) > 0:
            condition_value = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_value]
            df_value = df.copy()
            condition_value2 = df_value['stockcode'].isin(code_list)
            df_value = df_value[condition_value2]
            df_value = common.Calc_Portfolio(initial_investment=initial_investment,
                                             df=df_value)

            df_value.rename(columns={'portfolio_value': 'portfolio_svalue' + value},
                            inplace=True)
            df_value = df_value[['date', 'portfolio_svalue' + value]]

            merged_df = pd.merge(merged_df, df_value, on='date', how='left')

    if len(growth) > 0:  # 根据growth值筛选数据
        int_growth = float(grade_to_value[growth])
        code_df_growth = code_df.copy()
        code_df_growth = code_df_growth[code_df_growth['GROWTH_grade'] >= int_growth]
        code_list = code_df_growth.get('stockcode')
        if len(code_list) > 0:
            condition_growth = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_growth]
            df_growth = df.copy()
            condition_growth2 = df_growth['stockcode'].isin(code_list)
            df_growth = df_growth[condition_growth2]
            df_growth = common.Calc_Portfolio(initial_investment=initial_investment,
                                              df=df_growth)

            df_growth.rename(columns={'portfolio_value': 'portfolio_growth' + growth},
                             inplace=True)
            df_growth = df_growth[['date', 'portfolio_growth' + growth]]

            merged_df = pd.merge(merged_df, df_growth, on='date', how='left')
    if len(profitability) > 0:  # 根据PROFITABILITY_grade值筛选数据 MOMENTUM_grade
        int_profitability = float(grade_to_value[profitability])
        code_df_profitability = code_df.copy()
        code_df_profitability = code_df_profitability[code_df_profitability['PROFITABILITY_grade'] >= int_profitability]
        code_list = code_df_profitability.get('stockcode')
        if len(code_list) > 0:
            condition_profitability = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_profitability]
            df_profitability = df.copy()
            condition_profitability2 = df_profitability['stockcode'].isin(code_list)
            df_profitability = df_profitability[condition_profitability2]
            df_profitability = common.Calc_Portfolio(initial_investment=initial_investment,
                                                     df=df_profitability)

            df_profitability.rename(
                columns={'portfolio_value': 'portfolio_profitability' + profitability},
                inplace=True)
            df_profitability = df_profitability[
                ['date', 'portfolio_profitability' + profitability]]
            merged_df = pd.merge(merged_df, df_profitability, on='date', how='left')
    if len(momentum) > 0:  # 根据MOMENTUM_grade值筛选数据
        int_momentum = float(grade_to_value[momentum])
        code_df_momentum = code_df.copy()
        code_df_momentum = code_df_momentum[code_df_momentum['MOMENTUM_grade'] >= int_momentum]
        code_list = code_df_momentum.get('stockcode')
        if len(code_list) > 0:
            condition_momentum = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_momentum]
            df_momentum = df.copy()
            condition_momentum2 = df_momentum['stockcode'].isin(code_list)
            df_momentum = df_momentum[condition_momentum2]
            df_momentum = common.Calc_Portfolio(initial_investment=initial_investment,
                                                df=df_momentum)

            df_momentum.rename(
                columns={'portfolio_value': 'portfolio_momentum' + momentum},
                inplace=True)
            df_momentum = df_momentum[['date', 'portfolio_momentum' + momentum]]
            merged_df = pd.merge(merged_df, df_momentum, on='date', how='left')
    if len(eps) > 0:  # 根据EPSREVISION_grade值筛选数据
        int_eps_revision = float(grade_to_value[eps])
        code_df_eps = code_df.copy()
        code_df_eps = code_df_eps[code_df_eps['EPSREVISION_grade'] >= int_eps_revision]
        code_list = code_df_eps.get('stockcode')
        if len(code_list) > 0:
            condition_eps_revision = df_input_flag['stockcode'].isin(code_list)
            df_input_flag = df_input_flag[condition_eps_revision]
            df_eps = df.copy()
            condition_eps_revision2 = df_eps['stockcode'].isin(code_list)
            df_eps = df_eps[condition_eps_revision2]
            df_eps = common.Calc_Portfolio(initial_investment=initial_investment,
                                           df=df_eps)

            df_eps.rename(
                columns={'portfolio_value': 'portfolio_eps' + eps},
                inplace=True)
            df_eps = df_eps[['date', 'portfolio_eps' + eps]]

            merged_df = pd.merge(merged_df, df_eps, on='date', how='left')



    if len(top_one)>0:
        merged_df = pd.merge(merged_df,top_one,on='date',how='left')


    # 创建一个集合来存储不重复的列名
    unique_cols = set()

    # 遍历所有列,检查是否已存在数值上完全相同的列
    for col in merged_df.columns:
        if not any(merged_df[col].equals(merged_df[other_col]) for other_col in unique_cols):
            unique_cols.add(col)

    # 对列名进行排序
    unique_cols = sorted(unique_cols)
    # 创建一个新的数据框,只包含不重复的列
    merged_df = merged_df[list(unique_cols)]

    merged_df.set_index('date', inplace=True)


    # 绘制指定日期区间内的组合价值及随机组合的价值对应的时间序列图
    common.Draw_plt(merged_df, "股票组合价值时间序列图")



def get_top_one_tickets_data(start_date,end_date):
    """
        查询行业市值第一的历史股票价值
        :param start_date:
        :param end_date:
        :return:
        """
    # 查询数据库股票的数据:
    data_sql = (
        f"select T1.TicketDate as date,RTRIM(T1.TicketCode) as stockcode ,T1.TicketADJClose as price "
        f"from MG_TopOneTicketsHistoryData T1 inner join MG_TopOneTickets T2 on T1.TicketCode=T2.TicketCode "
        f"where TicketDate>='{start_date}' and TicketDate<='{end_date}' order by TicketDate asc")
    data = db.ExecuteTableQueryHead(data_sql)
    top_one_df = pd.DataFrame(data)

    top_one_df['date'] = pd.to_datetime(top_one_df['date'])
    top_one_df = top_one_df.sort_values(by='date')
    return top_one_df


def select_top_one_stockcode_df(start_date, end_date):
    """
    查询股票代码及行业信息
    :param start_date: 开始日期
    :param end_date:  结束日期
    :return: 返回top_one_stockcode_df
    """
    stockcode_sql = (f"select RTRIM(A.TicketCode) stockcode,B.Description,B.IndustryName from "
                     f"(select distinct TicketCode from dbo.MG_TopOneTicketsHistoryData where "
                     f"TicketDate>='{start_date}' and TicketDate<='{end_date}' ) as A "
                     f"inner join MG_TopOneTickets B on A.TicketCode=B.TicketCode order by A.TicketCode")

    data_stockcode = db.ExecuteTableQueryHead(stockcode_sql)
    top_one_stockcode_df = pd.DataFrame(data_stockcode)
    return top_one_stockcode_df


def calc_top_one_portfilo_value(top_one_tickets_value_df):
    """
    计算行业市值第一对应的组合价值
    :param top_one_tickets_df:
    :return:
    """
    #top_one_portfilo_value = common.Calc_Portfolio(initial_investment=initial_investment,df=top_one_tickets_value_df)
    top_one_portfilo_value = select_portfolio_value(top_one_tickets_value_df)
    return top_one_portfilo_value


def get_mtkl_data(start_date,end_date):
    mtklData = common.get_mengtekaluo_data(start_date, end_date)

    stockPrice = pd.DataFrame(mtklData)
    stockPrice['date'] = pd.to_datetime(stockPrice['date'])
    # 按照日期排序(如果数据已经是按日期排序的,可以跳过此步骤)
    stockPrice = stockPrice.sort_values(by='date')
    return stockPrice

def calc_stock_price(stockPrice):
    StockReturns = stockPrice.set_index('date').pct_change().dropna() + 1

    stock_return = StockReturns.copy()

    # 替换inf为NaN
    stock_return.replace([np.inf, -np.inf], np.nan, inplace=True)

    # 删除包含NaN的列
    stock_return.dropna(axis=1, how='all', inplace=True)

    return stock_return

def calc_xie_fang_cha(stock_return):
    """
    计算斜方差
    :param stock_return:
    :return:  返回斜方差
    """
    # 计算协方差矩阵
    cov_mat = stock_return.dropna().cov()

    cov_mat=cov_mat.dropna()
    return cov_mat

def calc_year_xie_fang_cha(cov_mat):
    """
    计算年化斜方差
    :param cov_mat: 斜方差
    :return:  返回年化斜方差
    """
    # 年化协方差矩阵
    cov_mat_annual = cov_mat * 252
    return cov_mat_annual

def calc_mengtekaluo_data(stock_return,cov_mat_annual,ticker_list,number=10000):
    '''
    计算蒙特卡洛模型图
    :param stock_return:
    :param cov_mat_annual:
    :param ticker_list:
    :return:
    '''
    # 设置模拟的次数
    number = number
    # 设置空的numpy数组,用于存储每次模拟得到的权重、收益率和标准差
    random_p = np.empty((number, len(ticker_list)+2))
    # 设置随机数种子,这里是为了结果可重复
    np.random.seed(len(ticker_list)+2)

    # 循环模拟10000次随机的投资组合
    for i in range(number):
        # 生成股票列表数量对应的个随机数,并归一化,得到一组随机的权重数据
        random5 = np.random.random(len(ticker_list))
        random_weight = random5 / np.sum(random5)

        # 计算年平均收益率
        mean_return = stock_return.mul(random_weight, axis=1).sum(axis=1).mean()
        annual_return = (1 + mean_return) ** 252 - 1

        # 计算年化标准差,也成为波动率
        random_volatility = np.sqrt(np.dot(random_weight.T, np.dot(cov_mat_annual, random_weight)))

        # 将上面生成的权重,和计算得到的收益率、标准差存入数组random_p中
        random_p[i][:len(ticker_list)] = random_weight
        random_p[i][len(ticker_list)] = annual_return
        random_p[i][len(ticker_list)+1] = random_volatility

    # 将Numpy数组转化为DataF数据框
    RandomPortfolios = pd.DataFrame(random_p)
    # 设置数据框RandomPortfolios每一列的名称
    RandomPortfolios.columns = [ticker + '_weight' for ticker in ticker_list] + ['Returns', 'Volatility']

    return RandomPortfolios

def draw_mtkl_point_view(randomPortfolios):
    # 绘制散点图
    randomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3)
    plt.show()

def draw_mtkl_point_min_index_view(randomPortfolios):
    # 找到标准差最小数据的索引值
    min_index = randomPortfolios.Volatility.idxmin()

    # 在收益-风险散点图中突出风险最小的点
    randomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3)
    x = randomPortfolios.loc[min_index, 'Volatility']
    y = randomPortfolios.loc[min_index, 'Returns']
    plt.scatter(x, y, color='red')
    # 将该点坐标显示在图中并保留四位小数
    plt.text(np.round(x, 4), np.round(y, 4), (np.round(x, 4), np.round(y, 4)), ha='left', va='bottom', fontsize=10)
    plt.show()

def draw_shap_point_view(randomPortfolios):
    #####夏普比率相关#######
    # 设置无风险回报率为0
    risk_free = 0
    # 计算每项资产的夏普比率
    randomPortfolios['Sharpe'] = (randomPortfolios.Returns - risk_free) / randomPortfolios.Volatility
    # 绘制收益-标准差的散点图,并用颜色描绘夏普比率
    plt.scatter(randomPortfolios.Volatility, randomPortfolios.Returns, c=randomPortfolios.Sharpe)
    plt.colorbar(label='Sharpe Ratio')
    plt.show()

def draw_shap_point_max_index_view(randomPortfolios):
    # 找到夏普比率最大数据对应的索引值
    max_index = randomPortfolios['Sharpe'].idxmax()
    # 在收益-风险散点图中突出夏普比率最大的点
    randomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3)
    x = randomPortfolios.loc[max_index, 'Volatility']
    y = randomPortfolios.loc[max_index, 'Returns']
    plt.scatter(x, y, color='red')
    # 将该点坐标显示在图中并保留四位小数
    plt.text(np.round(x, 4), np.round(y, 4), (np.round(x, 4), np.round(y, 4)), ha='left', va='bottom', fontsize=10)
    plt.show()

主程序的相关代码:

import datetime

from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QStringListModel, QDate

from MainForm import Ui_MainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QAbstractItemView, QWidget, QMessageBox, \
    QFileDialog
from PyQt5.QtGui import QFont
import pandas as pd
import CalcInint as calc
import SpyData as spydata
import ReadCvsData as readCvsTicketsData



class WorkerSignals(QObject):
    # 定义一个信号来传递 DataFrame
    df_ready = pyqtSignal(pd.DataFrame)


class SelectDataWorker(QThread):
    def __init__(self, start_date, end_date, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.start_date = start_date
        self.end_date = end_date
        self.signal = WorkerSignals()

    def run(self):
        start_date = self.start_date
        end_date = self.end_date
        # 在这里执行后台操作
        df = calc.select_stockcode_df(start_date, end_date)
        df = calc.select_stockcode_df_ex(df)

        self.signal.df_ready.emit(df)  # 发出完成信号


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()  # 创建一个 Ui_MainWindow 实例
        self.ui.setupUi(self)  # 初始化界面,将控件设置到 MyMainWindow 上

        # 给相应的控件附加初始值
        items = ['', 'A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'E']
        self.ui.cbox_value.addItems(items)
        self.ui.cbox_growth.addItems(items)
        self.ui.cbox_profitability.addItems(items)
        self.ui.cbox_momentum.addItems(items)
        self.ui.cbox_esp.addItems(items)

        current_date=QDate.currentDate()

        self.ui.end_date.setDate(current_date)

        # 设置相关控件的属性
        self.ui.LV_Plate.setSelectionMode(QAbstractItemView.MultiSelection)  # 设置list_view可多选
        self.ui.pushButton.setEnabled(False)
        self.ui.Search_Data_2.setEnabled(False)
        self.ui.btn_export_data.setEnabled(False)
        self.ui.export_megred_data.setEnabled(False)
        self.ui.btn_draw_info.setEnabled(False)
        self.ui.btn_export_top_one_and_portfolio.setEnabled(False)
        self.ui.btn_xie_fang_cha_ju_zhen.setEnabled(False)
        self.ui.btn_year_xie_fang_cha_ju_zhen.setEnabled(False)
        self.ui.btn_mtkl_points_view.setEnabled(False)
        self.ui.btn_mtkl_min_point.setEnabled(False)
        self.ui.btn_shap_point_view.setEnabled(False)
        self.ui.btn_shap_point_max.setEnabled(False)
        self.ui.btn_shap_point_view.setEnabled(False)
        self.ui.btn_shap_point_max.setEnabled(False)
        self.ui.btn_get_mtkl_data.setEnabled(False)
        self.ui.btn_top_one_and_select_option.setEnabled(False)
        self.ui.load_top_one_tickets_data.setEnabled(False)


        # 给相应控件增加事件
        self.ui.Search_Data.clicked.connect(self.btn_search_clicked)
        self.ui.Search_Data_2.clicked.connect(self.btn_a_clicks)
        self.ui.pushButton.clicked.connect(self.btn_tiaojian_clicks)
        self.ui.get_new_indexValue.clicked.connect(self.btn_get_new_index_value)
        self.ui.get_new_StockInfo.clicked.connect(self.btn_get_new_stocket_data)
        self.ui.btn_export_data.clicked.connect(self.btn_export_data)
        self.ui.export_megred_data.clicked.connect(self.btn_export_megred_data)
        self.ui.btn_ticket_history_data.clicked.connect(self.import_tickets_his_data)
        self.ui.btn_top_one_ticket_data.clicked.connect(self.import_top_one_ticket_his_data)
        self.ui.load_top_one_tickets_data.clicked.connect(self.load_top_one_tickets_data)
        self.ui.btn_draw_info.clicked.connect(self.btn_draw_top_one)
        self.ui.btn_export_top_one_and_portfolio.clicked.connect(self.btn_export_top_one_portfolio_value)
        self.ui.btn_get_mtkl_data.clicked.connect(self.load_mtkl_data)
        self.ui.btn_xie_fang_cha_ju_zhen.clicked.connect(self.load_xie_fang_cha)
        self.ui.btn_year_xie_fang_cha_ju_zhen.clicked.connect(self.load_year_xie_fang_cha)
        self.ui.btn_get_new_top_one_ticket_data.clicked.connect(self.btn_get_new_top_one_stocket_data)
        self.ui.btn_mtkl_points_view.clicked.connect(self.show_mtkl_point_view)
        self.ui.btn_mtkl_min_point.clicked.connect(self.show_mtkl_point_min_index_view)
        self.ui.btn_shap_point_view.clicked.connect(self.show_shap_point_view)
        self.ui.btn_shap_point_max.clicked.connect(self.show_shap_point_max_index_view)
        self.ui.btn_top_one_and_select_option.clicked.connect(self.draw_top_one_and_select_option)

        # 初始化工作线程
        start_date = self.ui.start_date.date().toString('yyyy-MM-dd')
        end_date = self.ui.end_date.date().toString('yyyy-MM-dd')
        self.worker = SelectDataWorker(start_date, end_date)
        self.worker.signal.df_ready.connect(self.on_search_df_ready)

    def show_message_box(self,text='数据正在处理中,请稍后...'):
        """
        开启对话框
        :param text: 对话框内容
        :return:
        """
        # 开启对话框
        self.msg_box_hint = QMessageBox()
        self.msg_box_hint.setIcon(QMessageBox.Information)
        self.msg_box_hint.setWindowTitle('操作提示')
        # 标题自己设置
        self.msg_box_hint.setText(text)
        self.msg_box_hint.show()
        QApplication.processEvents()

    def close_message_box(self):
        """
        关闭对话框
        :return:
        """
        # 关闭对话框
        self.msg_box_hint.close()

    def btn_search_clicked(self):
        """
        数据查询
        :return:
        """
        # start_date = self.ui.start_date.date().toString('yyyy-MM-dd')
        # end_date = self.ui.end_date.date().toString('yyyy-MM-dd')
        if not self.worker.isRunning():
            self.worker.start()
            self.ui.Search_Data.setEnabled(False)  # 禁用开始按钮,防止重复点击
            self.ui.pushButton.setEnabled(False)
            self.ui.Search_Data_2.setEnabled(False)
            self.ui.btn_export_data.setEnabled(False)
            self.ui.load_top_one_tickets_data.setEnabled(False)

    def btn_a_clicks(self):
        """
        绘制组合价值曲线图
        :return:
        """
        df_pf_inx = calc.merge_index_value_and_portfolio_value(self.ui.index_value_df, self.ui.portfolio_value_daily)
        calc.draw_portfolio_value(df_pf_inx)

    def btn_tiaojian_clicks(self):
        """
        条件组合生成曲线图
        :return:
        """
        self.show_message_box()
        self.ui.pushButton.setEnabled(False)
        indexs = self.ui.LV_Plate.selectedIndexes()

        select_items = []
        for index in indexs:
            item = self.ui.lv_model.itemData(index)
            select_items.append(item[0])
        plates = None
        if len(select_items) > 0:
            plates = ','.join(select_items)

        df_pf_inx = calc.merge_index_value_and_portfolio_value(self.ui.index_value_df, self.ui.portfolio_value_daily)

        self.ui.old_merged_df = calc.selct_data_by_input(df=self.ui.df, stockcode_df=self.ui.stockcode_df,
                                                         merged_df=df_pf_inx,
                                                         plates=plates,
                                                         value=self.ui.cbox_value.currentText(),
                                                         growth=self.ui.cbox_growth.currentText(),
                                                         profitability=self.ui.cbox_profitability.currentText(),
                                                         momentum=self.ui.cbox_momentum.currentText(),
                                                         eps=self.ui.cbox_esp.currentText())
        self.ui.pushButton.setEnabled(True)

        self.close_message_box()
        self.ui.export_megred_data.setEnabled(True)

    def btn_get_new_index_value(self):
        self.ui.get_new_indexValue.setEnabled(False)
        self.show_message_box(text="正在获取最新指数数据,请稍后.....")
        try:
         spydata.get_new_index_value(input_menu=1)
        except Exception as e:
            self.show_message_box(text=e)
        self.close_message_box()
        self.ui.get_new_indexValue.setEnabled(True)

    def btn_get_new_stocket_data(self):
        self.ui.get_new_StockInfo.setEnabled(False)
        self.show_message_box(text='正在获取最新股票数据,请稍后.....')
        try:
            spydata.get_stock_data(input_menu=2)
        except Exception as e:
            self.show_message_box(text=e)
        self.close_message_box()
        self.ui.get_new_StockInfo.setEnabled(True)

    def btn_get_new_top_one_stocket_data(self):
        self.ui.btn_get_new_top_one_ticket_data.setEnabled(False)
        self.show_message_box(text='正在获取行业第一股票的最新数据,请稍后.....')
        try:
           spydata.get_new_top_one_stock_data(input_menu=3)
        except Exception as e:
            self.show_message_box(text=e)
        self.close_message_box()
        self.ui.btn_get_new_top_one_ticket_data.setEnabled(True)

    def export_data(self, data):
        """
        导出数据为excel
        :param data:
        :return:
        """
        # 创建一个QFileDialog来选择保存路径和文件名
        filename, _ = QFileDialog.getSaveFileName(self, '保存文件', '', 'Excel Files (*.xlsx)')
        if filename:
            self.show_message_box(text='正在导出数据,请稍后....')
            # 假设self.data是一个包含数据的列表
            data = data
            df = pd.DataFrame(data)
            df.to_excel(filename, index=False)
            self.close_message_box()

    def import_top_one_ticket_his_data(self):
        """
        导入行业第一股票的历史数据
        :return:
        """
        self.show_message_box()
        readCvsTicketsData.add_TopOnetickets_data()
        self.close_message_box()

    def import_tickets_his_data(self):
        """
        导入股当前股票组合的历史数据
        :return:
        """
        self.show_message_box()
        readCvsTicketsData.add_tickets_data()
        self.close_message_box()

    # 加载行业市值第一的股票数据
    def load_top_one_tickets_data(self):
        """
        加载行业第一股票数据
        :return:
        """
        start_date = self.ui.start_date.date().toString('yyyy-MM-dd')
        end_date = self.ui.end_date.date().toString('yyyy-MM-dd')
        self.show_message_box()
        # 清空原表
        self.ui.tw_top_one_data.clearContents()
        self.ui.tw_top_one_data.setRowCount(0)

        top_one_df = calc.select_top_one_stockcode_df(start_date=start_date,end_date=end_date)
        #装载数据
        if len(top_one_df) > 0:
            self.ui.tw_top_one_data.setRowCount(top_one_df.shape[0])
            self.ui.tw_top_one_data.setColumnCount(top_one_df.shape[1])
            # 设置表头
            self.ui.tw_top_one_data.setHorizontalHeaderLabels(top_one_df.columns.tolist())

            # 填充数据
            try:
                for row in range(top_one_df.shape[0]):

                    for column in range(top_one_df.shape[1]):
                        item = QTableWidgetItem(str(top_one_df.iat[row, column]))
                        self.ui.tw_top_one_data.setItem(row, column, item)
            except Exception as e:
                self.show_message_box(text=f"Error filling data:{e}")
                return

        top_one_tickets_value_df = calc.get_top_one_tickets_data(start_date=start_date, end_date=end_date)

        self.ui.top_one_tickets_value_df = top_one_tickets_value_df

        self.close_message_box()
        self.ui.btn_draw_info.setEnabled(True)

    def btn_draw_top_one(self):
        """
        绘制行业第一股票组合的曲线图
        :return:
        """
        self.show_message_box()
        portfolio = calc.calc_top_one_portfilo_value(self.ui.top_one_tickets_value_df)
        portfolio = portfolio[['date', 'portfolio_value']]  # 组合时间序列
        portfolio.rename(columns={'portfolio_value': 'TopOnePV'},
                        inplace=True)
        portfolio.set_index('date', inplace=True)  # 设置date为索引

        self.ui.top_one_portfolio_value_df = portfolio
        try:
           df_pf_inx = calc.merge_index_value_and_portfolio_value(self.ui.index_value_df,
                                                                   self.ui.portfolio_value_daily)
           merged_df = pd.merge(portfolio,df_pf_inx, on='date', how='left')
           calc.draw_portfolio_value(merged_df)
           self.ui.top_one_portfolio_value=merged_df
        except Exception as e:
            self.show_message_box(text=f"Error filling data:{e}")
            return

        self.close_message_box()
        self.ui.btn_export_top_one_and_portfolio.setEnabled(True)
        if len(self.ui.old_merged_df)>0:
           self.ui.btn_top_one_and_select_option.setEnabled(True)

    def btn_export_top_one_portfolio_value(self):
        """
        导出行业第一市值股票组合与当前股票组合的数据
        :return:
        """
        data = self.ui.top_one_portfolio_value
        self.export_data(data)


    def btn_export_data(self):
        """
        导出股票组合价值数据
        :return:
        """
        data = self.ui.stockcode_df
        self.export_data(data)

    def btn_export_megred_data(self):
        """
        导出合并后的数据
        :return:
        """
        data = self.ui.old_merged_df
        self.export_data(data)

    def on_search_df_ready(self, df):
        """
        查询按钮加载完成展示数据
        :param df:
        :return:
        """
        self.show_message_box()
        # 清空原表
        self.ui.Dt_View.clearContents()
        self.ui.Dt_View.setRowCount(0)

        start_date = self.ui.start_date.date().toString('yyyy-MM-dd')
        end_date = self.ui.end_date.date().toString('yyyy-MM-dd')
        if len(df) > 0:
            self.ui.Dt_View.setRowCount(df.shape[0])
            self.ui.Dt_View.setColumnCount(df.shape[1])
            # 设置表头
            self.ui.Dt_View.setHorizontalHeaderLabels(df.columns.tolist())

            # 填充数据
            try:
                for row in range(df.shape[0]):

                    for column in range(df.shape[1]):
                        item = QTableWidgetItem(str(df.iat[row, column]))
                        self.ui.Dt_View.setItem(row, column, item)
            except Exception as e:
                self.show_message_box(text=f"Error filling data:{e}")
                return
        self.ui.stockcode_df = df

        # 给plate_lv绑定数据
        plate_df = calc.select_plate(start_date, end_date)
        self.ui.lv_model.setStringList(plate_df.values.flatten().tolist())
        self.ui.LV_Plate.setModel(self.ui.lv_model)

        self.ui.index_value_df = calc.select_index_value(start_date, end_date)
        self.ui.df = calc.select_df(start_date, end_date)
        self.ui.portfolio_value_daily = calc.select_portfolio_value(self.ui.df)
        self.ui.pushButton.setEnabled(True)
        self.ui.Search_Data_2.setEnabled(True)
        self.ui.Search_Data.setEnabled(True)  # 重新启用开始按钮
        self.ui.btn_export_data.setEnabled(True)
        self.ui.btn_get_mtkl_data.setEnabled(True)
        self.ui.load_top_one_tickets_data.setEnabled(True)
        self.close_message_box()

    def load_mtkl_data(self):
        """
        加载蒙特卡洛相关数据
        :return:
        """
        self.show_message_box()
        # 清空原表
        self.ui.tw_mtkl_data.clearContents()
        self.ui.tw_mtkl_data.setRowCount(0)
        start_date = self.ui.start_date.date().toString('yyyy-MM-dd')
        end_date = self.ui.end_date.date().toString('yyyy-MM-dd')
        stockprice = calc.get_mtkl_data(start_date,end_date)
        stock_return = calc.calc_stock_price(stockprice)

        if len(stock_return) > 0:
            self.ui.tw_mtkl_data.setRowCount(stock_return.shape[0])
            self.ui.tw_mtkl_data.setColumnCount(stock_return.shape[1])
            # 设置表头
            self.ui.tw_mtkl_data.setHorizontalHeaderLabels(stock_return.columns.tolist())

            # 填充数据
            try:
                for row in range(stock_return.shape[0]):

                    for column in range(stock_return.shape[1]):
                        item = QTableWidgetItem(str(stock_return.iat[row, column]))
                        self.ui.tw_mtkl_data.setItem(row, column, item)
            except Exception as e:
                self.show_message_box(text=f"Error filling data:{e}")
                return

        self.ui.stock_return = stock_return
        self.close_message_box()
        self.ui.btn_xie_fang_cha_ju_zhen.setEnabled(True)

    def load_xie_fang_cha(self):
        """
        计算斜方差
        :return:
        """
        self.show_message_box()
        xie_fang_cah = calc.calc_xie_fang_cha(self.ui.stock_return)
        if len(xie_fang_cah) > 0:
            self.ui.tw_xie_fang_cha_ju_zhen.setRowCount(xie_fang_cah.shape[0])
            self.ui.tw_xie_fang_cha_ju_zhen.setColumnCount(xie_fang_cah.shape[1])
            # 设置表头
            self.ui.tw_xie_fang_cha_ju_zhen.setHorizontalHeaderLabels(xie_fang_cah.columns.tolist())

            # 填充数据
            try:
                for row in range(xie_fang_cah.shape[0]):

                    for column in range(xie_fang_cah.shape[1]):
                        item = QTableWidgetItem(str(xie_fang_cah.iat[row, column]))
                        self.ui.tw_xie_fang_cha_ju_zhen.setItem(row, column, item)
            except Exception as e:
                self.show_message_box(text=f"Error filling data:{e}")
                return
        self.ui.xie_fang_cha = xie_fang_cah
        self.close_message_box()
        self.ui.btn_year_xie_fang_cha_ju_zhen.setEnabled(True)

    def load_year_xie_fang_cha(self):
        """
        计算年化斜方差
        :return:
        """
        self.show_message_box()
        year_xie_fang_cha = calc.calc_year_xie_fang_cha(self.ui.xie_fang_cha)
        if len(year_xie_fang_cha) > 0:
            self.ui.tw_year_xie_fang_cha_ju_zhen.setRowCount(year_xie_fang_cha.shape[0])
            self.ui.tw_year_xie_fang_cha_ju_zhen.setColumnCount(year_xie_fang_cha.shape[1])
            # 设置表头
            self.ui.tw_year_xie_fang_cha_ju_zhen.setHorizontalHeaderLabels(year_xie_fang_cha.columns.tolist())

            # 填充数据
            try:
                for row in range(year_xie_fang_cha.shape[0]):

                    for column in range(year_xie_fang_cha.shape[1]):
                        item = QTableWidgetItem(str(year_xie_fang_cha.iat[row, column]))
                        self.ui.tw_year_xie_fang_cha_ju_zhen.setItem(row, column, item)
            except Exception as e:
                self.show_message_box(text=f"Error filling data:{e}")
                return
        self.ui.year_xie_fang_cha = year_xie_fang_cha
        ticker_list = self.ui.stockcode_df['stockcode']
        randomportfolios = calc.calc_mengtekaluo_data(self.ui.stock_return, self.ui.year_xie_fang_cha, ticker_list)
        self.ui.randomp_ortfolios = randomportfolios
        self.close_message_box()
        self.ui.btn_mtkl_points_view.setEnabled(True)
        self.ui.btn_mtkl_min_point.setEnabled(True)
        self.ui.btn_shap_point_view.setEnabled(True)
        self.ui.btn_shap_point_max.setEnabled(True)

    def show_mtkl_point_view(self):
        calc.draw_mtkl_point_view(self.ui.randomp_ortfolios)

    def show_mtkl_point_min_index_view(self):
        calc.draw_mtkl_point_min_index_view(self.ui.randomp_ortfolios)

    def show_shap_point_view(self):
        calc.draw_shap_point_view(self.ui.randomp_ortfolios)

    def show_shap_point_max_index_view(self):
        calc.draw_shap_point_max_index_view(self.ui.randomp_ortfolios)


    def draw_top_one_and_select_option(self):
        self.show_message_box()
        try:
            top_one_portfolio = calc.calc_top_one_portfilo_value(self.ui.top_one_tickets_value_df)
            top_one_portfolio = top_one_portfolio[['date', 'portfolio_value']]  # 组合时间序列
            top_one_portfolio.rename(columns={'portfolio_value': 'TopOnePV'},
                             inplace=True)
            top_one_portfolio.set_index('date', inplace=True)  # 设置date为索引

            indexs = self.ui.LV_Plate.selectedIndexes()

            select_items = []
            for index in indexs:
                item = self.ui.lv_model.itemData(index)
                select_items.append(item[0])
            plates = None
            if len(select_items) > 0:
                plates = ','.join(select_items)

            df_pf_inx = calc.merge_index_value_and_portfolio_value(self.ui.index_value_df,
                                                                   self.ui.portfolio_value_daily)

            calc.selct_data_by_input_and_top_one(df=self.ui.df, stockcode_df=self.ui.stockcode_df,
                                     merged_df=df_pf_inx,
                                     plates=plates,
                                     value=self.ui.cbox_value.currentText(),
                                     growth=self.ui.cbox_growth.currentText(),
                                     profitability=self.ui.cbox_profitability.currentText(),
                                     momentum=self.ui.cbox_momentum.currentText(),
                                     eps=self.ui.cbox_esp.currentText(),top_one=top_one_portfolio)
        except Exception as e:
            self.show_message_box(text=f"Error filling data:{e}")
            return
        self.close_message_box()











# 在这里添加其他方法


# 应用程序入口
if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    # 设置应用程序的默认字体大小
    font = QFont()
    font.setPointSize(10)  # 设置字体大小为12
    app.setFont(font)
    mainWin = MainWindow()  # 创建 MyMainWindow 实例
    mainWin.setWindowTitle("股票相关计算程序")
    # 禁用最大化按钮
    mainWin.setWindowFlags(mainWin.windowFlags() & ~Qt.WindowMaximizeButtonHint)
    mainWin.show()  # 显示窗口
    sys.exit(app.exec_())  # 进入主事件循环

标签:Python3.11,code,df,self,value,Server,ui,SQL,date
From: https://blog.csdn.net/accp10422/article/details/139644720

相关文章

  • mysql高级查询技巧
    常见表表达式(CommonTableExpressions,简称CTEs)描述:CTEs是SQL中的一种高级查询功能,它允许用户定义一个临时的结果集,这个结果集在执行后续的SQL语句时可以被引用,就像一个临时表一样。CTEs使得复杂的查询逻辑更加模块化和易于理解。声明和语法:WITHCTE_NameAS(SELECTc......
  • SQlite
    #PRAGMA命令https://www.sqlite.org/pragma.html#pragma_journal_modehttps://www.w3cschool.cn/sqlite/sqlite-pragma.html##查询锁模式PRAGMAlocking_mode;PRAGMAlocking_mode=NORMAL|EXCLUSIVE(排它模式)此编译指示设置或查询数据库连接锁定模式。锁定模式为......
  • 提取SQL Server 数据库数据字典
    SELECT表名=CASEWHENA.COLORDER=1THEND.NAMEELSE''END,表备注=CASEWHENA.COLORDER=1THENISNULL(F.VALUE,'')ELSE''END,列序号=A.COLORDER,列名称=A.NAME,标识=CASEWHENCOLUMNPROPERTY(A.ID,A.NAME,'ISIDENTITY')=1THE......
  • Oracle 是否扼杀了开源 MySQL
    Oracle是否无意中扼杀了开源MySQLPeterZaitsev是一位俄罗斯软件工程师和企业家,曾在MySQL公司担任性能工程师。大约15年前,当甲骨文收购Sun公司并随后收购MySQL时,有很多关于甲骨文何时“杀死MySQL”的讨论。他曾为甲骨文进行辩护,反驳了这些不友好的说法。然而,如今Zaitsev......
  • Docker安装MySQL主从
    Docker安装MySQL主从搭建主从dockerrun[OPTIONS]IMAGE[COMMAND][ARG...]dockerrun-p3306:3306很多-d--namehahamysql:5.7Docker启动容器的数据部分一定挂载出来1、创建Masterdockerrun-p3307:3306--namemysql-master\-v/myd......
  • MySQL安全性管理
    用户权限管理创建和管理用户:使用CREATEUSER和GRANT语句创建和管理用户。例如:CREATEUSER'username'@'host'IDENTIFIEDBY'password';GRANTSELECT,INSERT,UPDATE,DELETEONdatabase.*TO'username'@'host';最小权限原则:只赋予用户执行其任务所需的最......
  • 【Go】用 Go 原生以及 Gorm 读取 SQLCipher 加密数据库
    本文档主要描述通过https://github.com/mutecomm/go-sqlcipher生成和读取SQLCipher加密数据库以及其中踩的一些坑用go去生成读取SQLCipher数据库用gorm去读取SQLCipher数据库在生成后分别用DBeaver、dbbrowser和sqlcipher读取SQLCipher数据库,基础操作见......
  • SQL注入&HTTP 头XFF&COOKIE&POST请求
    目录#知识点:#补充点:案例演示1数据请求方式涉及到的问题:phpJavaSpringPython案例演示2手工注入sqlmap注入方式一方式二案例演示3​编辑案例演示4#知识点:1、数据请求方式-GET&POST&COOKIE等2、常见功能点请求方式-用户登录&IP记录等3、黑盒白盒注入......
  • MySQL怎么为表添加描述
    1.MySQL为表添加描述的方法在MySQL中,表本身并没有直接的“描述”字段或属性来存储关于表的额外信息,如用途、创建者、备注等。但是,我们可以通过几种方式来实现这一需求:1.1使用COMMENT关键字为表或列添加注释虽然这不是一个完整的“描述”字段,但我们可以使用COMMENT关键字为表或......
  • 如何查询MySQL存储的树形结构,层次结构
    表定义如下 如果我们需要在表中查询这个树状结构,通过SQL语句,有两种查询方法:1.通过inner自连接查询,适用于简单的结构SELECT*FROMcourse_categoryASoneINNERJOINcourse_categoryAStwoONtwo.parentid=one.idWHEREone.parentid='1'ORDER......