背景
今天,尝试一下基于Python开发基金实战可视化之比较超过3只基金的趋势,遇到日期不一样,怎么优化整合?
分析
实质上就是在日期段没数据时补空值
开门见山看效果
运行效果图如下所示:
方案
上图以累计净值为例进行趋势类比。
重点需要关注的方面有:
1、通过execjs.compile方法读js文件内容。
2、解析js数据。
3、通过merge方法合并pandas数据结构对象,此处需要特别注意的是需要做一次赋值(merge方法return后的才是合并结果,不会改变self)。
4、日期的展示,需要设置为index并排序。
5、保存整合后的数据为csv文件。
核心代码如下:
# 比较超过3只基金的趋势,日期不一样时有做优化整合
def compare3mfsACWorth(fscodes, fstype):
# 获取绝对路径,funddata为当前文件夹
curpath = os.path.join(os.path.dirname(__file__), 'funddata')
# 初始化汇总序列
pdACWorthTrend = pd.DataFrame()
# 定义字段名
colSet = ['Date']
# 定义title
tname = fstype + ": "
name = []
code = []
# 循环逐个执行fscodes
for fs in fscodes:
# 文件操作
fileName = fs + 'content.js'
file_object_path = os.path.join(curpath, fileName)
f = open(file_object_path, 'r', encoding='utf-8')
content = f.read()
f.close()
jsContent = execjs.compile(content)
# 基金名称及代码
name.append(jsContent.eval('fS_name'))
code.append(jsContent.eval('fS_code'))
# 累计净值走势=单位净值+累计分红
ACWorthTrendData = jsContent.eval('Data_ACWorthTrend')
ACWorthTrend = [v[1] for v in ACWorthTrendData]
# x轴:日期。因为系统是毫秒级timeStamp故此需要除以1000取秒级timeStamp,否则转换后的日期不对
# vtimeStamp = [int(v[0] / 1000) for v in ACWorthTrendData1] # // 算法符号的结果可以直接取整
# xs = pd.to_datetime(vtimeStamp, unit='s') # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
# x轴:日期。获取年月日需要除以(1000 *24*3600),因为系统是毫秒级timeStamp。
vtimeStamp = [int(v[0] / (1000 * 24 * 3600)) for v in ACWorthTrendData] # // 算法符号的结果可以直接取整
xs = pd.to_datetime(vtimeStamp, unit='D') # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
# 提取x、y1、y2轴数据并整合, pd.merge适用于Series数据类型
# 设置y轴数据
sACWorthTrend = pd.Series(ACWorthTrend, name='ACWorth_' + fs)
# 设置x轴数据
stimeStamp = pd.Series(xs, name=colSet[0])
pdACWorthTrendTmp = pd.merge(stimeStamp, sACWorthTrend, left_index=True, right_index=True)
if pdACWorthTrend.empty:
pdACWorthTrend = pdACWorthTrendTmp
tname += fs
else:
# 合并数据
pdACWorthTrend = pdACWorthTrend.merge(pdACWorthTrendTmp, how='outer', on=colSet[0])#, suffixes=('_' + code))
tname += ' vs ' + fs
tname += " " + u"趋势类比"
# 设置索引为Date列
pdACWorthTrend.set_index(colSet[0], inplace=True)
# 以日期排序,但是存在csv文件的依然有部分没有顺序存储
pdACWorthTrend.sort_index()
# 存数据fstype
fileName = fstype + '.csv'
file_object_path = os.path.join(curpath, fileName)
pdACWorthTrend.to_csv(file_object_path)
# 当for循环有两个需要迭代的对象时,要用zip对这多个变量封装,否则会报错“too many values to unpack”
cols = []
for n, c in zip(name, code):
cols.append(n + '_' + c)
# 设置新列
pdACWorthTrend.columns = cols
# 趋势图类比
# 主次轴差异化显示
# tech_df.plot(secondary_y=colSet[2], grid=True)
# 主轴显示
pdACWorthTrend.plot()
ax = plt.gca() # 表明设置图片的各个轴,plt.gcf()表示图片本身
ax.xaxis.set_major_formatter(mdate.DateFormatter(
'%Y-%m-%d')) # 横坐标标签显示的日期格式;注意,如果不加语句plt.gca().xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d')),则横坐标只显示年份
plt.xlabel(u'日期')
plt.ylabel(u'累计净值')
plt.title(tname)
# plt.text('2017-01-01', 0.65, showStr)
plt.gcf().autofmt_xdate() # 自动旋转日期标记
# plt.tight_layout()
# 测试代码开始————————————————————————————————————————————————————————————————————————————————
# 测试代码结束————————————————————————————————————————————————————————————————————————————————
plt.show()
return