Scipy 显著性检验

SciPy 显著性检验全面指南:量化金融统计分析

scipy.stats 模块提供了完整的假设检验工具箱,支持参数检验、非参数检验、多元统计检验等,广泛应用于金融回报检验、风险模型验证、事件研究、因子有效性检验等场景。

1. 基础参数检验

正态性检验
from scipy import stats
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import shapiro, jarque_bera, normaltest, kstest, anderson

# 生成金融回报数据
np.random.seed(42)
returns_normal = np.random.normal(0, 0.02, 1000)  # 正态回报
returns_fat = np.random.standard_t(3, 1000) * 0.02  # 厚尾回报
returns_skew = stats.skewnorm.rvs(a=5, size=1000) * 0.02  # 偏态回报

def normality_tests(returns, alpha=0.05):
    """多重正态性检验"""
    results = {}

    # 1. Shapiro-Wilk检验(小样本,n<5000)
    if len(returns) <= 5000:
        stat_sw, p_sw = shapiro(returns)
        results['Shapiro-Wilk'] = {'stat': stat_sw, 'pvalue': p_sw, 
                                  'reject': p_sw < alpha}

    # 2. Jarque-Bera检验(偏度和峰度)
    stat_jb, p_jb = jarque_bera(returns)
    results['Jarque-Bera'] = {'stat': stat_jb, 'pvalue': p_jb, 
                             'reject': p_jb < alpha}

    # 3. D'Agostino正态性检验(偏度+峰度)
    stat_dag, p_dag = normaltest(returns)
    results['D\'Agostino'] = {'stat': stat_dag, 'pvalue': p_dag, 
                             'reject': p_dag < alpha}

    # 4. Kolmogorov-Smirnov检验(与标准正态比较)
    stat_ks, p_ks = kstest(returns, 'norm', args=(returns.mean(), returns.std()))
    results['KS'] = {'stat': stat_ks, 'pvalue': p_ks, 'reject': p_ks < alpha}

    # 5. Anderson-Darling检验
    ad_result = anderson(returns, dist='norm')
    results['Anderson-Darling'] = {
        'stat': ad_result.statistic,
        'critical_values': ad_result.critical_values,
        'pvalue': ad_result.significance_level,
        'reject': ad_result.statistic > ad_result.critical_values[2]  # 5%水平
    }

    return results

# 测试不同分布
print("=== 正态回报检验 ===")
normal_results = normality_tests(returns_normal)
for test, result in normal_results.items():
    status = "拒绝" if result['reject'] else "接受"
    print(f"{test}: p={result['pvalue']:.4f}, {status} H0")

print("\n=== 厚尾回报检验 ===")
fat_results = normality_tests(returns_fat)
for test, result in fat_results.items():
    status = "拒绝" if result['reject'] else "接受"
    print(f"{test}: p={result['pvalue']:.4f}, {status} H0")
t检验与均值比较
def financial_t_tests(returns1, returns2, alpha=0.05):
    """金融回报t检验"""
    results = {}

    # 1. 单样本t检验(检验是否为零收益)
    t_stat1, p1 = stats.ttest_1samp(returns1, 0)
    results['Zero Mean 1'] = {'t_stat': t_stat1, 'pvalue': p1, 
                             'reject': p1 < alpha}

    # 2. 独立样本t检验(等方差假设)
    t_stat_eq, p_eq = stats.ttest_ind(returns1, returns2, equal_var=True)
    results['Equal Var'] = {'t_stat': t_stat_eq, 'pvalue': p_eq, 
                           'reject': p_eq < alpha}

    # 3. Welch t检验(不等方差)
    t_stat_welch, p_welch = stats.ttest_ind(returns1, returns2, equal_var=False)
    results['Welch'] = {'t_stat': t_stat_welch, 'pvalue': p_welch, 
                       'reject': p_welch < alpha}

    # 4. 配对t检验(相同资产不同时期)
    if len(returns1) == len(returns2):
        t_stat_paired, p_paired = stats.ttest_rel(returns1, returns2)
        results['Paired'] = {'t_stat': t_stat_paired, 'pvalue': p_paired,
                            'reject': p_paired < alpha}

    # 5. 单侧检验示例
    # H0: μ1 ≤ μ2 vs H1: μ1 > μ2
    from scipy.stats import ttest_ind_from_stats
    mean1, std1, n1 = np.mean(returns1), np.std(returns1, ddof=1), len(returns1)
    mean2, std2, n2 = np.mean(returns2), np.std(returns2, ddof=1), len(returns2)
    t_stat_one, p_one = ttest_ind_from_stats(mean1, std1, n1, mean2, std2, n2, 
                                            equal_var=False, alternative='greater')
    results['One-sided'] = {'t_stat': t_stat_one, 'pvalue': p_one,
                           'reject': p_one < alpha}

    return results

