Files
quanxiel/alpha/低波动率策略.ipynb

7.7 KiB

低波动率策略 — 构建与回测

策略思路

低波动率异常(Low Volatility Anomaly)指波动率较低的股票,长期来看风险调整后收益往往优于高波动股票。 本策略使用 20 日波动率倒数 作为低波因子,每月调仓,买入波动率最低的一批股票。

研究流程

  1. 加载数据
  2. 低波因子计算与 IC 分析
  3. 分层回测验证因子有效性
  4. 构建策略并回测
  5. 绩效评估
In [ ]:
import sys
sys.path.insert(0, '..')

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from alpha.config import AlphaConfig
from alpha.factors import FactorAnalyzer
from alpha.strategy import Strategy, QuantileSignal, EqualWeightAllocator
from alpha.backtest import BacktestEngine
from alpha.evaluation import PerformanceEvaluator
from alpha.data_loader import DataLoader

%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

print('模块导入成功')

1. 加载数据

In [ ]:
# 回测区间
START_DATE = '2020-01-01'
END_DATE   = '2024-12-31'

loader = DataLoader()

# 后复权收盘价
price_data = loader.load_prices(START_DATE, END_DATE)
print(f'价格数据: {price_data.shape}, 日期: {price_data.index[0]} ~ {price_data.index[-1]}')
price_data.head()

2. 低波因子计算与 IC 分析

In [ ]:
# 低波因子: 20日波动率的倒数(波动越小 → 因子值越大)
VOL_WINDOW = 20
daily_ret = price_data.pct_change()
volatility = daily_ret.rolling(VOL_WINDOW).std()
low_vol_factor = -volatility  # 取负号使低波动为正

# 未来 10 日收益率(验证预测能力,低波策略通常持有期较长)
fwd_10d = price_data.pct_change(10).shift(-10)

factor_stacked = low_vol_factor.stack()
fwd_stacked = fwd_10d.stack()

analyzer = FactorAnalyzer(factor_stacked, fwd_stacked)
ic = analyzer.compute_ic(method='rank')

print('低波因子 IC 汇总:')
for k, v in analyzer.ic_summary().items():
    print(f'  {k}: {v:.4f}')

# IC 曲线
ic.plot(figsize=(12, 3), title='低波因子 Rank IC 时间序列')
plt.axhline(y=0, color='r', linestyle='--')
plt.show()

3. 分层回测

In [ ]:
# 分 5 组,观察单调性(Q1=高波动, Q5=低波动)
quantile_ret = analyzer.quantile_returns(n_quantiles=5)
print('各分位组平均收益 (Q1=最高波动, Q5=最低波动):')
print(quantile_ret)

quantile_ret['avg_return'].plot(kind='bar', figsize=(8, 4), color='steelblue')
plt.title('低波因子分层收益 (未来10日)')
plt.ylabel('平均收益率')
plt.grid(True, alpha=0.3)
plt.show()

4. 构建策略并回测

In [ ]:
# 回测配置
config = AlphaConfig(
    initial_cash=1_000_000,
    commission_rate=0.0003,
    slippage=0.001,
    stamp_tax=0.001,
)

# 低波策略:持有波动率最低的 20% 股票,等权
strategy = Strategy(
    name='低波动率策略-20日',
    factors=[],
    signal_generator=QuantileSignal(
        n_quantiles=5, long_quantile=5, short_quantile=0,  # 只做多
    ),
    weight_allocator=EqualWeightAllocator(max_positions=10),
    description='每月持有过去20日波动率最低的20%股票,等权配置'
)

engine = BacktestEngine(config)
equity_curve = engine.run(
    strategy=strategy,
    price_data=price_data,
    factor_data={'low_vol': low_vol_factor},
    rebalance_freq='M',
)

print(f'回测完成, 共 {len(equity_curve)} 个交易日')
print(f'累计收益率: {(equity_curve["nav"].iloc[-1] - 1) * 100:.2f}%')

5. 净值曲线与回撤

In [ ]:
fig, axes = plt.subplots(2, 1, figsize=(14, 8))

# 净值曲线
axes[0].plot(equity_curve.index, equity_curve['nav'], label='策略净值', color='green')
axes[0].axhline(y=1.0, color='gray', linestyle='--')
axes[0].set_title('低波动率策略净值曲线')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 回撤曲线
nav = equity_curve['nav']
running_max = nav.cummax()
drawdown = (nav - running_max) / running_max
axes[1].fill_between(equity_curve.index, 0, drawdown.values, color='red', alpha=0.3)
axes[1].set_title('回撤曲线')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

6. 绩效评估

In [ ]:
# 基准:股票池等权组合
bench_ret = price_data.pct_change().mean(axis=1)

evaluator = PerformanceEvaluator(equity_curve, benchmark_returns=bench_ret, risk_free_rate=0.03)
print(evaluator.summary())

report_df = evaluator.full_report()
pd.DataFrame(list(report_df.items()), columns=['指标', '数值']).set_index('指标')

波动率窗口敏感性分析

不同波动率计算窗口对因子表现的影响:

In [ ]:
# 不同波动率窗口对比
for win in [5, 10, 20, 40]:
    vol = daily_ret.rolling(win).std()
    fac = -vol
    a = FactorAnalyzer(fac.stack(), fwd_stacked)
    summary = a.ic_summary()
    print(f'窗口 {win}日: IC均值={summary["IC_Mean"]:.4f}, ICIR={summary["IR"]:.4f}, '
          f'IC>0占比={summary["IC>0_Ratio"]:.2%}')