Skip to content

2.3 概率统计与相关性

概念详解

概率思维与随机性

金融市场的本质特征是不确定性。相对于工程问题(给定输入,输出基本确定),金融问题是典型的随机系统——即使你拥有完美的信息,也无法精确预测明天的股价。这种不确定性不是暂时的技术限制,而是市场的本质特征:如果有任何可预测的规律,它会被立即交易掉。

因此,量化交易者必须建立扎实的概率统计基础。不是"预测"市场,而是在不确定性中寻找概率优势

名词解释:肥尾分布

与正态分布相比,尾部更厚的分布,意味着极端事件发生概率更高。金融收益率常呈现此特征。

名词解释:峰度 (Kurtosis)

衡量分布"尾部厚度"的统计量。正态分布的峰度为3,大于3为"尖峰厚尾"(Leptokurtic),意味着极端值出现的概率高于正态分布的预测。

名词解释:偏度 (Skewness)

衡量分布不对称性的统计量。正偏表示右侧尾部更长(如彩票),负偏表示左侧尾部更长(如崩盘风险)。金融收益率常呈现负偏。

为什么正态分布假设在金融中很危险

经典金融理论(如CAPM、Black-Scholes)大量依赖正态分布假设。但实际数据显示:

  • 日收益率的峰度通常在5-10之间(远高于正态的3)
  • 1987年黑色星期一(标普下跌20%+),在正态假设下应该是"宇宙年龄尺度才发生一次"的事件
  • 收益率方差不是恒定的,而是呈现波动率聚集(volatility clustering)
名词解释:波动率聚集

金融时间序列中,大波动之后往往跟随大波动(无论方向),小波动之后往往跟随小波动。这种现象使收益率并非独立同分布,而是具有"自回归条件异方差"(ARCH效应)。

数学原理

关键概率分布

量化交易中最常用的分布:

分布PDF / 特征金融应用
正态分布 N(μ,σ2)对称钟形,由均值和方差决定理论基准(虽然不完美)
对数正态右偏,价格非负股票价格模型
t分布 t(ν)尾部比正态厚,自由度控制厚度收益率建模、稳健回归
拉普拉斯分布尖峰厚尾高频收益率
帕累托分布极厚尾部,幂律衰减极端损失建模

相关系数及其陷阱

皮尔逊相关系数衡量线性相关程度:

\rho_{X,Y} = \frac{\text{Cov}(X, Y)}{\sigma_X \sigma_Y} = \frac{E[(X - \mu_X)(Y - \mu_Y)]}{\sigma_X \sigma_Y}

相关性分析中需要特别注意:

  1. 相关性不等于因果关系:X和Y高度相关可能是因为(a)X导致Y,(b)Y导致X,(c)Z同时导致X和Y(混淆变量),(d)纯属偶然
  2. 相关性不稳定:金融资产间的相关关系随时间剧烈变化,在危机期间相关性往往陡升(diversification fails when you need it most)
  3. 线性假设局限:皮尔逊相关系数仅衡量线性关系,X=sin(Y)的相关系数可能接近0但二者存在强烈的确定性关系
  4. 异常值敏感:一个极端值可以严重扭曲皮尔逊相关系数的估计

期望值与条件期望

对于离散和连续情况:

E[X] = \begin{cases} \sum x_i \cdot p(x_i) & \text{离散} \\ \int_{-\infty}^{\infty} x \cdot f(x) dx & \text{连续} \end{cases}

条件期望(Conditional Expectation)是量化信号的核心工具——我们想知道给定某些特征的条件下,资产的预期收益:

E[R_{t+1} | X_t = x] = \int r \cdot f(r | X_t = x) dr

交互式探索

期望值计算器

🎲 期望值计算器

期望值 = 14.50 美元/笔。✅ 正期望策略

随机游走模拟器

📉 随机游走模拟器

资产相关性热力图

🔥 资产相关性热力图

Python实战

案例1:收益分布的统计诊断

PYTHON88 行 · 3.8 KB
📄此处有展示代码88 行 · 3.8 KB展开 ▼
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
# 注:本案例纯 matplotlib + scipy, 不依赖 seaborn(浏览器沙箱不支持)。