# 策略对比检验
strategy1_returns = np.random.normal(0.0005, 0.015, 252)  # 策略1
strategy2_returns = np.random.normal(0.0008, 0.018, 252)  # 策略2

t_results = financial_t_tests(strategy1_returns, strategy2_returns)
print("=== 策略回报t检验 ===")
for test, result in t_results.items():
    direction = "优于" if result['t_stat'] > 0 else "劣于"
    print(f"{test}: t={result['t_stat']:.3f}, p={result['pvalue']:.4f}, "
          f"{'拒绝' if result['reject'] else '接受'}零假设")

2. 方差与波动率检验

方差比检验(波动率稳定性)
def volatility_tests(returns1, returns2, alpha=0.05):
    """波动率检验"""
    results = {}

    # 1. F检验(方差比)
    var1, var2 = np.var(returns1, ddof=1), np.var(returns2, ddof=1)
    f_stat = var1 / var2
    p_f = 2 * min(stats.f.cdf(f_stat, len(returns1)-1, len(returns2)-1),
                  1 - stats.f.cdf(f_stat, len(returns1)-1, len(returns2)-1))
    results['F-test'] = {'f_stat': f_stat, 'pvalue': p_f, 'reject': p_f < alpha}

    # 2. Levene检验(稳健方差等性检验)
    stat_lev, p_lev = stats.levene(returns1, returns2)
    results['Levene'] = {'stat': stat_lev, 'pvalue': p_lev, 
                        'reject': p_lev < alpha}

    # 3. Bartlett检验(假设正态性)
    stat_bart, p_bart = stats.bartlett(returns1, returns2)
    results['Bartlett'] = {'stat': stat_bart, 'pvalue': p_bart,
                          'reject': p_bart < alpha}

    # 4. 波动率比率(非参数)
    vol_ratio = np.std(returns1) / np.std(returns2)
    # 引导法检验(bootstrap)
    n_bootstrap = 10000
    boot_ratios = []
    combined = np.concatenate([returns1, returns2])
    for _ in range(n_bootstrap):
        sample1 = np.random.choice(combined, len(returns1), replace=True)
        sample2 = np.random.choice(combined, len(returns2), replace=True)
        boot_ratios.append(np.std(sample1) / np.std(sample2))

    p_bootstrap = np.mean(np.abs(np.array(boot_ratios) - 1) >= np.abs(vol_ratio - 1))
    results['Bootstrap'] = {'vol_ratio': vol_ratio, 'pvalue': p_bootstrap,
                           'reject': p_bootstrap < alpha}

    return results

# 波动率对比
high_vol_period = np.random.standard_t(3, 252) * 0.02  # 高波动期
low_vol_period = np.random.normal(0, 0.01, 252)        # 低波动期

vol_results = volatility_tests(high_vol_period, low_vol_period)
print("=== 波动率检验 ===")
for test, result in vol_results.items():
    print(f"{test}: p={result['pvalue']:.4f}, "
          f"{'波动率不同' if result['reject'] else '波动率相等'}")

3. 非参数检验

