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方法和稳健性检验,可以构建可靠的金融统计分析流程。需要特定金融检验方法的深入实现或与机器学习模型验证的集成,请告诉我具体需求!