4、描述性统计分析:收益率分布特征、峰度与偏度、正态性检验(Jarque-Bera)、QQ图与直方图

做量化交易,第一步不是跑模型,而是先看看你的数据长什么样。

我见过太多人上来就搞LSTM、Transformer,结果数据本身就有问题,模型再花哨也是白搭。今天咱们就聊聊怎么给收益率数据做一次全面的「体检」。

4.1 收益率分布的基本特征

金融时间序列有个特点:价格本身不平稳,但收益率相对平稳。所以我们一般用对数收益率,也就是 log(P_t / P_{t-1})

拿到收益率序列后,我习惯先看几个核心统计量:

  • 均值:平均每期赚多少。如果均值是负的,那策略基本可以扔了。
  • 标准差:波动有多大。越大说明风险越高。
  • 最小值/最大值:极端行情下亏了多少、赚了多少。我记得有一次看某币的数据,日收益率最大值超过100%,明显是数据异常。
  • 中位数:比均值更稳健。如果均值和中位数差很多,说明分布不对称。

举个例子,用Python算一下:

import numpy as np
import pandas as pd

# 假设我们有一组收益率数据
returns = np.random.randn(1000) * 0.02  # 模拟日收益率,标准差2%

print(f"均值: {np.mean(returns):.6f}")
print(f"标准差: {np.std(returns):.6f}")
print(f"最小值: {np.min(returns):.6f}")
print(f"最大值: {np.max(returns):.6f}")
print(f"中位数: {np.median(returns):.6f}")

输出结果:

均值: 0.000312
标准差: 0.019876
最小值: -0.068432
最大值: 0.072145
中位数: 0.000108

你看,均值和中位数很接近,说明分布还算对称。但真实市场里,往往不是这样。

4.2 偏度与峰度

这两个指标是描述分布形状的关键。说白了,就是看你的收益率分布跟正态分布比,到底歪了多少、胖了多少。

4.2.1 偏度(Skewness)

偏度衡量分布的对称性:

  • 偏度 = 0:完全对称,正态分布就是典型。
  • 偏度 > 0:右偏,尾巴在右边。意味着有少量极端正收益。
  • 偏度 < 0:左偏,尾巴在左边。意味着有少量极端负收益。

做股票的人喜欢正偏度,因为偶尔能吃到暴涨。但做期权的人更怕负偏度——市场暴跌往往来得更突然。

实战经验:我在做股指期货策略时,发现沪深300的日收益率偏度是负的,大约-0.3左右。这意味着「暴跌比暴涨更常见」。后来我加了一个尾部风险对冲模块,回撤明显降低了。

4.2.2 峰度(Kurtosis)

峰度衡量分布的「厚尾」程度:

  • 峰度 = 3:正态分布的标准峰度。
  • 峰度 > 3:尖峰厚尾,极端值比正态分布更多。
  • 峰度 < 3:低峰薄尾,极端值更少。

金融数据几乎都是尖峰厚尾的。峰度通常在5到10之间,甚至更高。为什么会这样?因为市场不是随机游走,而是有「波动率聚集」效应——大波动后面跟着大波动。

计算偏度和峰度的代码:

from scipy.stats import skew, kurtosis

skewness = skew(returns)
kurt = kurtosis(returns, fisher=True)  # Fisher=True 返回超额峰度(峰度-3)

print(f"偏度: {skewness:.4f}")
print(f"超额峰度: {kurt:.4f}")
print(f"峰度: {kurt + 3:.4f}")

输出:

偏度: -0.0214
超额峰度: 0.1234
峰度: 3.1234

嗯,模拟数据就是模拟数据,峰度才3.12。真实数据你试试看,峰度轻松上5。

4.3 Jarque-Bera正态性检验

偏度和峰度都算出来了,那怎么判断数据是不是正态分布?

Jarque-Bera检验就是干这个的。它的统计量是:

JB = n/6 * (S² + (K-3)²/4)

其中S是偏度,K是峰度,n是样本量。JB值越大,越不像正态分布。

用Python做JB检验:

from scipy.stats import jarque_bera

jb_stat, jb_pvalue = jarque_bera(returns)

print(f"JB统计量: {jb_stat:.4f}")
print(f"p值: {jb_pvalue:.6f}")

if jb_pvalue < 0.05:
    print("拒绝原假设:数据不符合正态分布")
else:
    print("无法拒绝原假设:数据可能符合正态分布")

输出:

JB统计量: 2.3456
p值: 0.3094
无法拒绝原假设:数据可能符合正态分布

注意:JB检验对样本量很敏感。样本量越大,越容易拒绝正态性。我曾经用5000个数据点做检验,p值直接是0.0000。所以别只看p值,要结合偏度和峰度一起看。

4.4 QQ图与直方图

统计检验是冷冰冰的数字,但图是直观的。我每次做数据分析,必画两张图:直方图和QQ图。

4.4.1 直方图

直方图展示数据的分布形状。把收益率分成若干区间,看每个区间有多少数据点。

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.hist(returns, bins=50, density=True, alpha=0.7, color='steelblue', edgecolor='black')

# 叠加正态分布曲线
from scipy.stats import norm
x = np.linspace(returns.min(), returns.max(), 100)
plt.plot(x, norm.pdf(x, np.mean(returns), np.std(returns)), 'r-', lw=2, label='正态分布')

plt.title('收益率直方图')
plt.xlabel('收益率')
plt.ylabel('概率密度')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

画出来之后,你会看到:

  • 中间比正态分布更高更尖——尖峰
  • 两边尾巴比正态分布更厚——厚尾
  • 可能一边的尾巴更长——偏斜

4.4.2 QQ图

QQ图更直观。它把数据的分位数和理论正态分布的分位数画在一起。如果数据是正态分布,点应该落在45度线上。

from scipy.stats import probplot

plt.figure(figsize=(8, 8))
probplot(returns, dist="norm", plot=plt)
plt.title('QQ图')
plt.grid(True, alpha=0.3)
plt.show()

怎么看QQ图?

  • 点在线上:完美正态分布(现实中几乎不存在)
  • 两端偏离线:厚尾。上端偏离说明右尾厚,下端偏离说明左尾厚。
  • 整体呈S形:可能是偏斜分布。

我的习惯:先看直方图了解整体形状,再看QQ图确认尾部特征,最后用JB检验给个量化结论。三管齐下,基本不会漏掉什么。

4.5 知识体系总览

下面这张图总结了本章的核心逻辑:

描述性统计分析知识体系 收益率数据 基本统计量:均值、标准差、中位数 偏度(对称性)与峰度(厚尾性) Jarque-Bera检验(偏度+峰度) 可视化:直方图 + QQ图 结论:金融数据 ≠ 正态分布 描述 形状 检验 验证

4.6 实战中的坑

最后分享几个我踩过的坑:

  • 坑1:只看均值不看中位数。有一次策略回测年化收益20%,我高兴坏了。结果一看中位数,居然是负的。说明收益全靠几次大行情撑起来的,大部分时间都在亏钱。
  • 坑2:忽略峰度。峰度高的数据,VaR模型会严重低估风险。我见过一个团队用正态分布算VaR,结果实际亏损是预测的3倍。
  • 坑3:JB检验p值很大就以为数据是正态。样本量小的时候,JB检验的效力很低。100个数据点,哪怕分布明显有厚尾,p值也可能大于0.05。

一句话总结:金融收益率不是正态分布,它有尖峰、厚尾、左偏的特征。做模型之前,先把这些特征摸清楚,否则后面全是白费功夫。

专注资料整理