scipy_demo · 统计工具箱
内容:
年化波动率:这只股票一年颠簸得多厉害
夏普比率:每承担一分风险,换回多少超额收益
t 检验:你赚的是实力还是运气?
scipy 安装:pip install scipy
导入与主入口
import numpy as np
import pandas as pd
from scipy import stats
from quant_data import get_kline
if __name__ == "__main__":
0. 复用上期的数据
df = get_kline()
df["收益率"] = df["close"].pct_change()
r = df["收益率"].dropna()
print(f"\n共 {len(r)} 个交易日收益率样本")
1. 年化波动率
日波动率 × √252 = 年化波动率(252 是 A 股一年大概的交易日数量)
vol_daily = r.std()
vol_year = vol_daily * np.sqrt(252)
print("\n===== 年化波动率 =====")
print(f"日波动率 : {vol_daily:.4f}")
print(f"年化波动率: {vol_year:.2%}")
2. 夏普比率
夏普比率 = 超额收益 ÷ 风险,再年化。(>1 不错,>2 很能打)
rf = 0.02
excess_daily = r.mean() - rf / 252
sharpe = excess_daily / r.std() * np.sqrt(252)
print("\n===== 夏普比率 =====")
print(f"年化收益率 : {r.mean() * 252:.2%}")
print(f"夏普比率 : {sharpe:.2f} (>1 不错,>2 很能打)")
3. t 检验:实力还是运气?
ttest_1samp(数据, 0):检验"数据的平均值是不是 0"。主要看 p 值:
p < 0.05 → 收益显著不为 0,大概率是实力
p ≥ 0.05 → 收益不够显著,可能只是运气
t_stat, p_value = stats.ttest_1samp(r, 0)
print("\n===== t 检验 =====")
print(f"t 统计量: {t_stat:.3f}")
print(f"p 值 : {p_value:.4f}")
if p_value < 0.05:
print("p < 0.05 → 收益显著不为 0,大概率是实力,不是运气")
else:
print("p >= 0.05 → 收益不够显著,可能只是运气")
核心要点速览
年化波动率:r.std() × √252
夏普比率:超额收益 ÷ 风险 × √252
t 检验:stats.ttest_1samp(r, 0)
年化收益:r.mean() × 252
无风险利率:rf = 0.02(可调)
显著性门槛:p < 0.05
年化因子:√252(A股交易日)
安装:pip install scipy
金句:
std() × √252 算波动率,
ttest_1samp() 验实力 ——
scipy 把"统计学"变成"一行代码"。
运行输出 · python .\scipy_demo.py
PS> python .\scipy_demo.py
[数据源] akshare 不可用(ProxyError),尝试 baostock...
login success!
logout success!
[数据源] baostock 获取成功,共 178 条
共 177 个交易日收益率样本
===== 年化波动率 =====
日波动率 : 0.0155
年化波动率: 24.68%
===== 夏普比率 =====
年化收益率 : -13.92%
夏普比率 : -0.65 (>1 不错,>2 很能打)
===== t 检验 =====
t 统计量: -0.473
p 值 : 0.6369
p >= 0.05 → 收益不够显著,可能只是运气
关键结论:年化波动率 24.68%;夏普比率 -0.65(负值,表现不佳);
t 检验 p = 0.6369 ≥ 0.05,收益不够显著,可能只是运气。