Mann-Whitney U检验与Wilcoxon检验
def non-parametric_tests(returns1, returns2, alpha=0.05):
    """非参数检验"""
    results = {}

    # 1. Mann-Whitney U检验(独立样本中位数比较)
    stat_mw, p_mw = stats.mannwhitneyu(returns1, returns2, alternative='two-sided')
    results['Mann-Whitney'] = {'stat': stat_mw, 'pvalue': p_mw,
                              'reject': p_mw < alpha}

    # 2. Wilcoxon符号秩检验(配对样本)
    if len(returns1) == len(returns2):
        stat_wil, p_wil = stats.wilcoxon(returns1 - returns2)
        results['Wilcoxon'] = {'stat': stat_wil, 'pvalue': p_wil,
                              'reject': p_wil < alpha}

    # 3. Kolmogorov-Smirnov检验(分布比较)
    stat_ks, p_ks = stats.ks_2samp(returns1, returns2)
    results['KS 2-sample'] = {'stat': stat_ks, 'pvalue': p_ks,
                             'reject': p_ks < alpha}

    # 4. Kruskal-Wallis检验(多组比较)
    if len(returns1) > 0 and len(returns2) > 0:
        kw_stat, kw_p = stats.kruskal(returns1, returns2)
        results['Kruskal-Wallis'] = {'stat': kw_stat, 'pvalue': kw_p,
                                    'reject': kw_p < alpha}

    return results

# 策略分布比较
strategy_returns = [strategy1_returns, strategy2_returns]
np_results = non-parametric_tests(strategy1_returns, strategy2_returns)
print("=== 非参数检验 ===")
for test, result in np_results.items():
    print(f"{test}: p={result['pvalue']:.4f}, "
          f"{'分布不同' if result['reject'] else '分布相似'}")

4. 相关性与自相关检验

相关系数显著性检验
def correlation_tests(data1, data2, alpha=0.05):
    """相关性检验"""
    results = {}

    # 1. Pearson相关系数检验(线性相关)
    pearson_r, pearson_p = stats.pearsonr(data1, data2)
    results['Pearson'] = {'r': pearson_r, 'pvalue': pearson_p,
                         'significant': pearson_p < alpha}

    # 2. Spearman秩相关(单调关系)
    spearman_r, spearman_p = stats.spearmanr(data1, data2)
    results['Spearman'] = {'rho': spearman_r, 'pvalue': spearman_p,
                          'significant': spearman_p < alpha}

    # 3. Kendall Tau相关(一致性)
    kendall_tau, kendall_p = stats.kendalltau(data1, data2)
    results['Kendall'] = {'tau': kendall_tau, 'pvalue': kendall_p,
                         'significant': kendall_p < alpha}

    # 4. 偏相关分析(控制第三变量)
    from scipy.stats import partial_corr
    if 'control_var' in globals():
        partial_r, partial_p = partial_corr(data1, data2, control_var)
        results['Partial'] = {'r_partial': partial_r, 'pvalue': partial_p,
                             'significant': partial_p < alpha}

    return results

# 因子与回报相关性
factor_returns = np.random.normal(0.001, 0.01, 252)
asset_returns = 0.3 * factor_returns + np.random.normal(0, 0.015, 252)

corr_results = correlation_tests(factor_returns, asset_returns)
print("=== 相关性检验 ===")
for test, result in corr_results.items():
    if 'significant' in result:
        sig = "显著" if result['significant'] else "不显著"
        print(f"{test}: r={result[list(result.keys())[0]]:.3f}, p={result['pvalue']:.4f}, {sig}")
自相关检验(序列相关性)
def autocorrelation_tests(returns, max_lag=10, alpha=0.05):
    """自相关检验"""
    results = {}

    # 1. Ljung-Box Q检验(整体自相关)
    lb_stat, lb_p = stats.acorr_ljungbox(returns, lags=max_lag, 
                                        return_df=True, alpha=alpha)
    results['Ljung-Box'] = lb_p

    # 2. Durbin-Watson检验(一阶自相关)
    dw_stat = stats.durbin_watson(returns)
    # DW统计量解释:~2表示无自相关,<2正自相关,>2负自相关
    results['Durbin-Watson'] = {'dw': dw_stat, 'interpretation': 
                               '正自相关' if dw_stat < 1.5 else 
                               '负自相关' if dw_stat > 2.5 else '无自相关'}

    # 3. 部分自相关函数(PACF)
    from statsmodels.tsa.stattools import pacf
    pacf_vals, pacf_conf = pacf(returns, nlags=max_lag, alpha=alpha)
    significant_pacf = np.abs(pacf_vals[1:]) > pacf_conf[1:, 1]  # 排除lag=0
    results['PACF'] = {'significant_lags': np.where(significant_pacf)[0] + 1}

    return results

