python做基金投资分析(基金定投的Python模拟投资分析)_基金知识_景合财经知识网_景合财经景合财经

景合财经
景合财经知识网站

python做基金投资分析(基金定投的Python模拟投资分析)

(70后红太阳2020年4月写于成都)

摘要:在介绍基金定投和沪深300指数基金的基础上,本文提出了基金定投(日定投)的基本数学原理,并建立了数学模型。根据数学模型,本文利用Python语言进行软件开发,对定投沪深300指数基金进行模拟分析,主要分析了短期定投和长期定投的投资收益与风险,并给出了建设性结论。

关键词:基金定投;Python;模拟分析;投资收益与风险

Keywords: Automatic fund investment; Python; Simulation analysis; Investment income and risk

1、引言

基金定投是定期定额投资基金的简称,是指在固定的时间(定投周期)以固定的金额投资到指定的基金中。

按投资周期来分,基金定投分为日定投、周定投、月定投。本文主要分析日定投。

一般来说,定投首选指数型基金,因为它较少受到人为因素干扰,只是跟踪指数,沪深300指数基金就是其中之一。

沪深300指数,是由沪深证券交易所于2005年4月8日联合发布的反映沪深300指数编制目标和运行状况的金融指标。该指数具有稳定性、代表性和可操作性,可以给投资者提供权威的投资方向,也便于投资者进行跟踪和进行投资组合。

本文利用Python语言,通过建立数学模型,编程模拟分析日定投沪深300指数基金的投资收益与风险。

2、数学建模

本文提出基金定投(日定投)的基本数学原理就是:已知沪深300指数,求定投周期后的收益与风险。

设:定投周期为N天,第i天的沪深300指数为Zi(i=0,1,2……N-1),则第i天沪深300指数的振幅ZAi为:

大多数沪深300指数基金的基金净值变化曲线都能较好地拟合沪深300指数的变化曲线,本文假设沪深300指数基金的基金净值变化曲线完全拟合沪深300指数的变化曲线,并假设定投开始日期的基金净值为1元,则第i天沪深300指数基金的基金净值Ji为:

可以得到:第i天基金净值的振幅JAi为:

假设每日定投(基金固定买入)的金额为D元,则第i天的基金确认份额Fi为:

第i天的本金投入Bi为:

由式(4)可以得到:第i天的基金持有份额CFi为:

由式(2)和式(6)可以得到:第i天的基金持有金额CMi为:

由式(5)和式(7)可以得到:第i天的基金累计收益Si为:

由式(5)和式(8)可以得到:第i天的基金累计收益率SRi为:

式(8)和式(9)就是我们要得到的结果,为与沪深300指数的变化相对比,可以同时计算第i天的沪深300指数收益率ZSRi为:

以上就完成了基金定投的数学建模,为Python软件开发奠定了理论基础。

3、软件开发

3.1、配置环境

开发环境:Win7;

开发工具:Python 3.8.2 IDLE,Qt Designer 5.13.2;

Python安装目录:D:\python

文件保存目录:D:\python\基金定投的Python模拟投资分析;

路径配置:在cmd下,运行path=%path%;D \python\python38-32\scripts;D: \python\python38-32,让Python的相关程序可以调用。

数据下载:在浏览器中打开网址http://quotes.money.163.com/trade/lsjysj_zhishu_399300.html,于网页的右侧点击下载数据按钮,下载沪深300指数历史交易数据。将下载结果据保存到目录D:\python\基金定投的Python模拟投资分析,命名为:沪深300指数历史交易数据.csv。

3.2、设计界面

运行Qt Designer 5.13.2开发工具,设计图形用户界面,设计结果如图1所示:


python做基金投资分析

图1:“基金定投的Python模拟投资分析”的用户界面设计图

将设计结果保存到目录D:\python\基金定投的Python模拟投资分析,命名为:ShowMain.ui。

在cmd下,运行pyuic5 -o D:\python\基金定投的Python模拟投资分析\ShowMain.py D:\python\基金定投的Python模拟投资分析\ShowMain.ui。

