python实现基金定投并可视化结果

1.什么是指数基金
2.什么是基金定投
3.本次数据来源
4.作出假设

5.改变定投策略,获得更好的收益(以2018和2019的平均收益率分析)

1.什么是指数基金

股票指数是指按照一定的规则所选择的股票的平均值。比如:

上证50指数:就是把上海证券交易所规模最大、流动性最好的50家公司的股票统计起来的股票平均值。
沪深300指数:就是把上交所和深交所前300只规模最大、流动最好的300家公司的股票统计起来的股票平均值。
中证500指数:把沪深300指数的前300家大公司排除,剩下的大公司中再选前500只规模最大、流动最好的500家公司的股票统计起来的股票平均值。

因此:指数基金即按照某选股规则选出来的一堆股票的集合即指数基金

2.什么是基金定投

基金定投,就是按照固定的频率和固定的金额,不停分批次小额买入金融市场上的基金。定投可以选择任何种类的基金。我们以指数基金为例(大部分传说中无脑定投的案例都是以指数基金的定投方式),分析本案例

3.本次数据来源

通过API接口从网易财经上进行调取
接口规范
http://quotes.money.163.com/service/chddata.html?code=003833&start=19901219&end=20200228&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;VOTURNOVER;VATURNOVER
说明:

code参数后面的7位整数代表了股票代码;比如0000001指的是上证指数。注意这串数字要分0和000001两部分看。0代表sh,1代表sz。所以0000001其实是sh000001的意思。同理,0 000300也就是sh000300 沪深300的代码。
start和end参数后面的8位整数代表年(xxxx)月(xx)日(xx)
fields选项中,TCLOSE,HIGH,LOW,TOPEN分别表示当日的收盘,最高,最低,开盘价;LCLOSE表示昨日收盘>价。CHG,PCHG,VOTURNOVER,VAT分别表示涨跌额,涨跌幅,成交量,成交金额。

本次研究沪深300指数基金

4.作出假设

# 加载模块
from datetime import datetime,timedelta
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

# 指定默认字体
plt.rcParams['font.family']=['SimHei']
# 解决负号'-'显示为方块的问题
plt.rcParams['axes.unicode_minus']=False
# 获取数据
def get_data(indexID,dateStart="20000101",dateEnd="20200320",local=True):
    # 定义网络数据接口
    api="http://quotes.money.163.com/service/chddata.html?code="
    
    if local:
        data=pd.read_csv(indexID[1:]+'.csv',index_col=0,encoding='gb2312')  # index_col将第一列作为index使用,'gb2312'文件里有中文
    else:
        api+=indexID+"&start="+dateStart+"&end="+dateEnd
        api+="&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;VOTURNOVER;VATURNOVER"
        
        data=pd.read_csv(api,index_col=0,encoding='gb2312')
        
    data=data.loc[(data.index>datetime.strptime(dateStart,"%Y%m%d").strftime("%Y-%d-%m"))
                  &(data.index<datetime.strptime(dateEnd,"%Y%m%d").strftime("%Y-%d-%m"))]
    data=data.sort_values(by=['日期']) #排序
    
    return data
        
def invest(indexID,dateStart,dateEnd,amount,freq,fixRate=None,fixPercent=0.15,strategy=1):
    '''
    简单定投的实现
    strategy-定投策略:
        1-固定金额(amount)
        2-固定比例(fixPercent)
        3-给定最小投入额情况下的固定比例(max(fixPercent,amount))
        4-逢低加大买入
    fixRate-定期存款的年利率:用于计算收益对比
    '''
    # 获取数据
    data=get_data(indexID,dateStart,dateEnd,False)
    
    
    # 初始化定投金额/份额列表/定投日期
    listAmount=[]
    listShare=[]
    listDate=[]
    
    # 定投比例
    percent=fixPercent
    
    # 定投次数
    num=0
    
    # 固定收益
    fixProfit=0
    
    # 开始定投
    st=datetime.strptime(dateStart,"%Y%m%d")
    sd=datetime.strptime(dateEnd,"%Y%m%d")
    
    while True:
        if st.strftime("%Y-%m-%d") not in data.index:
            st+=timedelta(days=1)
        else:
            #投入金额
            price=data.loc[st.strftime("%Y-%m-%d")]['收盘价']
            listDate.append(st)
            if strategy==1:
                listAmount.append(amount)
            elif strategy==2:
                listAmount.append(price*percent)
            else:
                listAmount.append(max(price*percent,amount))
            share=listAmount[-1]/price 
            listShare.append(share)
            
            #定投周期
            st+=timedelta(days=freq)

            # 固定收益更新
            fixProfit+=(1+fixRate)**((sd-listDate[-1]).days/365)*listAmount[-1]

            num+=1

        if st>sd:
            break
        
    # 计算定投收益
    totalInvest=sum(listAmount)
    totalProfit=sum(listShare)*price-totalInvest
        
    # 计算固定利率收益
    fixProfit=fixProfit-totalInvest
         
    return totalInvest,totalProfit,fixProfit
            
    

