算收益,用算术平均好还是几何平均好?
假设我们已构建一套投资策略,并通过回测工具获取了该策略的每日历史回测收益数据。下一步的核心工作是对策略进行全面评估,包括其有效性、风险水平及收益表现,QuantStats的设计目标即在于此。
Quantstats是 Ran Aroussi 的一个开源项目,是一款用于交易策略绩效分析的 Python 库,深受量化圈用户喜爱,在 Github 上获得了超过 5.8k 的 stars。
它主要由3部分组成:
由于前段时间原作者长期未维护,导致新安装的 Quantstats,尤其是在 Python 3.12 及以上高版本中,几乎无法运行,因此,前段时间我们出手维护,带来了Quantstats Reloaded,欢迎大家安装使用!
!pip install quantstats-reloaded
评价策略表现的具体量化依据为各类指标,例如: 信息比率、夏普比率、最大回撤,以及 α 收益、β 收益 等。需明确的是,这些指标的计算遵循客观、标准化的公式,具备严格的数理规则;但对指标结果的解读与评价则具有主观性,往往与使用者的风险偏好相关。
tip
光是QuantStats中的Stats库下就有几十种计算指标。我们今天先来介绍Stats库中的compsum()、comp()、expected_return() 这三个函数,看看这三个函数有什么用处?它们之间有着怎样的联系呢?
基础统计
1. compsum(): 将收益率序列转换为累积复合收益率序列(累积乘积)
函数: compsum(returns)
# 参数介绍
returns(pd.Series, 推荐)
• 收益率序列,通常是日收益率数据
格式: [0.01, -0.02, 0.03, ...]
• 表示1%, -2%, 3%
• 计算公式: (1 + returns).cumprod() - 1
# 示例用法
returns = pd.Series([0.01, -0.02, 0.03, -0.01, 0.02])
cumulative = qs.stats.compsum(returns)
# 输出结果
[0.01, -0.0098, 0.0207, 0.0105, 0.0307]
tip

2. comp() : 计算总复合收益率(最终累积收益)- 整个期间的总收益率
函数: comp(returns)
#参数介绍
returns(pd.Series, 推荐)
• 收益率序列
计算公式: (1 + returns).prod() - 1
• 等同于 compsum() 的最后一个值
# 示例用法
returns = pd.Series([0.01, -0.02, 0.03, -0.01, 0.02])
total_return = qs.stats.comp(returns)
print(f"总收益率: {total_return:.4f}")
# 等价计算方法
cumulative = qs.stats.compsum(returns)
print(f"最后值: {cumulative.iloc[-1]:.4f}")
tip
3. expected_return() : 计算期望收益率(几何平均数)
函数: expected_return(returns, aggregate=None, compounded=True, prepare_returns=True)
#参数介绍
returns(pd.Series, 推荐)
•收益率序列
aggregate(str, 可选)
• 聚合周期: 'D'(日), 'W'(周), 'M'(月), 'Q'(季), 'Y'(年)
compounded(bool, 默认=True)
• 是否使用复合收益率计算
prepare_returns(bool, 默认=True)
• 是否预处理数据(去除NaN等)
# 示例用法
returns = pd.Series([0.01, -0.02, 0.03, -0.01, 0.02])
# 计算日度期望收益
expected_ret = qs.stats.expected_return(returns)
print(f"日度期望收益: {expected_ret:.4f}")
# 计算公式: (∏(1 + returns))^(1/n) - 1
# 几何平均数,考虑复利效应
假设有A、B两个策略,其中:
A策略:已运行30天,区间总计累积收益为30%(使用comp计算得到) B策略:已运行25天,区间总计累积收益为20%(使用comp计算得到)
A策略与B策略相比,谁更好?
**平均数的计算方式分为:「算术平均数」和「几何平均数」,用哪个更好?
现在,我们通过下方代码生成一系列随机数,我们可以生成很多个上涨或下跌情况下的净值走势以及它们的算术平均数和几何平均数从起点到终点的变化路径
dates = pd.date_range("2021-01-01", periods=100)
# np.random.seed(78)
ret = pd.Series(np.random.normal(0, 0.02, size = 100), index=dates) * -1
df_returns = pd.DataFrame({
"original return": ret,
"culmulative": compsum(ret).values,
"mean by daily return": [np.mean(ret)]*100,
"geometric return": [expected_return(ret)] * 100,
}, index=dates)
df_net_value = pd.DataFrame({
"daily mean": (df_returns["mean by daily return"] + 1).cumprod(),
"geometric mean": (df_returns["geometric return"] + 1).cumprod(),
"cumulative original": (1 + df_returns["culmulative"])
})
df_net_value.plot()
我们发现,无论是上涨还是下跌,蓝线始终在红线上方


为什么无论上涨或是下跌,蓝线永远在红线上方?

我们高中就学过的均值不等式,你还记得吗....