运行后,就将图形用户界面文件ShowMain.ui转换成了Python源代码文件ShowMain.py,便于下一步编写代码时调用。

3.3、编写代码

运行Python 3.8.2 IDLE开发工具,编写代码并调试,将代码保存到目录D:\python\基金定投的Python模拟投资分析,命名为:FundDT.py。

源代码编程结果及其注释如下所示:

#=====1、导入包、定义全局列表=====import sys #导入sys模块import ShowMain #导入ShowMain窗体模块(用QtDesigner设计的)from PyQt5.QtWidgets import * #导入PyQt5的QtWidgets(Qt小部件)相关模块组件from PyQt5.QtCore import * #导入PyQt5的QtCore相关模块组件from PyQt5.QtGui import * #导入PyQt5的QtGui相关模块组件import csv #导入csv模块import datetime #导入时间模块import win32api,win32con #导入win32相关模块import os #导入os相关模块csv_list=[] #定义存储整个csv文件的列表Analysis_list=[] #定义分析数据的列表AnalysisHead=[] #定义分析数据的表头Hheader_list=[] #定义存储水平方向表头的列表Vheader_list=[] #定义存储垂直方向表头的列表#=====2、显示图形用户界面=====app=QApplication(sys.argv) #创建应用程序实例MainWindow=QMainWindow() #创建主窗体实例ui=ShowMain.Ui_MainWindow() #创建已设计窗体ShowMain实例ui.setupUi(MainWindow) #把ShowMain与主窗体进行结合MainWindow.setFixedSize(MainWindow.width(), MainWindow.height()) #屏蔽掉主窗体最大化按钮MainWindow.show() #显示结合后的主窗体#=====3、按钮:打开文件名===== def MyFun_FileOpen(): #自定义函数来打开文件名 FileName=QFileDialog.getOpenFileName(MainWindow,'打开文件','','Csv files(*.csv)') #打开文件对话框 ui.lineEdit_SRWJ.setText(FileName[0]) #将打开的文件名输出到输入文件文本框 ui.pushButton_OpenFile.clicked.connect(MyFun_FileOpen) #为按钮增加鼠标点击事件,并连接自定义函数MyFun_FileOpen#=====4、按钮:模拟分析===== def MyFun_MNFX(): #自定义函数来模拟分析 # ===4.1、打开csv文件并读取到列表中=== FileName=ui.lineEdit_SRWJ.text() #从输入文件文本框得到文件名 if os.path.exists(FileName)==False: #如果输入文件不存在 win32api.MessageBox(0,'%s%s'%(FileName,'文件不存在,请重新输入!'), "提示",win32con.MB_ICONASTERISK) return #终止函数执行 csv_file=open(FileName,'r') #以只读方式打开csv文件 csvfile_content=csv.reader(csv_file) #读取csv文件内容 csv_list.clear() #清空csv列表 for Row in csvfile_content: #按行对csv文件内容进行循环 csv_list.append(Row) #按行(元素)将csv文件追加到列表中 csv_file.close() #关闭csv文件 # ===4.2、得到csv列表的行列数=== RowCount=len(csv_list) #得到csv列表的行数 ColCount=len(csv_list[0]) #得到csv列表的列数 # ===4.3、判断日期是否在csv文件中=== JudgeBegin=False #判断开始日期赋初值为否 for Row in range(0,RowCount,1): #按行进行循环 if ui.dateEdit_Begin.date().toString(Qt.ISODate)==csv_list[Row][0]: #判断开始日期是否在csv文件中 JudgeBegin=True #如果在,判断开始日期为是 BeginRow=Row #如果在,记住开始日期的行号 break #如果在,跳出for循环 JudgeEnd=False #判断结束日期赋初值为否 for Row in range(0,RowCount,1): #按行进行循环 if ui.dateEdit_End.date().toString(Qt.ISODate)==csv_list[Row][0]: #判断结束日期是否在csv文件中 JudgeEnd=True #如果在,判断结束日期为是 EndRow=Row #如果在,记住结束日期的行号 break #如果在,跳出for循环 # ===4.4、根据判断日期是否在csv文件中的结果,分别执行代码=== if JudgeBegin==False and JudgeEnd==False: #如果开始日期和结束日期均不在csv文件中 win32api.MessageBox(0,"开始日期和结束日期均不在csv文件中,请重新输入!", "提示",win32con.MB_ICONASTERISK) #弹出消息框 return #终止函数执行 elif JudgeBegin==False: #如果开始日期不在csv文件中 win32api.MessageBox(0,"开始日期不在csv文件中,请重新输入!", "提示",win32con.MB_ICONASTERISK) #弹出消息框 return #终止函数执行 elif JudgeEnd==False: #如果结束日期不在csv文件中 win32api.MessageBox(0,"结束日期不在csv文件中,请重新输入!", "提示",win32con.MB_ICONASTERISK) #弹出消息框 return #终止函数执行 elif BeginRow<=EndRow: #如果开始日期大于等于结束日期 win32api.MessageBox(0,"开始日期必须小于结束日期,请重新输入!", "提示",win32con.MB_ICONASTERISK) #弹出消息框 return #终止函数执行 else: #如果开始日期和结束日期均在csv文件中,开始模拟分析数据 FundJz=ui.doubleSpinBox_FundBegin.text() #从Spin文本框获取基金净值 FundMrz=ui.comboBox_EverydayDT.currentText() #从下拉框获取基金买入值 ui.tableWidget.clearContents() #清空表格控件的所有内容 AnalysisHead=['日期', '周', '沪深300指数', '振幅%','基金净值元', '振幅%','基金买入元','基金卖出元','确认份额份','本金投入元','持有份额份','持有金额元','投资天数','累计收益元','累计收益率%','指数收益率%'] #定义分析数据的表头列表 RowCount=BeginRow-EndRow+1 #得到分析数据的行数 ColCount=len(AnalysisHead) #得到分析数据的列数 Analysis_list.clear() #清空分析列表 for Row in range(0,RowCount,1): #按行进行循环 Analysis_list.append(AnalysisHead) #按行给分析数据填充 # ===设置表格控件的行列数=== ui.tableWidget.setRowCount(RowCount) #设置表格控件的行数 ui.tableWidget.setColumnCount(ColCount) #设置表格控件的列数 ui.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) #设置表格控件的列宽自适应内容 # ===显示表格控件表头=== Hheader_list.clear() #清空存储水平方向表头的列表 for Col in range(0,ColCount,1): #按列进行循环 Hheader_list.append('%s'%(Analysis_list[0][Col])) #给水平方向表头列表赋值 ui.tableWidget.setHorizontalHeaderLabels(Hheader_list) #设置水平方向表头标签 Vheader_list.clear() #清空存储垂直方向表头的列表 for Row in range(0,RowCount,1): #按行进行循环 Vheader_list.append('%s%d%s'%('第',Row+1,'行')) #给垂直方向表头列表赋值 ui.tableWidget.setVerticalHeaderLabels(Vheader_list) #设置垂直方向的表头标签 # ===分析数据并显示到表格控件=== for Row in range(0,RowCount,1): #按行进行循环 Analysis_list[Row][0]=csv_list[BeginRow-Row][0] #将csv_list列表第0列的数据传送给Analysis_list列表(第0列)日期 Analysis_list[Row][1]=str(datetime.datetime(int(Analysis_list[Row][0][0:4]),int(Analysis_list[Row][0][5:7]),int(Analysis_list[Row][0][8:10])).weekday()+1) #根据第0列日期得到星期给(第1列)周 Analysis_list[Row][2]=csv_list[BeginRow-Row][3] #将csv_list列表第3列的数据传送给Analysis_list列表(第2列)沪深指数 #分析第3列以上的数据 if Row==0: #得到第0行的初始值 Col3ZF=0 #第0行(第3列)振幅为0 Analysis_list[Row][3]=str(Col3ZF) #第0行(第3列)振幅为0 Rember2Col=Analysis_list[Row][2] #记住第0行第2列的值,以便第3列振幅的计算 Analysis_list[Row][4]=FundJz #得到第0行(第4列)的基金净值 RemberFundJZ=Analysis_list[Row][4] #记住基金净值,以便下一行基金净值的计算 Analysis_list[Row][5]='0' #第0行(第5列)基金净值振幅为0 Rember4Col=Analysis_list[Row][4] #记住第0行第4列的值,以便第5列基金振幅的计算 Analysis_list[Row][6]=FundMrz #得到第0行(第6列)的基金买入值 Analysis_list[Row][7]='0' #第0行(第7列)基金卖出值为0 Analysis_list[Row][8]=str(round((float(Analysis_list[Row][6])-float(Analysis_list[Row][7]))/float(Analysis_list[Row][4]),4)) #计算第0行(第8列)的确认份额值 Analysis_list[Row][9]=str(round(float(Analysis_list[Row][6])-float(Analysis_list[Row][7]),2)) #计算第0行(第9列)的本金投入值 Analysis_list[Row][10]=str(round(float(Analysis_list[Row][8]),4)) #计算第0行(第10列)的持有份额值 Analysis_list[Row][11]=str(round(float(Analysis_list[Row][10])*float(Analysis_list[Row][4]),4)) #计算第0行(第11列)的持有金额值 Analysis_list[Row][12]='0' #第0行(第12列)投资天数为0 BeginDay=datetime.datetime(int(Analysis_list[Row][0][0:4]),int(Analysis_list[Row][0][5:7]),int(Analysis_list[Row][0][8:10])) #根据第0列计算开始日期 Analysis_list[Row][13]='0' #第0行(第13列)累计收益为0 Analysis_list[Row][14]='0' #第0行(第14列)累计收益率为0 Analysis_list[Row][15]='0' #第0行(第15列)指数收益率为0 BeginZS=Analysis_list[Row][2] #得到开始日期的指数值 else: #得到其他行的值 Col3ZF=round(float(Analysis_list[Row][2])*100/float(Rember2Col)-100,4) #计算本行(第3列)振幅 Analysis_list[Row][3]=str(Col3ZF) #得到本行(第3列)振幅 Rember2Col=Analysis_list[Row][2] #记住本行第2列的值,以便下一行第3列振幅的计算 Analysis_list[Row][4]=str(round(float(RemberFundJZ)*(1+float(Analysis_list[Row][3])/100),6)) #计算本行(第4列)的基金净值 RemberFundJZ=Analysis_list[Row][4] #记住基金净值,以便下一行基金净值的计算 Analysis_list[Row][5]=str(round(float(Analysis_list[Row][4])*100/float(Rember4Col)-100,4)) #本行(第5列)基金净值的振幅 Rember4Col=Analysis_list[Row][4] #记住本行第4列的值,以便下一行第5列基金净值振幅的计算 Analysis_list[Row][6]=FundMrz #得到本行(第6列)的基金买入值 Analysis_list[Row][7]='0' #本行(第7列)基金卖出值为0 Analysis_list[Row][8]=str(round((float(Analysis_list[Row][6])-float(Analysis_list[Row][7]))/float(Analysis_list[Row][4]),4)) #计算本行(第8列)的确认份额值 Analysis_list[Row][9]=str(round(float(Analysis_list[Row-1][9])+float(Analysis_list[Row][6])-float(Analysis_list[Row][7]),2)) #计算本行(第9列)的本金投入值 Analysis_list[Row][10]=str(round(float(Analysis_list[Row-1][10])+float(Analysis_list[Row][8]),4)) #计算本行(第10列)的持有份额值 Analysis_list[Row][11]=str(round(float(Analysis_list[Row][10])*float(Analysis_list[Row][4]),4)) #计算本行(第11列)的持有金额值 CurrentDay=datetime.datetime(int(Analysis_list[Row][0][0:4]),int(Analysis_list[Row][0][5:7]),int(Analysis_list[Row][0][8:10])) #根据第0列计算当前日期 Analysis_list[Row][12]=str((CurrentDay-BeginDay).days) #计算投资天数(第12列) Analysis_list[Row][13]=str(round(float(Analysis_list[Row][11])-float(Analysis_list[Row][9]),2)) #计算本行(第13列)的累计收益值 Analysis_list[Row][14]=str(round(float(Analysis_list[Row][13])*100/float(Analysis_list[Row][9]),2)) #计算本行(第14列)的累计收益率值 Analysis_list[Row][15]=str(round((float(Analysis_list[Row][2])/float(BeginZS)-1)*100,2)) #计算本行(第15列)的指数收益率值 for Col in range(0,ColCount,1): #按列进行循环 CellData=QTableWidgetItem(Analysis_list[Row][Col]) #为每个表格获取数据 ui.tableWidget.setItem(Row,Col,CellData) #为每个表格添加数据 CellData.setTextAlignment(Qt.AlignHCenter|Qt.AlignVCenter) #设置单元格文本为居中对齐方式 if Col3ZF>=0: #如果指数上涨 CellData.setForeground(QBrush(QColor(255,0,0))) #设置单元格颜色为红色 else: #如果指数下跌 CellData.setForeground(QBrush(QColor(0,200,0))) #设置单元格颜色为淡绿色 ui.progressBar.setValue(int((Row+1)*100/RowCount)) #显示分析进度 AnalysisHead.clear() #清空分析数据表头的列表ui.pushButton_MNFX.clicked.connect(MyFun_MNFX) #为按钮增加鼠标点击事件,并连接自定义函数MyFun_MNFX#=====5、按钮:退出程序===== ui.pushButton_Exit.clicked.connect(MainWindow.close) #为按钮增加鼠标点击事件,关闭主窗体#=====6、系统退出命令===== sys.exit(app.exec_()) #系统接收退出命令后,退出

