智能定投——均线偏离法(手工测试)
#初始化
import pandas as pd
import seaborn as sns
import random as rand
from datetime import datetime
#指定要跟踪的指数和定投的基金等
SECURITY ='000001.XSHG' #000001.XSHG 上证综指 #000300.XSHG 沪深300 #000905.XSHG 中证500
AIP_FUND ='510210.XSHG' #510210.XSHG #富国上证综指ETF #159919.XSHE #嘉实沪深300ETF #510580.XSHG #易方达中证500ETF
START_DATE='2005-01-05' #取数的开始日期,上证综指不能早于'2005-01-05',沪深300不能早于’2005-04-08',中证500不能早于'2007-01-15'
END_DATE='2016-01-05' #取数、测算的结束日期
START_CAL_DATE='2015-01-05' #测算起始日期(如果要用10年均线测算,起始日期必须晚于取数开始日期+10年)
STD_AMOUNT =100 #基准定投金额
pop=[2,1,1] #指定均线种类、偏离度和级差
'''
第1位记录均线种类,取值范围[0-4],分别表示:120日、180日、250日、500日、10年均线
第2位记录偏离度,取值范围[0,2],分别表示:
0:广发 (-n,-40),[-40,-30),[-30,-20),[-20,-10),[-10,-5),[-5,0),(0,15],(15,50],(50,100],(100,n)
1: 富国 (-n,-45),[-45,-35),[-35,-25),[-25,-15),[-15,-5),[-5,5),[5,20),[20,35),[35,50),[50,n)
2: 博时 cls/avg<=0.9,0.9<cls/avg<=1.1,cls/avg>=1.1
第3位记录级差,取值范围[0,2],分别表示:10%、20%、30%
'''
#获取历史数据
security_data=get_price(SECURITY,START_DATE,END_DATE,fields=['price','close']) #跟踪的指数
aip_fund_data=get_price(AIP_FUND,START_CAL_DATE,END_DATE,fields=['price']) #定投的基金
#获取START_CAL_DATE在security_data中的index
cal_date=pd.DatetimeIndex([datetime.strptime(START_CAL_DATE,'%Y-%m-%d')])[0]
i=0
while (i<len(security_data)):
if(security_data.index[i]>=cal_date):
index=i
break
else:
i+=1
#检查录入的均线、偏离度、级差是否正确
if(pop[2]>2):
print('编码第3位:',pop[2],' 超出级差取值范围')
sys.exit()
if(pop[1]>2):
print('编码第2位:',pop[1],' 超出偏离度取值范围')
sys.exit()
if(pop[0]>4):
print('编码第1位:',pop[0],' 超出均线种类取值范围')
sys.exit()
if(pop[0]==4 and (security_data.index[i]<pd.DatetimeIndex([datetime.strptime('2015-01-05','%Y-%m-%d')])[0])):
print('均线是10年均线,但历史数据不足10年')
sys.exit()
#求index日指数的前num日均线值
def mav(security_data,index,num):
if(index-num<0):
print('现有数据不足以计算此均值,最早日期为: ',temp_security.index[0],'超出天数为: ',-e.value)
sys.exit()
j=index-1
sumv=0.0
while (j>=index-num and j>=0):
sumv=sumv+security_data.iloc[j][1]
j=j-1
mav=sumv/num
return mav
#解码函数
'''
第1位记录均线种类,取值范围[0-4],分别表示:120日、180日、250日、500日、10年均线
第2位记录偏离度,取值范围[0,2],分别表示:
0:广发 (-n,-40),[-40,-30),[-30,-20),[-20,-10),[-10,-5),[-5,0),(0,15],(15,50],(50,100],(100,n)
1: 富国 (-n,-45),[-45,-35),[-35,-25),[-25,-15),[-15,-5),[-5,5),[5,20),[20,35),[35,50),[50,n)
2: 博时 price/avg<=0.9,0.9<price/avg<=1.1,price/avg>=1.1
第3位记录级差,取值范围[0,2],分别表示:10%、20%、30%
'''
def decode(pop,index):
temp_p=pop
fd_index=index
#计算START_CAL_DATE日个体编码对应的均线值
if(temp_p[0]==0):
mavg=mav(security_data,fd_index,120)
print('均线:120日')
elif(temp_p[0]==1):
mavg=mav(security_data,fd_index,180)
print('均线:180日')
elif(temp_p[0]==2):
mavg=mav(security_data,fd_index,250)
print('均线:250日')
elif(temp_p[0]==3):
mavg=mav(security_data,fd_index,500)
print('均线:500日')
elif(temp_p[0]==4):
mavg=mav(security_data,fd_index,2426) #10年均线按2426个工作日算(基于2005-1-5到2015-1-4计算得到)
print('均线:10年(2426日)')
else:
sys.exit()
if(temp_p[1]==0):
print('偏离率: 广发')
elif(temp_p[1]==1):
print('偏离率: 富国')
elif(temp_p[1]==2):
print('偏离率: 博时')
else:
sys.exit()
if(temp_p[2]==0):
print('级差: 10%')
elif(temp_p[2]==1):
print('级差: 20%')
elif(temp_p[2]==2):
print('级差: 30%')
else:
sys.exit()
aip_index=0
amount=0.0
quantity=0.0
fitness=0.0
nav=[]
std_amount=0.0 #普通定投
std_quantity=0.0 #普通定投
std_nav=[] #普通定投
while(fd_index<len(security_data)):
#0:广发 (-n,-40),[-40,-30),[-30,-20),[-20,-10),[-10,-5),[-5,0),(0,15],(15,50],(50,100],(100,n)
if(temp_p[1]==0):
rod=(security_data.iloc[fd_index][1]-mavg)*100/mavg #security_data.iloc[j][1] 表示close,用close计算偏离率
if(rod<-40):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*6))
elif(rod<-30):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*5))
elif(rod<-20):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*4))
elif(rod<-10):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*3))
elif(rod<-5):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*2))
elif(rod<0):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*1))
elif(rod<=15):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.1*1))
elif(rod<=50):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.1*2))
elif(rod<=100):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.1*3))
else:
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.1*4))
amount += in_amount
quantity += in_amount/aip_fund_data.iloc[aip_index][0]
nav.append (amount/quantity)
print('日期: ',aip_fund_data.index[aip_index],' 指数收盘价: ',security_data.iloc[fd_index][1],' 指数均值: ',mavg,' 偏离率:',rod,\
' 基金净值: ',aip_fund_data.iloc[aip_index][0],' 购买金额: ',in_amount,' 总金额: ',\
amount,' 总数量: ',quantity,' 成本净值: ',nav[aip_index])
#1: 富国 (-n,-45),[-45,-35),[-35,-25),[-25,-15),[-15,-5),[-5,5),[5,20),[20,35),[35,50),[50,n)
elif(temp_p[1]==1):
rod=(security_data.iloc[fd_index][1]-mavg)*100/mavg
if(rod<-45):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*5))
elif(rod<-35):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*4))
elif(rod<-25):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*3))
elif(rod<-15):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*2))
elif(rod<-5):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*1))
elif(rod<5):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1*0))
elif(rod<20):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.05*1))
elif(rod<35):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.05*2))
elif(rod<50):
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.05*3))
else:
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.05*4))
amount += in_amount
quantity += in_amount/aip_fund_data.iloc[aip_index][0]
nav.append (amount/quantity)
print('日期: ',aip_fund_data.index[aip_index],' 指数收盘价: ',security_data.iloc[fd_index][1],' 指数均值: ',mavg,' 偏离率:',rod,\
' 基金净值: ',aip_fund_data.iloc[aip_index][0],' 购买金额: ',in_amount,' 总金额: ',\
amount,' 总数量: ',quantity,' 成本净值: ',nav[aip_index])
#2: 博时 price/avg<=0.9,0.9<price/avg<=1.1,price/avg>=1.1
elif(temp_p[1]==2):
rod=security_data.iloc[fd_index][1]/mavg
if(rod<=0.9):
in_amount=(STD_AMOUNT*(1+(temp_p[2]+1)*0.1))
elif(rod<1.1):
in_amount=STD_AMOUNT
else:
in_amount=(STD_AMOUNT*(1-(temp_p[2]+1)*0.1))
amount += in_amount
quantity += in_amount/aip_fund_data.iloc[aip_index][0]
nav.append (amount/quantity)
print('日期: ',aip_fund_data.index[aip_index],' 指数收盘价: ',security_data.iloc[fd_index][1],' 指数均值: ',mavg,' 偏离率:',rod,\
' 基金净值: ',aip_fund_data.iloc[aip_index][0],' 购买金额: ',in_amount,' 总金额: ',\
amount,' 总数量: ',quantity,' 成本净值: ',nav)
else:
print('个体编码第2位:',temp_p[1],' 超出现有偏离度种类')
sys.exit()
std_amount+=STD_AMOUNT
std_quantity+=STD_AMOUNT/aip_fund_data.iloc[aip_index][0]
std_nav.append(std_amount/std_quantity)
if(fd_index==(len(security_data)-1)):
fitness=(aip_fund_data.iloc[aip_index][0]-nav[aip_index])*quantity
print('总投入金额: ',amount,' 总数量: ',quantity,' 成本净值: ',nav[aip_index],' 基金当前净值: ',aip_fund_data.iloc[aip_index][0],\
' 总收益: ',fitness,' 普通定投金额: ',std_amount,' 普通定投数量: ',std_quantity,' 普通定投成本净值: ',std_nav[aip_index])
#设置横坐标和纵坐标的名称
plt.xlabel('Date')
plt.ylabel('Net value')
# 图的标题
plt.title('Net value of the fund & cost')
# 定义线条
line1 = plt.plot(aip_fund_data.index, aip_fund_data,label='fund')
plt.setp(line1, color='r', linewidth=2.0)
line2 = plt.plot(aip_fund_data.index, nav,label='cost')
plt.setp(line2, color='b', linewidth=2.0)
line3 = plt.plot(aip_fund_data.index,std_nav,label='std_cost')
plt.setp(line3, color='k', linewidth=2.0)
plt.legend()
fd_index+=1
aip_index+=1
decode(pop,index)