def diagnose_return_distribution(returns, title='收益率分布诊断'):
    """
    全面诊断收益分布的统计特征
    """
    returns = returns.dropna()
    n = len(returns)
    
    # 基础统计量
    mean = returns.mean()
    std = returns.std()
    skew = stats.skew(returns)
    kurt = stats.kurtosis(returns)  # 超额峰度 (excess kurtosis, normal=0)
    jb_stat, jb_p = stats.jarque_bera(returns)  # Jarque-Bera正态性检验
    
    # VaR 和 CVaR
    var_95 = np.percentile(returns, 5)
    var_99 = np.percentile(returns, 1)
    cvar_95 = returns[returns <= var_95].mean()  # Expected Shortfall
    
    # 创建诊断图表
    fig, axes = plt.subplots(2, 3, figsize=(18, 10))
    
    # 1. 收益率时序图
    axes[0, 0].plot(returns.index, returns.values, linewidth=0.5, alpha=0.7)
    axes[0, 0].axhline(y=mean, color='red', linestyle='--', alpha=0.5, label=f'均值={mean:.4f}')
    axes[0, 0].axhline(y=mean + 2*std, color='orange', linestyle=':', alpha=0.5, label=f'±2σ')
    axes[0, 0].axhline(y=mean - 2*std, color='orange', linestyle=':', alpha=0.5)
    axes[0, 0].set_title('收益率时序')
    axes[0, 0].legend(fontsize=8)
    
    # 2. 直方图 vs 正态分布
    axes[0, 1].hist(returns, bins=50, density=True, alpha=0.6, color='steelblue', edgecolor='white')
    x_range = np.linspace(returns.min(), returns.max(), 200)
    axes[0, 1].plot(x_range, stats.norm.pdf(x_range, mean, std), 'r-', linewidth=2, label='正态分布拟合')
    axes[0, 1].set_title(f'收益率分布\n偏度={skew:.3f}, 超额峰度={kurt:.3f}')
    axes[0, 1].legend(fontsize=8)
    
    # 3. Q-Q图 (Quantile-Quantile Plot)
    stats.probplot(returns, dist='norm', plot=axes[0, 2])
    axes[0, 2].set_title(f'Q-Q图 (JB p值={jb_p:.4f})')
    
    # 4. 自相关图
    from statsmodels.graphics.tsaplots import plot_acf
    plot_acf(returns, ax=axes[1, 0], lags=30)
    axes[1, 0].set_title('收益率自相关')
    
    # 5. 滚动波动率
    rolling_vol = returns.rolling(20).std() * np.sqrt(252)
    axes[1, 1].plot(rolling_vol.index, rolling_vol.values, linewidth=0.8)
    axes[1, 1].set_title('滚动年化波动率 (20日)')
    
    # 6. 左尾放大(关注极端亏损)
    left_tail = returns[returns < returns.quantile(0.10)]
    axes[1, 2].hist(left_tail, bins=30, density=True, alpha=0.6, color='darkred', edgecolor='white')
    axes[1, 2].axvline(x=var_95, color='orange', linestyle='--', label=f'VaR 95%={var_95:.2%}')
    axes[1, 2].axvline(x=var_99, color='red', linestyle='--', label=f'VaR 99%={var_99:.2%}')
    axes[1, 2].set_title(f'左尾分布\nCVaR 95%={cvar_95:.2%}')
    axes[1, 2].legend(fontsize=8)
    
    plt.suptitle(title, fontsize=14, fontweight='bold')
    plt.tight_layout()
    plt.show()
    
    # 打印统计报告
    print("=" * 50)
    print(f"样本量: {n}")
    print(f"均值: {mean:.6f} (年化: {mean*252:.2%})")
    print(f"标准差: {std:.6f} (年化: {std*np.sqrt(252):.2%})")
    print(f"偏度: {skew:.4f} {'(显著负偏⚠️)' if skew < -0.5 else ''}")
    print(f"超额峰度: {kurt:.4f} {'(厚尾⚠️)' if kurt > 1 else ''}")
    print(f"Jarque-Bera p值: {jb_p:.6f} {'(拒绝正态分布)' if jb_p < 0.05 else '(无法拒绝正态分布)'}")
    print(f"VaR (95%): {var_95:.4%}")
    print(f"VaR (99%): {var_99:.4%}")
    print(f"CVaR (95%): {cvar_95:.4%}")
    
    return {
        'mean': mean, 'std': std, 'skew': skew, 'kurt': kurt,
        'jb_pvalue': jb_p, 'var_95': var_95, 'var_99': var_99, 'cvar_95': cvar_95
    }

