利用python实现基金定投策略动态评估

发表时间:2020-03-26

2018年,空仓基金夺得股票型基金冠军。“空仓躺赢”体现出2018年投资市场大写的“尴尬”。本文不准备谈论2019年走势如何,单纯从技术角度利用python语言分析基金定投策略对投资收益的影响。

利用python实现基金定投策略动态评估

一、采集数据源:

做数据分析首先需要稳定准确的基金净值数据源,更重要的是免费!

利用python实现基金定投策略动态评估

经过对比研究比较发现sina新浪财经频道的后台提供开放的API接口。调用格式如下:

http://stock.finance.sina.com.cn/fundInfo/api/openapi.php/CaihuiFundInfoService.getNav?symbol="+fundID+"&page=1

其中fundID是基金代码

调用返回的类型是字典类型:

{"result":{"status":{"code":0},"data":{"data":[{"fbrq":"2018-12-31 00:00:00","jjjz":"1.784","ljjz":"1.784"},{"fbrq":"2018-12-28 00:00:00","jjjz":"1.784","ljjz":"1.784"}],"total_num":"2013"}}}

其中jjjz为基金净值数据,ljjz为累计净值数据,total_num为全部数据条数。以每页20条计算,即可计算出基金数据总页数,根据页数进行循环可以获取所有交易日的基金净值数据。

基金数据采集并保存至本地csv文件的代码为:

def FundCap(fundID):
url="http://stock.finance.sina.com.cn/fundInfo/api/openapi.php/CaihuiFundInfoService.getNav?symbol="+fundID+"&page=1"
up=urllib.request.urlopen(url)
cont=eval(up.read())
#print (cont['result']['data']['total_num'])
item_count = cont['result']['data']['total_num']
page_count = math.ceil(int(item_count) / 20)
cont = None
fund_file = open('./store/' + fundID + '.csv', 'w')
curpage = page_count
while curpage > 0:
url = "http://stock.finance.sina.com.cn/fundInfo/api/openapi.php/CaihuiFundInfoService.getNav?symbol=" + fundID + "&page=" + str(curpage)
up = urllib.request.urlopen(url)
cont = eval(up.read())
for item in reversed(cont['result']['data']['data']):
total_net_value = item['ljjz']
net_value = item['jjjz']
datetime = item['fbrq']
fund_file.write(datetime+ ','+ net_value + ',' + total_net_value + '\n')
curpage = curpage - 1
fund_file.close()

二、设计循环策略:

根据当前主流定投软件的定投规则,设计以下三个循环评估策略:

1. 对该基金时间周期进行循环评估,循环项4个:近一年、近两年、近三年、成立以来。

2. 对不同的止盈策略进行循环评估,循环项12个:10%、20%、30%、40%、50%、60%、70%、80%、90%、100%、1000%、10000%(长期持有策略)。

3. 对不同的定投日期进行循环评估,循环项6个:周一、周二、周三、周四、周五、每天。

循环策略决定了策论的评估周期,即:若评估近一年的定投策略优劣需要进行6*12=72轮计算,若要完成4个时间周期的策略评估需要288轮计算。

其实笔者还曾加入带回撤率的平仓策略以及50%/80%平仓策略,因为测试结果对基金投资收益影响不明显,所以这两个策略被暂时精简掉。

for startp in [ValSize - 257, ValSize - 514, ValSize - 770, 0]: #
if startp < 0:
continue
for StopRate in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7 ,0.8, 0.9, 1, 10, 100]:
for weekday in [0,1,2,3,4,None]: #None,
anarob.nStep = startp
anarob.ValSize = ValSize
anarob.cond_weekday = weekday
anarob.StopRate = StopRate
ProfitRate = anarob.Go()
nLoop = nLoop + 1
if ProfitRate > MaxProfitRate:
MaxProfitRate = ProfitRate
MaxCond_weekday = weekday
MaxCost = anarob.MaxCost
MaxStopRate = StopRate
if weekday is not None:
weekstr = weekdaystr[weekday]
else:
weekstr = '每天'
print("[Idx=%d][StopRate=%.02f, MaxProfitRate=%.02f;MaxCost=%.02f]%s" % (nLoop, StopRate, ProfitRate,anarob.MaxCost, weekstr))
if MaxCond_weekday is not None:
weekstr = weekdaystr[MaxCond_weekday]
else:
weekstr = '每天'
print("[%s]Final[LoopSum=%d][start=%s|end=%s]:[StopRate=%.02f%%, MaxProfitRate=%.02f;MaxCost=%.02f]%s" % (
reader.filename, nLoop, anarob.start_time, anarob.end_time, MaxStopRate * 100, MaxProfitRate, MaxCost, weekstr))
MaxProfitRate = 0

三、定投机器人设计:

定投机器人类AnaRob是全文设计的核心,也是可以灵活调整定投策略的投资者原型。定投机器人每次触发定投条件会自动定投1000元资金,根据当前净值计算持仓份额,并且逐日盯市决定是否触发止盈条件,若触发止盈条件则立即平仓获利,随后继续定投,自动开启下一轮定投周期。

