利用python比较股票定投和一次性投资收益效果。最终发现,当股市上涨时,定投收益低于一次性投资;当股市下跌时,定投优于一次性投资,定投收益可以在股市下跌后的第一次反弹时迅速有力的回升。并且,一次性投资收益基本处于随机状态,定投则可以跟随股市趋势变动
import tushare as ts
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import copy
plt.rcParams['font.sans-serif']=['simhei']#用于正常显示中文标签
plt.rcParams['axes.unicode_minus']=False#用于正常显示负号
pro=ts.pro_api()
class InvestmentStrategy():
def __init__(self,ts_code):
self.__basic_parameters()
self.ts_code=ts_code
self.__get_data()
def __basic_parameters(self):
"""基础参数"""
self.cycle=100#投资周期(天)
self.per_cycle=5#定投间隔时间(天)
self.init_fund=1000#定投初始建仓资金(元)
self.per_fund=100#每期定投金额(元)
#定投智能参数
self.auto=True#是否使用智能定投
self.critical_point=0.03#涨跌幅度调整临界值
def __get_data(self):
"""获得股票数据"""
self.stock = pro.daily(ts_code=self.ts_code)[['ts_code','trade_date','close','pct_chg']]
self.stock=pd.DataFrame(self.stock)
self.stock.sort_index(ascending=False,inplace=True)
self.stock.index=range(len(self.stock))
def fixed_investment(self):
"""定额投资"""
#self_stock=copy.deepcopy(stock_0)
self.stock['fixed_rate']=0.000#定额投资
self.stock['general_rate'] = 0.000#普通投资
for i in self.stock.index[:(-1*self.cycle)]:
#i=5
stock=self.stock[i:(i+self.cycle)]
number =self.init_fund/stock.ix[i,'close']
self.cost=self.init_fund#总投资成本
for j in stock.index[::self.per_cycle]:
#j=7
per_fund = self.per_fund
if self.auto==True:
per_fund=self.__change_per_fund(day_rate=stock.ix[j,'pct_chg'])
elif self.auto==False:
per_fund=self.per_fund
number_=per_fund/stock.ix[j,'close']
number+=number_
self.cost+=per_fund
for j in (set(stock.index)-set(stock.index[::self.per_cycle])):
day_rate=stock.ix[j,'pct_chg']
if day_rate < -1 * self.critical_point:
per_fund += self.per_fund * ((-1 * self.critical_point - day_rate) * 100)
number_ = per_fund / stock.ix[j, 'close']
number += number_
self.cost += per_fund
rate=(stock.ix[i+self.per_cycle,'close']*number-self.cost)/self.cost/self.cycle*360
self.stock.ix[(i+self.cycle),'fixed_rate']=rate
#用相同的资金进行普通的一次性投资,计算收益
number = self.cost / stock.ix[i, 'close']
rate=(stock.ix[i+self.per_cycle,'close']*number-self.cost)/self.cost/self.cycle*360
self.stock.ix[(i + self.cycle), 'general_rate'] = rate
print('已经完成{}%'.format(round(i/len(self.stock),4)*100))
def __change_per_fund(self,day_rate):
"""根据涨跌幅度及时调整每期定投金额
day_rate为当天涨跌幅度
"""
per_fund = self.per_fund
#如果当天跌幅超过一定点,则多加仓;如果涨幅高于一定点,则少加仓
if day_rate>self.critical_point:
per_fund=self.per_fund/((day_rate-self.critical_point)*100)
elif day_rate<-1*self.critical_point:
per_fund += self.per_fund *(( -1* self.critical_point-day_rate) * 100)
return per_fund
def compare(self,start_date,end_date):
"""将两种投资方式的收益率进行比较"""
stock = copy.deepcopy(self.stock)
stock.index=stock['trade_date']
stock=stock.ix[start_date:end_date,:]
print(stock[['fixed_rate','general_rate']].describe())#m描述性统计分析比较
plt.figure(figsize=(12,8))
plt.grid(True,alpha=0.3)
plt.plot(stock['trade_date'],stock['fixed_rate'],label='定额投资')
plt.plot(stock['trade_date'], stock['general_rate'],label='一次性投资')
plt.legend(fontsize=14)
plt.xlabel('日期',fontsize=15)
plt.ylabel('收益率',fontsize=15)
plt.title(str(self.ts_code)+'收益率比较图',fontsize=18)
close = plt.twinx()
close.plot(stock['trade_date'], stock['close'], label='收盘价', color='black')
close.set_ylabel('收盘价', fontsize=15)
plt.xticks(stock['trade_date'].values[::200],rotation=270)
def single_invstment(self,start_date,end_date):
"""在一只股票上各个期限的定投"""
stock = copy.deepcopy(self.stock)
stock.index = stock['trade_date']
stock = stock.ix[start_date:end_date, :]
stock.index=range(len(stock))
stock['fixed_rate'] = 0.000 # 定额投资收益
stock['fixed_year_rate']=0.000#年化收益率
stock['fixed_number']=0.000#定额投资股票份数
stock['fixed_value']=0.000#定额投资股票价值
stock['cost']=0.000#投资股票所需要的成本
stock['general_rate'] = 0.000 # 普通投资收益
#投入初始建仓资金
stock.ix[0,'cost'] =self.init_fund
stock['fixed_value'] =self.init_fund
stock.ix[0,'fixed_number']=self.init_fund/stock.ix[0,'close']
for i in stock.index[1:]:
if i%self.per_cycle==0:
stock.ix[i,'fixed_number'] =stock.ix[i-1,'fixed_number']+self.per_fund/stock.ix[i,'close']
stock.ix[i,'cost'] =stock.ix[i-1,'cost']+self.per_fund
stock.ix[i,'fixed_value']=stock.ix[i,'fixed_number']*stock.ix[i,'close']
stock.ix[i,'fixed_rate']=(stock.ix[i,'fixed_value']-stock.ix[i,'cost'])/stock.ix[i,'cost']
stock.ix[i,'fixed_year_rate']=stock.ix[i,'fixed_rate']/(i+1)*360
stock.ix[i,'general_rate']=(stock.ix[i,'close']-stock.ix[0,'close'])/stock.ix[0,'close']
else:
stock.ix[i, 'fixed_number']=stock.ix[i-1, 'fixed_number']
stock.ix[i, 'cost']=stock.ix[i-1,'cost']
stock.ix[i, 'fixed_value'] = stock.ix[i, 'fixed_number'] * stock.ix[i, 'close']
stock.ix[i, 'fixed_rate'] = (stock.ix[i, 'fixed_value'] - stock.ix[i, 'cost']) / stock.ix[i, 'cost']
stock.ix[i, 'fixed_year_rate'] = stock.ix[i, 'fixed_rate'] / (i + 1) * 360
stock.ix[i,'general_rate']=(stock.ix[i,'close']-stock.ix[0,'close'])/stock.ix[0,'close']
self.stock=stock
if __name__=='__main__':
ts_code = '000002.SZ'
invest_strategy=InvestmentStrategy(ts_code)
invest_strategy.cycle=100
invest_strategy.fixed_investment()
invest_strategy.compare(start_date='20091202',end_date='20161116')
invest_strategy.single_invstment(start_date='20131202',end_date='20200616')
invest_strategy.compare(start_date='20151202',end_date='20190616')
stock=invest_strategy.stock