每周定投一次,每次定投500,计算2019年对沪深300指数基金进行定投的收益率

# 数据参数
indexID='0000300' #沪深300
dateStart='20190101' #开始日期
dateEnd='20191231'	#结束日期

# 固定年利率  作为收益对比
fixRate=0.03

# 定投参数
amount=500 # 每期定投金额(单位:元)
freq=7 # 定投周期(单位:天)


# 数据获取
data=get_data(indexID,dateStart,dateEnd,False)
data.head()

在这里插入图片描述

# 数据可视化
'''
str转换为datetime  通过datetime.strptime() 
datetime对象 转换为str 通过datetime.strftime() 
'''


xs=[datetime.strptime(d,'%Y-%m-%d').date() for d in data.index]

plt.figure(figsize=(16,8))
plt.subplot(121)
plt.plot(xs,data["收盘价"])
plt.xlim([xs[0],xs[-1]])
plt.xticks(rotation=60)
plt.xlabel("日期")
plt.ylabel("指数值")
plt.title(data["名称"][0])
plt.grid()

plt.subplot(122)
plt.plot(xs,pd.to_numeric(data['涨跌幅'],errors='coerce'))
plt.xlim(xs[0],xs[-1])
plt.xticks(rotation=60)
plt.xlabel("日期")
plt.ylabel("指数变化值")
plt.title(data['名称'][0]+"日涨跌值")
plt.grid()

在这里插入图片描述

totalInvest,totalProfit,fixProfit=invest(indexID,dateStart,dateEnd,amount,freq,fixRate=fixRate,fixPercent=0.15,strategy=1)

print("定投总投入为%10.2f元,获得收益%10.2f元,固定年利率收益为%10.2f元"%(totalInvest,totalProfit,fixProfit))
print("定投收益率{:6.2f}%".format(totalProfit/totalInvest*100))

'''
输出结果:
定投总投入为  26000.00元,获得收益   2531.34元,固定年利率收益为    382.18元
定投收益率  9.74%
'''

每周定投一次,每次定投500,分别计算从2002年开始到2019年,每年定投沪深300指数基金的收益率

# 数据参数
indexID="0000300"
firstYear=2002
nYears=18

#固定年利率-收益对比
fixRate=0.03

# 定投参数
amount=500  # 每期定投金额
freq=7     # 定投周期(单位:天)

# 定投收益
profits=[]

# 遍历年份
for year in range(nYears):
    thisYear=str(firstYear+year)
    dateStart=thisYear+"0101"
    dateEnd=thisYear+"1231"
    
    totalInvest,totalProfit,fixProfit=invest(indexID,dateStart,dateEnd,amount,freq,fixRate=fixRate,fixPercent=0.15,strategy=1)
    
    profits.append(totalProfit/totalInvest*100)
    print("{}年的定投收益率{:6.2f}%".format(thisYear,totalProfit/totalInvest*100))

'''
输出结果:
2002年的定投收益率-13.37%
2003年的定投收益率  0.10%
2004年的定投收益率-13.56%
2005年的定投收益率  0.13%
2006年的定投收益率 53.12%
2007年的定投收益率 41.79%
2008年的定投收益率-33.18%
2009年的定投收益率 20.27%
2010年的定投收益率  2.45%
2011年的定投收益率-19.91%
2012年的定投收益率  4.39%
2013年的定投收益率 -4.43%
2014年的定投收益率 50.56%
2015年的定投收益率 -2.79%
2016年的定投收益率  3.06%
2017年的定投收益率 10.84%
2018年的定投收益率-15.05%
2019年的定投收益率  9.74%
'''
# 可视化定投结果
xs=[datetime.strptime(str(d),'%Y').date() for d in range(2002,2020)]

plt.figure(figsize=(16,8))
plt.plot(xs,profits,'bo-.')
plt.xlim(xs[0],xs[-1])
plt.xlabel("年份")
plt.ylabel("收益百分比")
plt.title("沪深300的年定投收益率(每周固定金额的定投)")
plt.grid()

for i in range(len(profits)):
    if profits[i]>0:
        plt.text(xs[i],profits[i]+2,str(round(profits[i],2))+"%",color='r',fontsize=13)
    else:
        plt.text(xs[i],profits[i]-4,str(round(profits[i],2))+"%",color='g',fontsize=13)

在这里插入图片描述

5.改变定投策略,获得更好的收益(以2018和2019的平均收益率分析)

# 数据参数
indexID="0000300"
firstYear=2002
nYears=18

#固定年利率-收益对比
fixRate=0.03

# 定投参数
amount=500  # 每期定投金额
freq=7     # 定投周期(单位:天)

# 定投收益
quarterly_profits=[]

改变定投周期(每三个月定投)

