新闻

公募基金累计收益率、夏普比率、相关系数怎么计算最高效?

2022.10.12

近年来,国内的公募基金处于高速发展阶段,对于基金数据的分析需求也越来越多。我们基于公募基金的公开市场数据和历史净值数据,为大家展示了 DolphinDB 在时间序列数据分析上的一些基础范式和方法,并已将完整教程和代码发布在知乎@DolphinDB。

公募基金公开市场数据预处理

截至 2022 年 7 月,已经面市的公募基金总数约 1 万多只,公开市场数据表的行数与面市公募基金总数相等,所以这个表的数据量相对比较小,我们建议使用 DolphinDB 的维度表进行存储。

  • 数据导入

维度表是分布式数据库中没有进行分区的表,适用于存储不频繁更新的小数据集,可使用 createTable 函数创建。

db.createTable(table=schemaTB, tableName=tbName, sortColumns=`InceptDate)
  • 数据概览

数据导入后,可以执行相关 SQL 语句对维度表数据进行预览。例如:

fundData = loadTable("dfs://publicFundDB", "publicFundData")select top 10 * from fundData
  • 查询综合费率最低的基金

在选购基金的时候,综合费率也会是投资者考量的因素之一,我们同样可以执行相关 SQL 语句查询综合费率最低的基金。例如,查询综合费率最低的 50 只债券型且不是指数型的公募基金, 具体代码如下:

select top 50 * from fundFee where Type == "债券型", not(FullName like "%指数%") order by Fee
  • 按基金类型分组后的信息摘要

如果想查看按基金类型分组后的信息摘要应该怎么做呢?例如统计数据的平均值、最值、计数、标准差,快速计算分位数等。

此时我们将会用到 DolphinDB 内置的 stat 函数、quantile 函数,此外还可以通过 def 自定义一个信息摘要统计函数,然后对 Type 列进行分组计算。

  • 按基金类型分组后的分布直方图

更直观地,我们可以直接在 DolphinDB GUI 中绘图。这里用到 plotHist 函数,可以按基金类型分组绘制分布直方图:

公募基金历史净值数据基础分析

在选购基金的时候,基金的净值数据也会是投资者考量的因素之一,本教程中使用复权净值进行与基金回报率相关的数据分析。

截至 2022 年 7 月,历史净值数据表的数据量大约是 1 千多万条,建议使用 DolphinDB 的分区表进行存储,分区方法是在时间维度按照年为最小单位进行分区。

  • 计算复权净值日收益率

首先我们查询基金的复权净值并通过 panel 函数生成面板数据,然后可以使用 DolphinDB 的 percentChange 函数计算复权净值日收益率,并执行下述代码快速查看部分计算结果:

oriData = select TradeDate, SecurityID, AdjNetValue from fundNetValuepanelData = panel(row=oriData.TradeDate, col=oriData.SecurityID, metrics=oriData.AdjNetValue, rowLabel=workdays, parallel=true)returnsMatrix = panelData.ffill(10).percentChange()returnsMatrix[0:3]
  • 计算基金数量变化

计算公募基金在历史上的数量,并绘图:

fundNum = matrix(rowCount(returnsMatrix)).rename!(returnsMatrix.rowNames(), ["count"])plot(fundNum.loc( ,`count), fundNum.rowNames(), '公募基金在历史上的数量变化', LINE)

  • 计算复权净值季度平均收益率

执行下述代码,计算公募基金的季度平均收益率,并绘制其中一只基金的季度平均收益率曲线:

qavgReturns = returnsMatrix.setIndexedMatrix!().resample("Q", mean) plot(qavgReturns["160211.SZ"], chartType=LINE)

  • 计算各个类型基金的年度平均收益率
    执行下述代码,计算各个类型基金的年度平均收益率,并绘制部分类型基金的年度平均收益柱状图:
yearReturnsMatrix = ((returnsMatrix+1).resample("A", prod)-1).nullFill(0).regroup(fundTypeMap[returnsMatrix.colNames()], mean, byRow=falseyearReturnsMatrix = yearReturnsMatrix.loc( , ["债券型", "股票型", "混合型"])yearReturnsMatrix.loc(year(yearReturnsMatrix.rowNames())>=2014, ).plot(chartType=BAR)

  • 计算夏普比率

在设置筛选条件,并对指标年化后,可以通过如下代码计算夏普比率并生成年化收益率、年化波动率和夏普比率数据表:

sharpe = (exp - 0.028)/volperf = table(uReturnsMatrix.colNames() as SecurityID, fundTypeMap[uReturnsMatrix.colNames()] as Type, exp*100 as exp, vol*100 as vol, sharpe)

基于 perf 数据表进行数据可视化,例如绘制风险收益散点图:

mask = select * from perf where sharpe>0, vol<40, exp<40plot(mask["exp"], mask["vol"], ,SCATTER)

  • 计算年度收益率

年度收益率是指一年期限内,投资收益占投资本金的比率,通常等同于实际收益率。核心代码如下:

yearReturnsMatrix50 = transpose((returnsMatrix50 .setIndexedMatrix!()+1).resample("A", prod)-1).nullFill(0)yearReturnsMatrix50.loc(fundTypeMap[yearReturnsMatrix50.rowNames()] == "股票型", ) //查看指定类型基金的年度收益率
  • 计算相关系数

基金之间的相关系数,刻画的是基金之间的联动性,有利于分散投资,抵御市场行情差带来的风险。核心代码如下:

corrMatrix = pcross(corr, returnsMatrix50)corrMatrix.loc(fundTypeMap[corrMatrix.rowNames()]=="股票型", fundTypeMap[corrMatrix.rowNames()]=="股票型")//查看指定类型之间的相关系数
  • 计算持有区间的累计收益率

在获取 2010 年 1 月 1 日到 2020 年 12 月 31 日买入时的复权净值数据,以及 2020 年 12 月 31 日前买入并持有一年后的复权净值数据后,可执行下述代码计算持有区间的累计收益率:

filterPanelDataTmp, filterPanelData = align(filterPanelDataTmp, filterPanelData)cumulativeReturn = (filterPanelDataTmp - filterPanelData) / filterPanelData

性能对比

我们对 DolphinDB 与 Python Pandas 计算部分指标的性能进行了对比测试,结果如下:

可以看到,DolphinDB 中的函数计算性能普遍优于 Python Pandas 中的函数,并且 DolphinDB 依靠数据存储引擎和计算引擎的高度融合,方便地实现了分布式并行计算,可以有效提高计算效率和节省内存资源。

本教程主要通过公募基金的公开市场数据和历史净值数据在 DolphinDB 中的基础分析案例,介绍了 DolphinDB 时序数据库在时间序列数据分析上的一些基础范式和方法,旨在降低 DolphinDB 初学者们的学习成本,让 DolphinDB 使用者能够快速上手对基金数据进行基础分析。