# 自相关检验
ar_returns = np.zeros(252)
ar_returns[0] = 0.001
for t in range(1, len(ar_returns)):
    ar_returns[t] = 0.5 * ar_returns[t-1] + np.random.normal(0, 0.01)

auto_results = autocorrelation_tests(ar_returns)
print("=== 自相关检验 ===")
print(f"Ljung-Box p值 (各滞后): {auto_results['Ljung-Box']['lb_pvalue']}")
print(f"Durbin-Watson: {auto_results['Durbin-Watson']['dw']:.3f} - {auto_results['Durbin-Watson']['interpretation']}")
print(f"显著PACF滞后: {auto_results['PACF']['significant_lags']}")

5. 多元统计检验

协方差矩阵检验
def multivariate_tests(returns_matrix, alpha=0.05):
    """多元统计检验"""
    n_assets, n_obs = returns_matrix.shape

    results = {}

    # 1. Box的M检验(多元正态性)
    from scipy.stats import boxcox
    # 简化的多元正态性检验
    mahalanobis_dists = []
    for i in range(n_obs):
        obs = returns_matrix[i]
        mean = np.mean(returns_matrix, axis=0)
        cov = np.cov(returns_matrix.T)
        try:
            mahal = np.sqrt((obs - mean) @ np.linalg.inv(cov) @ (obs - mean))
            mahalanobis_dists.append(mahal)
        except:
            pass

    # Box-M检验近似(χ²分布)
    box_m_stat = n_obs * np.sum(np.log(1 + mahalanobis_dists**2 / (n_assets - 1)))
    box_m_p = 1 - stats.chi2.cdf(box_m_stat, n_assets * (n_assets + 1) // 2)
    results['Box-M'] = {'stat': box_m_stat, 'pvalue': box_m_p,
                       'multivariate_normal': box_m_p > alpha}

    # 2. 协方差矩阵球形检验(Mauchly's W)
    # 简化实现:Bartlett球形检验扩展
    variances = np.var(returns_matrix, axis=0, ddof=1)
    avg_var = np.mean(variances)
    bartlett_stat = (n_obs - 1 - (n_assets + 2)/6) * np.sum(np.log(variances / avg_var))
    bartlett_p = 1 - stats.chi2.cdf(bartlett_stat, n_assets - 1)
    results['Sphericity'] = {'stat': bartlett_stat, 'pvalue': bartlett_p,
                            'spherical': bartlett_p > alpha}

    return results

# 多资产回报
n_assets = 5
returns_matrix = np.random.multivariate_normal([0.001]*n_assets, 
                                              np.eye(n_assets)*0.02**2, 252)
mv_results = multivariate_tests(returns_matrix)
print("=== 多元统计检验 ===")
for test, result in mv_results.items():
    status = "满足" if list(result.values())[-1] else "拒绝"
    print(f"{test}: p={result['pvalue']:.4f}, {status}假设")

6. 金融特定检验

事件研究检验
def event_study_test(event_returns, benchmark_returns, event_window=(-5, 5), 
                     estimation_window=252, alpha=0.05):
    """事件研究异常回报检验"""

    # 估计期参数
    estimation_returns = event_returns[:estimation_window] - benchmark_returns[:estimation_window]
    alpha_est = np.mean(estimation_returns)
    beta_est = np.cov(event_returns[:estimation_window], benchmark_returns[:estimation_window])[0,1] / np.var(benchmark_returns[:estimation_window])

    # 事件窗口异常回报
    event_start, event_end = event_window
    event_idx = slice(estimation_window + event_start, estimation_window + event_end + 1)
    abnormal_returns = (event_returns[event_idx] - 
                       (alpha_est + beta_est * benchmark_returns[event_idx]))

    # 累计异常回报
    car = np.cumsum(abnormal_returns)

    # t检验
    t_stat = np.mean(abnormal_returns) / (np.std(abnormal_returns) / np.sqrt(len(abnormal_returns)))
    p_value = 2 * min(stats.t.cdf(-np.abs(t_stat), len(abnormal_returns)-1),
                      1 - stats.t.cdf(-np.abs(t_stat), len(abnormal_returns)-1))

    results = {
        'abnormal_returns': abnormal_returns,
        'cumulative_ar': car,
        'alpha': alpha_est,
        'beta': beta_est,
        't_stat': t_stat,
        'p_value': p_value,
        'significant': p_value < alpha
    }

    return results

# 模拟事件研究
np.random.seed(42)
benchmark = np.random.normal(0.0005, 0.01, 300)
event_asset = np.concatenate([
    0.3 * benchmark[:252] + np.random.normal(0, 0.015, 252),  # 估计期
    0.3 * benchmark[252:257] + np.random.normal(0.02, 0.015, 5),  # 事件前
    0.3 * benchmark[257:262] + np.random.normal(0.05, 0.02, 5),   # 事件期异常
    0.3 * benchmark[262:] + np.random.normal(0, 0.015, 43)        # 事件后
])

event_results = event_study_test(event_asset, benchmark)
print("=== 事件研究 ===")
print(f"异常回报均值: {np.mean(event_results['abnormal_returns']):.4f}")
print(f"CAR: {event_results['cumulative_ar'][-1]:.4f}")
print(f"t统计量: {event_results['t_stat']:.3f}, p={event_results['p_value']:.4f}")
print(f"事件显著: {'是' if event_results['significant'] else '否'}")
因子模型检验
def factor_model_test(factor_returns, asset_returns, alpha=0.05):
    """多因子模型显著性检验"""
    from statsmodels.regression.linear_model import OLS
    from statsmodels.stats.diagnostic import het_breuschpagan

    # OLS回归
    model = OLS(asset_returns, stats.add_constant(factor_returns)).fit()

    results = {
        'r_squared': model.rsquared,
        'f_stat': model.fvalue,
        'f_pvalue': model.f_pvalue,
        'coefficients': model.params[1:],  # 排除截距
        't_stats': model.tvalues[1:],
        'p_values': model.pvalues[1:],
        'significant_factors': np.where(model.pvalues[1:] < alpha)[0]
    }

    # 异方差检验
    bp_stat, bp_p = het_breuschpagan(model.resid, model.model.exog)
    results['heteroskedasticity'] = {'bp_stat': bp_stat, 'pvalue': bp_p,
                                   'homo': bp_p > alpha}

    # 自相关检验(Durbin-Watson)
    dw_stat = stats.durbin_watson(model.resid)
    results['autocorrelation'] = {'dw': dw_stat, 'no_autocorr': 1.5 < dw_stat < 2.5}

    return results, model

# 因子模型检验
n_factors = 3
n_obs = 252
factor_returns = np.random.normal(0, 0.01, (n_obs, n_factors))
asset_returns = factor_returns @ np.array([0.3, 0.2, 0.1]) + np.random.normal(0, 0.015, n_obs)

factor_results, model = factor_model_test(factor_returns, asset_returns)
print("=== 因子模型检验 ===")
print(f"R²: {factor_results['r_squared']:.3f}, F检验 p={factor_results['f_pvalue']:.4f}")
print("因子显著性:")
for i, p in enumerate(factor_results['p_values']):
    sig = "显著" if p < 0.05 else "不显著"
    print(f"  因子{i+1}: t={factor_results['t_stats'][i]:.2f}, p={p:.4f} ({sig})")
print(f"异方差检验 p={factor_results['heteroskedasticity']['pvalue']:.4f}")
print(f"自相关 DW={factor_results['autocorrelation']['dw']:.2f}")

7. 多重检验校正

Bonferroni与FDR校正
from statsmodels.stats.multitest import multipletests
import itertools

def multiple_testing_correction(p_values, method='fdr_bh', alpha=0.05):
    """多重检验校正"""

    # 多重检验校正
    reject, p_corrected, _, _ = multipletests(p_values, alpha=alpha, 
                                            method=method)

    results = {
        'method': method,
        'original_p': p_values,
        'corrected_p': p_corrected,
        'rejected': reject,
        'num_rejected': np.sum(reject),
        'fdr_rate': np.sum(reject) / len(p_values) if len(p_values) > 0 else 0
    }

    return results

# 模拟多重检验:100个因子显著性
n_factors = 100
p_values = np.random.uniform(0, 1, n_factors)
p_values[:10] = np.random.uniform(0, 0.001, 10)  # 10个真正显著

correction_results = multiple_testing_correction(p_values)
print("=== 多重检验校正 ===")
print(f"原始拒绝数量: {np.sum(p_values < 0.05)}")
print(f"{correction_results['method']} 校正拒绝数量: {correction_results['num_rejected']}")
print(f"FDR控制率: {correction_results['fdr_rate']:.1%}")

# 不同校正方法对比
methods = ['bonferroni', 'holm', 'fdr_bh', 'fdr_tsbh', 'fdr_tsbky']
for method in methods:
    corr = multiple_testing_correction(p_values, method=method)
    print(f"{method:12s}: {corr['num_rejected']:2d} 拒绝")

8. 稳健性检验与Bootstrap

Bootstrap假设检验
def bootstrap_test(returns1, returns2, statistic=np.mean, n_bootstrap=10000, 
                   alpha=0.05):
    """Bootstrap假设检验"""

    # 观测统计量
    obs_stat = statistic(returns1) - statistic(returns2)

    # 合并样本
    combined = np.concatenate([returns1, returns2])
    n1, n2 = len(returns1), len(returns2)

    # Bootstrap重采样
    boot_stats = []
    for _ in range(n_bootstrap):
        sample1 = np.random.choice(combined, n1, replace=True)
        sample2 = np.random.choice(combined, n2, replace=True)
        boot_stat = statistic(sample1) - statistic(sample2)
        boot_stats.append(boot_stat)

    boot_stats = np.array(boot_stats)

    # p值计算
    p_value = np.mean(np.abs(boot_stats) >= np.abs(obs_stat))

    # 置信区间
    ci_lower = np.percentile(boot_stats, alpha/2 * 100)
    ci_upper = np.percentile(boot_stats, (1 - alpha/2) * 100)

    return {
        'observed': obs_stat,
        'p_value': p_value,
        'ci': (ci_lower, ci_upper),
        'significant': p_value < alpha,
        'bootstrap_stats': boot_stats
    }

# Bootstrap夏普比率检验
def sharpe_ratio(returns):
    return np.mean(returns) / np.std(returns) * np.sqrt(252)

sr1 = sharpe_ratio(strategy1_returns)
sr2 = sharpe_ratio(strategy2_returns)
print(f"原始夏普比率: 策略1={sr1:.3f}, 策略2={sr2:.3f}")

boot_result = bootstrap_test(strategy1_returns, strategy2_returns, 
                            statistic=sharpe_ratio, n_bootstrap=5000)
print(f"Bootstrap检验: 差值={boot_result['observed']:.3f}, p={boot_result['p_value']:.4f}")
print(f"95% CI: ({boot_result['ci'][0]:.3f}, {boot_result['ci'][1]:.3f})")

9. 完整金融统计检验工作流

class FinancialStatisticalTests:
    """金融统计检验工作流"""

    def __init__(self, alpha=0.05):
        self.alpha = alpha
        self.test_results = {}

    def run_comprehensive_tests(self, returns_data, benchmarks=None):
        """运行完整统计检验"""

        if isinstance(returns_data, pd.DataFrame):
            asset_names = returns_data.columns
            for asset in asset_names:
                self._test_single_asset(returns_data[asset], asset)
        else:
            self._test_single_asset(returns_data, 'asset')

        if benchmarks is not None:
            self._test_vs_benchmark(returns_data, benchmarks)

        return self.test_results

    def _test_single_asset(self, returns, name):
        """单资产检验"""
        self.test_results[f'{name}_normality'] = normality_tests(returns, self.alpha)
        self.test_results[f'{name}_autocorr'] = autocorrelation_tests(returns)

        # 夏普比率显著性
        sharpe = np.mean(returns) / np.std(returns) * np.sqrt(252)
        t_sharpe = sharpe / np.sqrt(252 / len(returns))
        p_sharpe = 2 * (1 - stats.t.cdf(np.abs(t_sharpe), len(returns)-1))
        self.test_results[f'{name}_sharpe'] = {
            'sharpe': sharpe, 't_stat': t_sharpe, 'pvalue': p_sharpe,
            'significant': p_sharpe < self.alpha
        }

    def _test_vs_benchmark(self, returns, benchmark):
        """对比基准检验"""
        if isinstance(returns, pd.DataFrame):
            for asset in returns.columns:
                t_results = financial_t_tests(returns[asset], benchmark)
                self.test_results[f'{asset}_vs_benchmark'] = t_results
        else:
            t_results = financial_t_tests(returns, benchmark)
            self.test_results['asset_vs_benchmark'] = t_results

    def summary_report(self):
        """生成检验报告"""
        report = {}

        for test_name, results in self.test_results.items():
            if 'normality' in test_name:
                normal_tests = list(results.keys())
                rejection_rate = sum(1 for t in normal_tests if results[t]['reject']) / len(normal_tests)
                report[test_name] = f"正态性拒绝率: {rejection_rate:.1%}"
            elif 'sharpe' in test_name:
                report[test_name] = f"夏普显著: {results['significant']}"
            elif 'vs_benchmark' in test_name:
                significant_tests = sum(1 for t in results if results[t]['reject'])
                report[test_name] = f"显著优于基准: {significant_tests}/{len(results)} 检验"

        return report

# 使用示例
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=252, freq='B')
assets = pd.DataFrame({
    'Strategy_A': np.random.normal(0.0008, 0.015, 252),
    'Strategy_B': np.random.normal(0.0005, 0.012, 252),
    'Benchmark': np.random.normal(0.0003, 0.01, 252)
}, index=dates)