for year in range(nYears):
    thisYear=str(firstYear+year)
    
    # 遍历一年中的四个季度
    for quarter in range(4):
        monthStart=quarter*3+1
        monthEnd=monthStart+2
        dateStart=thisYear+str(monthStart).zfill(2)+"01"
        dateEnd=thisYear+str(monthEnd).zfill(2)+"30"
        
        totalInvest,totalProfit,fixProfit=invest(indexID,dateStart,dateEnd,amount,freq,fixRate=fixRate,fixPercent=0.15,strategy=1)
    
        quarterly_profits.append(totalProfit/totalInvest*100)


# 可视化定投结果
xs=[datetime.strptime(str(d)+str(m).zfill(2),'%Y%m').date() for d in range(2002,2020) for m in range(1,12,3)]

plt.figure(figsize=(16,8))
plt.plot(xs,quarterly_profits,'bo-.')
plt.xlim(xs[0],xs[-1])
plt.xlabel("年份")
plt.ylabel("收益百分比")
plt.title("沪深300的年定投收益率(每周固定金额的定投)")
plt.grid()

for i in range(len(quarterly_profits)):
    if quarterly_profits[i]>0:
        plt.text(xs[i],quarterly_profits[i]+1,str(round(quarterly_profits[i],2))+"%",color='r',fontsize=13)
    else:
        plt.text(xs[i],quarterly_profits[i]-2,str(round(quarterly_profits[i],2))+"%",color='g',fontsize=13)

在这里插入图片描述
2018、2019平均收益率如下:
在这里插入图片描述

改变定投金额(设置投入资金固定比例)

在这里插入图片描述

及时止损(即资金最大时收盘)

为了更加细致地得到最大定投收益,我们将定投周期改为日,只定投18、19年,其他不变,找出最大收益的日期为截至定投日期,并计算截至日期之前的平均收益率
这种方法,是基于知道了每日的收盘价,然后计算每天的收益率,当是一年的最大值时就停止定投,类似于”上帝视角“。

def invest(df,invest_cycle,invest_amount):
    '''
    返回每次投资的收益率 
    invest_cycle:定投周期
    invest_amount:定投金额
    '''
    data=df['收盘价']   
    time=list(df.index.values)
    time.append("2020")
       
    rate_dic={}  #记录 每一次的定投的收益率
    total_invest=0
    total_invest_dic={}
    share=0
     
    for i in range(len(data)):   # len(data)=len(time)+1
        if time[i][:4]==time[i+1][:4]:
            if i%invest_cycle==0: # 符合定投日期
                share=share+invest_amount/data[i] #买入
                total_invest=total_invest+invest_amount # 记录定投时的总投资
                total_invest_dic[time[i][:4]]=total_invest     # 记录每次定投的投资
                rate_dic[time[i]]=(share*data[i]/total_invest-1)*100    #每次定投时的收益率             
                
        else: # 一年的最后一天
            if i%invest_cycle==0: # 符合定投日期
                share=share+invest_amount/data[i] #买入
                total_invest=total_invest+invest_amount # 记录定投时的总投资
                total_invest_dic[time[i][:4]]=total_invest     # 记录每次定投的投资
                rate_dic[time[i]]=(share*data[i]/total_invest-1)*100    #每次定投时的收益率          
                         
            share=0   #计算下一年清零
            total_invest=0

    return rate_dic

def date_close(result):
    '''
    返回最大投资的日期
    策略:反向搜索
    计算每日的定投收益率-->确定最大收益的投资截至的日期
    '''         
    dic_18={}  # 记录2018年的定投日期及收益率
    dic_19={}
    key=result.keys()  # 记录定投的日期
    value=result.values()  # 记录定投的收益率
    for i in range(len(list(key))):
        if list(key)[i][:4]=='2018':
            dic_18[i]=list(value)[i]
        else:
            dic_19[i]=list(value)[i]
            
    max1=max(dic_18.values())
    id=list(dic_18.keys())[list(dic_18.values()).index(max(dic_18.values()))]  # 最大值的id
    date_close1=list(key)[id]
    
    max2=max(dic_19.values())
    id=list(dic_19.keys())[list(dic_19.values()).index(max(dic_19.values()))]  # 最大值的id
    date_close2=list(key)[id]
    
    return [max1,max2,date_close1,date_close2]
               
#当 周期为1 
data_1819=get_data(indexID,'20180101','20191231',False)
result=invest(data_1819,1,500)
plt.figure(figsize=(16,6))
plt.title("周期为1 投资金额为500 的每日收益趋势")
plt.xticks([0,50,100,150,200,250,300,350,400,450])
plt.plot(result.keys(),result.values())

在这里插入图片描述

# 截至定投的日期
d=date_close(result)
# 计算此时的平均收益
print("平均收益",(d[0]+d[1])/2)

在这里插入图片描述

发布了19 篇原创文章 · 获赞 21 · 访问量 2252

猜你喜欢

转载自blog.csdn.net/baidu_41304382/article/details/105603487