class AnaRob():
def Cond_1(self,key): #星期判断
if not self.cond_weekday:
return True
curdatetime = datetime.datetime.strptime(key, "%Y-%m-%d %H:%M:%S")
if curdatetime.weekday() == self.cond_weekday:
return True
else:
return False
def Cond_2(self,key): #时间判断
if not self.cond_time:
return True
curdatetime = datetime.datetime.strptime(key, "%Y-%m-%d %H:%M")
time = key[11:]
if time == self.cond_time:
return True
else:
return False
def Condition(self,key):
if self.Cond_1(key) and self.Cond_2(key):
return True
else:
return False
def CountLoop(self,key):
if self.Condition(key):
self.Loop = self.Loop + 1
def TriggerBuy(self,key):
if self.Condition(key):
return True
else:
return False
def TriggerCloseStopRate(self, val):
if ((val * self.PosiAmt - self.PosiCost) / self.PosiCost) > self.StopRate:
return True
else:
return False
#带回撤判断的平仓策略
def TriggerCloseRetrace(self, val):
if self.Ready2Retrace is False:
if ((val * self.PosiAmt - self.PosiCost) / self.PosiCost) > self.StopRate:
self.TopPrice = val
self.Ready2Retrace = True
else:
return False
else:
if val > self.TopPrice:
self.TopPrice = val
return False
if (self.TopPrice - val)/self.TopPrice > self.RetraceRate:
self.Ready2Retrace = False
return True
else:
return False
def TriggerClose(self, val):
if self.PosiCost <= 0:
return False
return self.TriggerCloseStopRate(val)
def InputData(self, keyval):
self.KeyVal=keyval
self.ValSize = len(self.KeyVal[1])
def DoCloseRate(self, val, rate = 1):
self.Profit = self.Profit + ((val * self.PosiAmt - self.PosiCost) * rate)
if self.PosiCost > self.MaxCost:
self.MaxCost = self.PosiCost
self.PosiAmt = self.PosiAmt * (1 - rate)
self.PosiCost = self.PosiCost * (1 - rate)
self.ProfitRate = self.Profit / self.MaxCost * 100
def DoClose(self,val):
#平50%、平80%策略并没有明显改善,策略弃!
self.DoCloseRate(val)
def Go(self):
self.PosiAmt=0
self.PosiCost=0
self.Profit=0
#self.nStep = 0
self.Loop=0
self.MaxCost=0
self.ProfitRate=0
self.start_time = self.KeyVal[0][self.nStep]
self.end_time = self.KeyVal[0][self.ValSize - 1]
self.finalCloseP = 0.0
while self.nStep < self.ValSize:
Key = self.KeyVal[0][self.nStep]
Val = self.KeyVal[1][self.nStep]
self.finalCloseP = Val
self.CountLoop(Key)
if self.TriggerClose(Val):
self.DoClose(Val)
if self.TriggerBuy(Key):
self.PosiAmt = self.PosiAmt+self.BuyAmt / Val
self.PosiCost = self.PosiCost + self.BuyAmt #self.BuyAmt*Val
self.nStep = self.nStep + 1
self.DoClose(self.finalCloseP)
#print("loop:%d" % self.Loop)
return self.ProfitRate

四、评估测算结果举例:

易方达消费行业股票(110022 )作为测试用例进行模拟下单测算,得到如下结果:

一年内该基金的定投最大收益率为-16.69%,最低收益率为-17.24%。“空仓躺赢”得到充分验证。

二年内该基金的定投最大收益率为7.35%,最佳止盈率为30%,若每次定投1000元,那么最大占用资金为56000元。最佳投资日期为星期四。最糟糕的定投策略是止盈率设置在了40%以上,并且定投日期为星期五,两年来的定投收益率为-9.65%。可见定投策略对于投资收益影响非常大!!

三年内该基金的定投最大收益率为56.06%,最佳止盈率为60.00%,最大占用资金103000元,最佳投资日期为星期四。

该基金成立以来定投最大收益率为113%,最佳止盈率为70.00%,最大占用资金228000,最佳投资日期为星期三。

根据评测的结果,大家可以根据自身的资金额度设置定投策略,并且在触发止盈率的时候理性止盈。虽然在2018年熊市的影响下基金市场一片惨淡,但随着政策底的逐渐明朗,希望大家在2019年能够抓住机会,画出一条完美的“微笑曲线”。

利用python实现基金定投策略动态评估

此外,笔者还对其他不同类型的基金进行了测算,这里就不一一介绍,感兴趣的朋友可以根据以上的策略自行模拟。

fundID = '110022' #易方达消费
fundID = '020003' #国泰金龙
fundID = '000742' #国泰新经济
fundID = '519068' #汇添富成长
fundID = '160212' #国泰估值优势LOF
fundID = '020026' #国泰成长
fundID = '110011' #易方达中小盘
fundID = '161725' #招商中证白酒
fundID = '519193' #纳斯达克QDII
fundID = '005176' #国富精准医疗灵活配置混合
fundID = '003096' #中欧医疗健康混合C

文章来源互联网,尊重作者原创,如有侵权,请联系管理员删除。邮箱:417803890@qq.com / QQ:417803890


Python Free

邮箱:417803890@qq.com
QQ:417803890

皖ICP备19001818号
© 2019 copyright www.pythonf.cn - All rights reserved

微信扫一扫关注公众号:

联系方式

Python Free