3.4、运行程序

在Python 3.8.2 IDLE开发工具中,按F5键,运行FundDT.py程序,运行结果如图2所示:


python做基金投资分析

图2:“基金定投的Python模拟投资分析”的运行结果图

程序运行时,可以设定以下参数:基金定投开始日期、结束日期、基金初始净值、每日定投金额,根据设定的参数进行模拟分析。

4、模拟分析

4.1、分析配置

分析软件:本文化开发的“基金定投的Python模拟投资分析”程序;

数据来源:本文3.1节下载的“沪深300指数历史交易数据.csv”文件;

基金初始净值:1.0元;

每日定投金额:100元。

4.2、分析结果

1、短期定投分析:按月为基础周期,分别模拟分析最近1个月到12个月的基金定投情况,分析结果如表1所示:


python做基金投资分析

表1:短期模拟分析结果表

2、长期定投分析:按年为基础周期,分别模拟分析最近1年到15年的基金定投情况,分析结果如表2所示:


python做基金投资分析

表2:长期模拟分析结果表

5、结论

由表1和表2的分析结果,可以得到如下结论:

1、1年内的短期定投收益率均为负值,2年以上的长期定投收益率均为正值,而且定投周期越长,收益率一般来说越高,说明基金定投适合长期投资。

2、定投周期越长,本金投入就越大,资金流动性减弱,说明基金定投适合用闲散资金投资。

3、模拟分析只是历史数据,仅作参考。股市有风险,投资需谨慎,投资者要综合考虑本金的安全性、流动性和收益率,结合本人的实际情况定投基金。

家电维修,空调维修,智能锁维修全国报修号码分享:可以直接拔打400-968-1665 全国各大城市均设网点。
赞(0) 打赏
欢迎转载分享:景合财经 » python做基金投资分析(基金定投的Python模拟投资分析)
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

-景合财经

在线报修网点查询