# 一键运行(用 demo 数据 df['returns'] 作为收益率序列)
diagnose_return_distribution(df['returns'].rename('returns'))
点击展开可浏览运行结果
==================================================
样本量: 252
均值: -0.000298 (年化: -7.51%)
标准差: 0.019889 (年化: 31.57%)
偏度: -0.0581 
超额峰度: 0.4032 
Jarque-Bera p值: 0.396704 (无法拒绝正态分布)
VaR (95%): -3.5156%
VaR (99%): -4.6745%
CVaR (95%): -4.2589%
运行结果图 1

案例2:相关性矩阵与层次聚类

PYTHON92 行 · 3.9 KB
📄此处有展示代码92 行 · 3.9 KB展开 ▼
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
from scipy.spatial.distance import squareform
# 注:本案例纯 matplotlib + scipy, 不依赖 seaborn(浏览器沙箱不支持)。

def correlation_clustering(returns_df, method='ward', n_clusters=4):
    """
    基于相关性的层次聚类,识别资产群组
    
    returns_df: 每列是一只资产的收益率序列
    """
    # 计算相关系数矩阵
    corr_matrix = returns_df.corr()
    
    # 将相关系数转换为距离(1 - |corr| 或直接 1 - corr)
    # 注意:负相关也可以用于对冲到同一群组中
    distance_matrix = 1 - corr_matrix.abs()  # 负相关也视为相关
    # distance_matrix = 1 - corr_matrix  # 如果只想聚类正相关的资产
    
    # 层次聚类
    condensed_dist = squareform(distance_matrix.values)
    linkage_matrix = linkage(condensed_dist, method=method)
    
    # 生成聚类标签
    cluster_labels = fcluster(linkage_matrix, n_clusters, criterion='maxclust')
    
    # 按聚类排序
    sorted_idx = np.argsort(cluster_labels)
    sorted_corr = corr_matrix.iloc[sorted_idx, sorted_idx]
    sorted_labels = cluster_labels[sorted_idx]
    
    # 可视化
    fig, axes = plt.subplots(1, 2, figsize=(18, 8))
    
    # 左:聚类后的相关性热力图(纯 matplotlib, 无需 seaborn)
    ax_left = axes[0]
    mask = np.triu(np.ones_like(sorted_corr, dtype=bool), k=1)
    arr = sorted_corr.values
    masked_arr = np.where(mask, np.nan, arr)
    im = ax_left.imshow(masked_arr, cmap='RdBu_r', vmin=-1, vmax=1,
                        aspect='equal', interpolation='nearest')
    cbar = plt.colorbar(im, ax=ax_left, shrink=0.8, fraction=0.046, pad=0.04)
    cbar.set_label('相关系数')
    ax_left.set_xticks([])
    ax_left.set_yticks([])
    
    # 添加聚类分隔线
    boundaries = np.where(np.diff(sorted_labels))[0]
    for b in boundaries:
        axes[0].axhline(y=b+1, color='black', linewidth=2)
        axes[0].axvline(x=b+1, color='black', linewidth=2)
    axes[0].set_title(f'资产相关性矩阵(层次聚类, n={n_clusters})')
    
    # 右:树状图
    dendro = dendrogram(linkage_matrix, labels=returns_df.columns.tolist(),
                        ax=axes[1], orientation='left',
                        leaf_font_size=9)
    axes[1].set_title(f'层次聚类树状图 ({method} linkage)')
    axes[1].set_xlabel('距离 (1 - |corr|)')
    
    plt.tight_layout()
    plt.show()
    
    # 输出每个聚类的成员
    print("=== 聚类结果 ===")
    for c in range(1, n_clusters + 1):
        members = returns_df.columns[cluster_labels == c].tolist()
        print(f"聚类 {c} ({len(members)}个资产): {members[:5]}{'...' if len(members) > 5 else ''}")
    
    return {
        'corr_matrix': corr_matrix,
        'cluster_labels': cluster_labels,
        'linkage_matrix': linkage_matrix,
        'distance_matrix': distance_matrix
    }

