Python预测基金净值:keras神经网络
如何搭建神经网络预测基金净值
有一种观点:利用股票历史股价数据,搭建神经网络深度学习,预测股票未来走势,是外行人士的发神经。原因不外乎这些:首先,现有的量价指标等分析工具,远比仅研究历史股价数据靠谱;其次,涨停板的限制、新股N个涨停、停盘之后的补涨补跌等等,是股价历史数据自身无法解释和预测的;最后,不同股票差异太大,有人做出这种“归一化”:某日收盘价 / 历史最高收盘价,非常荒谬(应该采用每日涨跌幅)。
与此相反,搭建神经网络预测基金(指开放式基金)净值,则相对有意义:
1、股票的量价指标公式,通常不能用于基金分析(没有成交量)
2、基金本身并没有涨停板、停盘之类的干扰
3、基金的每日涨跌幅是现成的重要数据,可由基金每日净值简单计算
本文是上一篇《Python基金数据实战分析:偏债混合基金篇》的延续,沿用了其中的爬基金数据的方法(借鉴照搬了前人的经验)。此外,开发环境需安装keras(用tensorflow2.X自带的keras即可)。
关于keras,可参考:keras中文文档
一、时间窗口
总长度为N的一系列数据,定义为p0,p1,…,pN-1,其中pi是第i天的数值,0≤i<N。 再定义一个固定大小的移动窗口w(实际上就是神经网络的input_size),该窗口大小的数据即是一个输入数据。
对于窗口数据,有不同的处理方法。主要有以下两种:
一、窗口不重叠
每次将窗口向右移动w个单位,使得所有移动窗口中的数据之间不重叠。用一个(或k+1个)移动窗口中的内容Wt来预测下一个Wt+1,亦即通过训练神经网络学习函数f,使得:Wt+1 = f(Wt),或Wt+1 = f(Wt, Wt-1, …, Wt-k)。这种方法可以预测窗口大小的未来日期的数值。
假定窗口大小3,用2个移动窗口预测下一个,那么训练样例如下:
Input1 = [[p0, p1, p2], [p3, p4, p5]], Label1 = [p6, p7, p8]
Input2 = [[p3, p4, p5], [p6, p7, p8]], Label2 = [p9, p10, p11]
…
二、窗口可重叠
每次将窗口向右移动1个单位(或多个单位),因此所有移动窗口中的数据之间可以重叠。用一个移动窗口中的内容Wt(即 ptw, ptw+1, …, p(t+1)w-1 )来预测下一个p(t+1)w,亦即通过训练神经网络学习函数f,使得:p(t+1)w = f(Wt)。这种方法可以预测下一天的数值。
假定窗口大小5,每次将窗口右移1个单位,那么训练样例如下:
Input1 = [[p0, p1, p2, p3, p4]], Label1 = [p5]
Input2 = [[p1, p2, p3, p4, p5]], Label2 = [p6]
…
神经网络模型可以用RNN(LSTM),也可以用普通的网络(CNN或全连接)。简单地说,普通网络不区分窗口内部的数据,而LSTM网络则越远的数据权重越小。本文先构造一个简单的2个隐藏层的全连接网络。
二、爬基金数据,准备作为训练集、验证集、测试集
import requests
import time
import execjs
fileTrain = './data/accTrain.csv'
jjTrain = ['004609', '004853', '005524', '005824', '007749']
fileTest = './data/accTest.csv'
jjTest = '007669'
def getUrl(fscode):
head = 'http://fund.eastmoney.com/pingzhongdata/'
tail = '.js?v='+ time.strftime("%Y%m%d%H%M%S",time.localtime())
return head+fscode+tail
# 根据基金代码获取净值
def getWorth(fscode):
content = requests.get(getUrl(fscode))
jsContent = execjs.compile(content.text)
#单位净值走势
netWorthTrend = jsContent.eval('Data_netWorthTrend')
#累计净值走势
ACWorthTrend = jsContent.eval('Data_ACWorthTrend')
netWorth = []
ACWorth = []
for dayWorth in netWorthTrend[::-1]:
netWorth.append(dayWorth['y'])
for dayACWorth in ACWorthTrend[::-1]:
ACWorth.append(dayACWorth[1])
return netWorth, ACWorth
ACWorthFile = open(fileTrain, 'w')
for code in jjTrain:
try:
_, ACWorth = getWorth(code)
except:
continue
if len(ACWorth) > 0:
ACWorthFile.write(",".join(list(map(str, ACWorth))))
ACWorthFile.write("\n")
print('{} data downloaded'.format(code))
ACWorthFile.close()
ACWorthTestFile = open(fileTest, 'w')
_, ACWorth = getWorth(jjTest)
if len