tester = FinancialStatisticalTests(alpha=0.05)
test_results = tester.run_comprehensive_tests(assets['Strategy_A'], assets['Benchmark'])
report = tester.summary_report()

print("=== 统计检验报告 ===")
for test, result in report.items():
    print(f"{test}: {result}")

10. 结果可视化与解释

def visualize_test_results(test_results):
    """可视化检验结果"""

    fig, axes = plt.subplots(2, 2, figsize=(15, 12))

    # 1. 正态性检验p值
    if 'Strategy_A_normality' in test_results:
        norm_pvals = [test_results['Strategy_A_normality'][test]['pvalue'] 
                     for test in test_results['Strategy_A_normality']]
        tests = list(test_results['Strategy_A_normality'].keys())
        axes[0,0].bar(tests, norm_pvals, color=['red' if p < 0.05 else 'green' for p in norm_pvals])
        axes[0,0].axhline(0.05, color='red', linestyle='--', alpha=0.7)
        axes[0,0].set_ylabel('p值')
        axes[0,0].set_title('正态性检验')
        axes[0,0].tick_params(axis='x', rotation=45)

    # 2. 自相关函数
    from statsmodels.graphics.tsaplots import plot_acf
    plot_acf(assets['Strategy_A'].dropna(), ax=axes[0,1], lags=20)
    axes[0,1].set_title('自相关函数')

    # 3. QQ图(正态性可视化)
    stats.probplot(assets['Strategy_A'].dropna(), dist="norm", plot=axes[1,0])
    axes[1,0].set_title('QQ图 - 策略A')

    # 4. 累积回报对比
    (assets['Strategy_A'] + 1).cumprod().plot(ax=axes[1,1], label='Strategy A')
    (assets['Benchmark'] + 1).cumprod().plot(ax=axes[1,1], label='Benchmark')
    axes[1,1].set_title('累积回报')
    axes[1,1].legend()

    plt.tight_layout()
    plt.show()

visualize_test_results(test_results)

SciPy显著性检验工具为量化金融提供了完整的统计验证框架,从基础假设检验到复杂多重检验校正,都能有效验证模型有效性和统计显著性。结合Bootstrap方法和稳健性检验,可以构建可靠的金融统计分析流程。需要特定金融检验方法的深入实现或与机器学习模型验证的集成,请告诉我具体需求!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注