# 一键运行(用 4 个因子 + df['returns'] 构造 5 列资产收益矩阵)
_np.random.seed(7)
_aligned_factors = factors.iloc[:len(df)]  # 因子行数与 df 对齐
_demo_returns = pd.DataFrame({
    'Asset_A':   df['returns'].values + _np.random.normal(0, 0.001, len(df)),
    'Asset_B':   0.7 * df['returns'].values + 0.3 * _aligned_factors['momentum'].values + _np.random.normal(0, 0.002, len(df)),
    'Asset_C':   0.6 * df['returns'].values + 0.4 * _aligned_factors['value'].values    + _np.random.normal(0, 0.002, len(df)),
    'Asset_D':   _aligned_factors['momentum'].values + _np.random.normal(0, 0.003, len(df)),
    'Asset_E':  -0.5 * _aligned_factors['momentum'].values + _np.random.normal(0, 0.003, len(df)),  # 与 D 负相关
}, index=df.index).iloc[1:]   # 去掉首个 NaN

results = correlation_clustering(_demo_returns, n_clusters=4)
print()
print(f"✅ 已识别 {results['cluster_labels'].max()} 个聚类群组")
点击展开可浏览运行结果
=== 聚类结果 ===
聚类 1 (2个资产): ['Asset_D', 'Asset_E']
聚类 2 (1个资产): ['Asset_A']
聚类 3 (1个资产): ['Asset_B']
聚类 4 (1个资产): ['Asset_C']

✅ 已识别 4 个聚类群组
运行结果图 1运行结果图 2

常见误区

误区一:相关系数为0就是不相关

事实:皮尔逊相关系数为0只意味着没有线性关系。两个变量之间可能存在完美的非线性关系(如圆形、正弦关系)而相关系数为0。在进行相关性分析之前,一定要先做散点图。

误区二:历史相关性可以外推

事实:金融相关性是高度不稳定的。2008年金融危机期间,几乎所有资产的相关性都飙升("diversification failed")。在构建投资组合时,必须考虑相关性在压力情景下的变化——这就是"压力测试"的意义。

误区三:正态分布是合理的近似

事实:对于日常决策可能够用,但对于风险管理可能是致命的。金融数据存在明确的肥尾特征。使用t分布或广义误差分布(GED)往往更安全,至少需要意识到正态假设的风险低估。

误区四:统计不显著=策略无效

事实:统计不显著可能有多种原因:(a) 样本量不够,(b) 信号确实不存在,(c) 信号存在但被噪声掩盖。正确的做法是计算统计功效(Power)——如果策略有经济意义上的合理效应大小,但统计检验的功效不足,则需要更大的样本量,而非直接放弃。

实战练习

  1. 分布拟合:取A股某只股票近5年的日收益率,分别用正态分布、t分布和拉普拉斯分布拟合。使用AIC/BIC选择最优分布,并用Kolmogorov-Smirnov检验评估拟合优度。

  2. 相关性衰减分析:选取5-8只不同行业的A股股票,计算滚动的60日相关性矩阵。绘制平均相关系数的时间序列,标注市场大跌日(如2015年股灾、2020年3月疫情冲击),观察相关性在危机期间是否上升。

  3. 蒙特卡洛模拟:假设一个策略月收益的期望为1%、标准差为5%,用蒙特卡洛模拟生成1000条36个月的资金曲线。输出(a) 终值的分位数分布,(b) 最大回撤的分布,(c) 至少有5条路径出现投资失败(终值<0.8)的概率。

延伸阅读

  • 《All of Statistics》—— Larry Wasserman,统计学的精确导论
  • 《Statistical Consequences of Fat Tails》—— Nassim Taleb,肥尾分布的全面剖析
  • 《An Introduction to Statistical Learning》—— James et al.,统计学习的经典入门书
  • Cont, R. (2001): "Empirical Properties of Asset Returns" —— 金融收益率统计特征的系统总结
  • Meucci, A. (2009): "Risk and Asset Allocation" —— 非正态分布下的投资组合构建

本章要点

  • 金融收益率具有偏度(通常为负)、超额峰度(肥尾)和波动率聚集三大典型特征
  • 正态分布假设在量化建模中方便但危险,尾部风险远高于正态预测
  • 相关性不等于因果关系,且金融相关性在时间和情境维度高度不稳定
  • 统计显著性不等于经济意义,需结合效应大小和统计功效综合判断
  • 蒙特卡洛模拟是理解不确定性的强大工具,也是策略压力测试的基础方法