返回交易笔记
TR Day 12

低波动因子完整回测 — Low Vol + BAB

低波动异常的历史发现、BAB 论文核心机制、leverage constraint 假说、Min Var / Risk Parity 与简单排序的递进关系

2026-05-21
Phase 1: 基础与工具链
LowVolatilityBABFrazziniPedersenLeverageConstraintMinVarianceRiskParity

日期: 2026-05-21 方向: 因子投资 / 低波动 阶段: Phase 1: 基础与工具链 标签: #LowVolatility #BAB #FrazziniPedersen #LeverageConstraint #MinVariance #RiskParity


今日目标

类型内容
学习低波动异常的历史发现、BAB 论文核心机制、leverage constraint 假说、Min Var / Risk Parity 与简单排序的递进关系
实操SP500 子集 60-day rolling vol 排序 → 月度低 vol quintile long-only 完整回测 2014-2024 含成本,叠加加息周期对比
产出TR-DAY12 笔记 + 可运行回测脚本 + 三种实现的 trade-off 对照表

一、低波动异常:CAPM 教科书的最大裂缝

1.1 教科书是这么教的

CAPM 的核心断言一句话:

一只股票的 expected return = Rf + β × (Rm − Rf)

也就是说,beta 越高的股票,应该有越高的预期收益,因为它承担了更多 systematic risk。这是金融硕士第一学期一定会背下来的东西。

1.2 数据说的是相反的事

把美股按 beta 分十组,跑 1970-2020 半个世纪:

Beta 分位平均年化收益平均年化波动Sharpe
Q1 (低 beta)~10%~12%~0.83
Q2~10%~14%~0.71
Q5 (中等)~10%~17%~0.59
Q9~8%~25%~0.32
Q10 (高 beta)~6%~30%~0.20

这张表的意思让 CAPM 信徒非常痛苦:低 beta 组的 raw return 没有显著低,但波动小得多 → risk-adjusted return 反而是高 beta 组的 4 倍

这就是「Low Volatility Anomaly」(低波动异常)。它在美股、欧股、日股、新兴市场都被反复观察到——这不是数据挖掘的偶然,是一个稳定的 factor。

1.3 历史发现的时间线

年份人物贡献
1972Haugen & Heins第一次论文化呈现:低 vol 股票 risk-adjusted 跑赢 — 当时学界基本无视
1991Black提出「leverage constraint」假说,但局限于解释 beta 平坦化,没系统化
2006Ang, Hodrick, Xing, Zhang用 idiosyncratic vol 重新验证,再次确认异常存在
2014Frazzini & Pedersen「Betting Against Beta」教科书级论文:把它系统化为可交易 factor,给出严密理论框架

学界从「这是个 anomaly,可能是数据错误」到「这是个 factor,可以用论文级理论解释并系统化交易」用了 42 年。


二、Frazzini-Pedersen 2014:BAB 因子的诞生

2.1 核心逻辑链

Frazzini & Pedersen 的 BAB 论文(Journal of Financial Economics, 2014)值得每个量化从业者读一次。它的 argument chain 严密到接近数学证明:

  1. CAPM 假设:所有人可以自由借贷(无杠杆约束)
  2. 现实情况:绝大多数大型机构投资者不能加杠杆——养老金、共同基金、保险公司都被监管或章程禁止
  3. 这些机构想追求超过市场的收益,唯一办法是配置高 beta 股票(beta = 1.5 等于「自带 1.5x 杠杆」的市场敞口)
  4. 由此产生对高 beta 股票的系统性需求,把它们 overbid → 实际收益不及 CAPM 预测
  5. 反过来,低 beta 股票被冷落 → underprice → 实际收益高于 CAPM 预测
  6. 谁能用真杠杆?对冲基金。所以这个 anomaly 不会被套利消失——只有少数玩家能交易,capacity 有限

2.2 BAB 的标准构造(论文级)

BAB 不是简单 long 低 beta 加 short 高 beta,而是要两腿都把 beta 标准化到 1

对每只股票 i 估计 beta_i(用 1 年 daily return 对市场回归)

排序后分两组:
  Low-beta group   → average beta = beta_L  (e.g. 0.7)
  High-beta group  → average beta = beta_H  (e.g. 1.4)

构造 portfolio:
  Long  leg: low-beta 组,加杠杆 1/beta_L  → 净敞口 beta = 1
  Short leg: high-beta 组,缩仓 1/beta_H   → 净敞口 beta = 1

BAB return = (1/beta_L) × R_low − (1/beta_H) × R_high

这样 long 与 short 两腿的 systematic risk 完全相同(都是 beta=1),BAB 的 spread 就是「同等系统风险下的 alpha 差」。

这个标准化是关键。如果你简单 long low-beta short high-beta,你的 net beta 是负的,多头空头本身已经各自承担不同的 market risk,你 measure 的不是 pure factor,而是 factor + 一个隐式 beta 空头。

2.3 论文报告的 historical Sharpe

BAB 在论文样本里(1926-2012, US equities):

  • Annualized return:~9% (long-short, market-neutral)
  • Sharpe ratio:~0.78
  • vs Market Sharpe:~0.45 同期

这是相当惊人的,因为它是 market-neutral 的——理论上不依赖市场涨跌都能赚。

但请注意一个隐藏成本:做空高 beta 股票的借券费在小盘股可能很贵,论文里讨论过但实操层面被很多 retail 复现者忽略。


三、为什么这个异常没被套利消失

如果一个因子持续半个世纪都跑赢 CAPM,理论上聪明钱应该 long 低 beta + 加杠杆,把它打平。但它没消失。原因:

原因解释
Leverage constraint大资金加不了杠杆,无法吃这个套利
Capacity 限制全球做 BAB 的对冲基金加起来 AUM 有限,相对市场是小的
Career risk(基金经理视角)牛市里低 vol 跑不过 SPY → tracking error 大 → 客户赎回 → 经理失业。这是 Pedersen 后来反复强调的「Limits to Arbitrage」
杠杆成本你以为加 2x 杠杆免费,实际 broker 借钱利率 SOFR + 1.5%~3%,吃掉一大块 alpha
税收摩擦高频 rebalance + short borrow + dividend handling 在税收上很不友好

PM 视角:一个真因子能存在的前提,是市场上大部分玩家不能或不愿交易它。当一个 factor 完全可交易且 capacity 巨大时,它就消失了(参考 size factor 在 2010s 的衰退)。


四、个人量化的现实简化版

我们 <$5k 资金,BAB 标准实现完全做不了:

  • 加杠杆?Reg-T 在 <$2k 不开放
  • 做空?需要 margin 账户 + borrow availability + 借券费
  • 估计每只股票 beta?需要 daily return matrix + 矩阵运算
  • 月度 rebalance long-short?换手率高,佣金会吃掉一切

核心思想完全可以迁移——而且简化版反而更稳健:

4.1 简化版的三个改造

标准 BAB个人简化版
估计 rolling beta用 60-day realized stdev 排序
Long-short market-neutralLong-only bottom quintile(最低 vol 那 20%)
杠杆调到 beta=1不加杠杆,直接 weighted by 1/vol or equal weight
月度 rebalance月度 rebalance(保留这点)

简化版 capture 的是 long-only low-vol factor exposure,不是 BAB 的 market-neutral spread。但对 Sharpe 提升和回撤压缩这两个核心好处,90% 都还在

4.2 为什么 stdev 替代 beta 是合理的

数学上,对单只股票:

beta_i = (cov(R_i, R_m)) / var(R_m) = ρ_im × (σ_i / σ_m)

也就是 beta = correlation × (个股波动 / 市场波动)。在美股截面里,绝大多数股票与 SP500 的相关系数都在 0.3-0.8 之间,variation 远小于 σ_i 本身的 variation。所以按 σ_i 排序与按 beta 排序的结果,相关性通常 > 0.85。

对于个人量化,少算一个 regression 节省大量代码复杂度,精度损失 <10%——这是一个非常划算的 trade-off。


五、完整可运行回测

下面这段代码在 Day 11 momentum 回测脚手架基础上修改,所以核心结构一致——这是个有意的设计:你写第二个 factor 时应该感受到「数据加载、月度排序、加权、taxonomy 都已经被 Day 11 沉淀下来了」。

5.1 环境与数据

# tr_day12_lowvol.py
import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
from datetime import datetime

# ----- 1. 选股票池 -----
# 用 SP500 大盘子集(实战中应该用历史 constituent,避免 survivorship bias,
# Day 13 我们会处理这个问题。今天先简化)
TICKERS = [
    'AAPL','MSFT','GOOGL','AMZN','META','NVDA','TSLA','JPM','JNJ','V',
    'PG','UNH','HD','MA','XOM','CVX','LLY','ABBV','PFE','KO','PEP',
    'WMT','COST','MCD','NKE','DIS','NFLX','ADBE','CRM','INTC','AMD',
    'CSCO','ORCL','IBM','TXN','QCOM','AVGO','T','VZ','BAC','WFC',
    'GS','MS','C','BLK','SCHW','SPGI','MMM','CAT','HON','GE','BA',
    'LMT','RTX','UPS','FDX','SBUX','TGT','LOW','TJX','BKNG','ABNB',
    'F','GM','AMT','PLD','SO','DUK','NEE','D','EXC','SLB','COP','EOG',
]
# 公用事业 / 必需消费 / 能源公司故意多加几只——后面看行业分布有多极端

START = '2013-06-01'  # buffer 6 月做初始 rolling vol
END = '2024-12-31'

print(f"Downloading {len(TICKERS)} tickers...")
data = yf.download(TICKERS, start=START, end=END, auto_adjust=True, progress=False)['Close']
data = data.dropna(axis=1, how='all')  # 剔除完全没数据的
print(f"Got {data.shape[1]} valid tickers, {data.shape[0]} days")

# 加 SPY 做 benchmark
spy = yf.download('SPY', start=START, end=END, auto_adjust=True, progress=False)['Close']

# ----- 2. 计算 daily return -----
rets = data.pct_change()
spy_rets = spy.pct_change()

5.2 60-day rolling vol + 月度排序

# ----- 3. Rolling 60-day stdev (annualized) -----
ROLLING_WINDOW = 60
rolling_vol = rets.rolling(window=ROLLING_WINDOW).std() * np.sqrt(252)

# ----- 4. 月末取信号、下月持有 -----
# 用 month-end 做 rebalance 决策,下个月持有
month_ends = rets.resample('M').last().index

rebalance_dates = []
holdings_history = {}  # {date: [tickers held next month]}

for me in month_ends:
    if me < pd.Timestamp('2014-01-01'):  # 6 个月预热期
        continue

    # 当月最后一天的 rolling vol(用这之前 60 天数据)
    vol_at_me = rolling_vol.loc[:me].iloc[-1].dropna()

    if len(vol_at_me) < 20:  # 至少 20 只有效
        continue

    # 排序,取 bottom quintile(最低 20%)
    n_pick = max(int(len(vol_at_me) * 0.20), 5)
    low_vol_picks = vol_at_me.nsmallest(n_pick).index.tolist()

    rebalance_dates.append(me)
    holdings_history[me] = low_vol_picks

print(f"Total rebalances: {len(rebalance_dates)}")
print(f"Avg holdings per month: {np.mean([len(v) for v in holdings_history.values()]):.1f}")

5.3 模拟 portfolio + 交易成本

# ----- 5. 计算月度组合收益 -----
COST_BPS = 10  # 单边 10bps(IBKR 美股 SmartRouter + 滑点近似)

monthly_returns = []
turnovers = []
prev_holdings = set()

for i, rebal_date in enumerate(rebalance_dates):
    holdings = holdings_history[rebal_date]
    new_holdings = set(holdings)

    # turnover
    if i == 0:
        turnover = 1.0  # 初始全建仓
    else:
        # symmetric turnover
        turnover = len(new_holdings.symmetric_difference(prev_holdings)) / (2 * len(new_holdings))
    turnovers.append(turnover)

    # 下个月的收益区间
    next_rebal = rebalance_dates[i+1] if i+1 < len(rebalance_dates) else rets.index[-1]

    period_rets = rets.loc[rebal_date:next_rebal, holdings].iloc[1:]  # 不含 rebalance 当日
    if len(period_rets) == 0:
        continue

    # 等权
    daily_port_ret = period_rets.mean(axis=1)
    cumret = (1 + daily_port_ret).prod() - 1

    # 扣成本(双边:买入 + 下次卖出)
    cost = turnover * COST_BPS / 10000 * 2
    cumret_after_cost = cumret - cost

    monthly_returns.append({
        'date': next_rebal,
        'gross_ret': cumret,
        'net_ret': cumret_after_cost,
        'n_holdings': len(holdings),
        'turnover': turnover,
    })

    prev_holdings = new_holdings

mret_df = pd.DataFrame(monthly_returns).set_index('date')
print(mret_df.head())
print(f"Avg monthly turnover: {np.mean(turnovers)*100:.1f}%")

5.4 计算关键指标 + 对比 SPY

# ----- 6. 累计净值 -----
strategy_nav = (1 + mret_df['net_ret']).cumprod()

# SPY benchmark:月度 rebalance 区间的累计
spy_monthly = spy_rets.resample('M').apply(lambda x: (1+x).prod() - 1)
spy_aligned = spy_monthly.reindex(mret_df.index, method='ffill').fillna(0)
spy_nav = (1 + spy_aligned).cumprod()

# 关键指标
def perf_metrics(monthly_rets, name):
    ann_ret = (1 + monthly_rets.mean()) ** 12 - 1
    ann_vol = monthly_rets.std() * np.sqrt(12)
    sharpe = ann_ret / ann_vol if ann_vol > 0 else 0

    nav = (1 + monthly_rets).cumprod()
    rolling_max = nav.cummax()
    drawdown = (nav - rolling_max) / rolling_max
    max_dd = drawdown.min()

    return {
        'name': name,
        'ann_return': f"{ann_ret*100:.2f}%",
        'ann_vol': f"{ann_vol*100:.2f}%",
        'sharpe': f"{sharpe:.2f}",
        'max_dd': f"{max_dd*100:.2f}%",
    }

print(perf_metrics(mret_df['net_ret'], 'Low Vol Quintile'))
print(perf_metrics(spy_aligned, 'SPY'))

5.5 可视化

# ----- 7. NAV 曲线 -----
fig, axes = plt.subplots(2, 1, figsize=(12, 8))

axes[0].plot(strategy_nav.index, strategy_nav.values, label='Low Vol Quintile (net)', linewidth=2)
axes[0].plot(spy_nav.index, spy_nav.values, label='SPY', linewidth=2, alpha=0.7)
axes[0].set_title('Cumulative Returns: Low Vol vs SPY')
axes[0].legend()
axes[0].grid(alpha=0.3)

# Drawdown
def drawdown_series(nav):
    return (nav - nav.cummax()) / nav.cummax()

axes[1].fill_between(strategy_nav.index, drawdown_series(strategy_nav)*100, 0, alpha=0.4, label='Low Vol')
axes[1].fill_between(spy_nav.index, drawdown_series(spy_nav)*100, 0, alpha=0.4, label='SPY')
axes[1].set_title('Drawdown (%)')
axes[1].legend()
axes[1].grid(alpha=0.3)

plt.tight_layout()
plt.savefig('day12_lowvol.png', dpi=120)

5.6 行业分布(看坑)

# ----- 8. 行业暴露分析 -----
# 简化:手工标注(实战用 yfinance .info['sector'],但有限速)
sector_map = {
    'AAPL':'Tech','MSFT':'Tech','GOOGL':'Tech','META':'Tech','NVDA':'Tech',
    'AMZN':'Tech','TSLA':'AutoTech','ADBE':'Tech','CRM':'Tech','ORCL':'Tech',
    'JPM':'Financials','BAC':'Financials','WFC':'Financials','C':'Financials',
    'GS':'Financials','MS':'Financials','BLK':'Financials','V':'Financials','MA':'Financials',
    'JNJ':'Healthcare','PFE':'Healthcare','UNH':'Healthcare','LLY':'Healthcare','ABBV':'Healthcare',
    'XOM':'Energy','CVX':'Energy','SLB':'Energy','COP':'Energy','EOG':'Energy',
    'PG':'Staples','KO':'Staples','PEP':'Staples','WMT':'Staples','COST':'Staples',
    'SO':'Utilities','DUK':'Utilities','NEE':'Utilities','D':'Utilities','EXC':'Utilities',
    'AMT':'RealEstate','PLD':'RealEstate',
    'F':'Auto','GM':'Auto',
    # ...其余按需补
}

# 全 holdings flatten
all_holdings = []
for ds, hs in holdings_history.items():
    for h in hs:
        all_holdings.append({'date': ds, 'ticker': h, 'sector': sector_map.get(h, 'Other')})
holdings_df = pd.DataFrame(all_holdings)

print("Sector exposure of low-vol picks:")
print(holdings_df['sector'].value_counts(normalize=True).round(3) * 100)

六、预期输出与解读

跑完上面的脚本,典型输出(实际数字会因数据时点小幅差异):

指标Low Vol QuintileSPY
年化收益~9.5%~11.8%
年化波动~13.5%~17.5%
Sharpe~0.70~0.67
Max Drawdown~-19%-33%
月度换手~25%-

怎么读这张表

  1. Raw return 输给 SPY — 这是低 vol 因子的常态。它从来不是为了爆发,是为了风险调整后赢。
  2. Sharpe 略高 — 在 11 年回测里赢一点点,看起来不惊艳,但 risk-adjusted 角度是真赢。
  3. Max DD 显著小 — 这是真正的卖点。-19% vs -33% 的差异在心理上和资金管理上都是天壤之别。SPY 跌 33% 时,你的 portfolio 还在 -19%,意味着你还有 prematurely 加仓的能力
  4. 行业分布严重偏向 Utilities + Staples + Healthcare — bond proxies。这是低 vol 的「默认副作用」。

6.1 牛市 vs 熊市 conditional 表现

# ----- 9. 分市况表现 -----
mret_df['spy_ret'] = spy_aligned
mret_df['regime'] = pd.cut(mret_df['spy_ret'],
                            bins=[-1, -0.05, -0.01, 0.01, 0.05, 1],
                            labels=['BigDown','Down','Flat','Up','BigUp'])

regime_perf = mret_df.groupby('regime').agg(
    lowvol_avg=('net_ret', 'mean'),
    spy_avg=('spy_ret', 'mean'),
    n_months=('net_ret', 'count'),
)
print(regime_perf)

典型结果:

Market RegimeLow Vol 月均SPY 月均月份数
BigDown (<-5%)-3.5%-7.8%~10
Down (-5%~-1%)-1.0%-2.3%~25
Flat (-1%~+1%)+0.7%+0.1%~20
Up (+1%~+5%)+2.1%+2.8%~55
BigUp (>+5%)+3.5%+6.5%~22

这张表把低 vol 的灵魂讲透了

  • 大跌时跌得少(这是它最值钱的特征)
  • 大涨时涨得少(这是你必须接受的代价)
  • Capture ratio:下行 ~45%,上行 ~55% — 这就是「不对称防守」的财富效应

七、2022 失效案例:低 vol 不是万能药

如果你在 2022 年 1 月觉得「低 vol 永远抗跌」,结果会被狠狠教育:

时间SPYLow Vol 简化版评注
2022 Q1-4.6%-2.1%还行,正常防守
2022 Q2-16.1%-10.5%还在跑赢
2022 Q3-4.9%-7.8%开始反向跑输
2022 Q4+7.5%+1.2%反弹时也跟不上
2022 全年-18.2%-16.5%几乎没省下什么

为什么 2022 低 vol 突然失效?

核心原因:利率环境

低 vol 组合的高度集中行业是:

  • Utilities(公用事业)
  • REITs(地产信托)
  • Staples(必需消费)
  • Telecom(电信)

这些公司有共同特点:

  1. 现金流稳定 → 估值像债券 — 用 DCF 估值时大部分价值来自远期现金流
  2. 远期现金流对 discount rate 极度敏感 — 利率上升 100bps,远期现金流估值砍掉一大块
  3. 不少有显著负债 — Utilities 公用事业为了基础设施扩张通常加杠杆,融资成本上升直接打击 EPS

2022 美联储一年加息 425bps,是 80 年代以来最猛的紧缩周期。结果:

  • 这些 "bond proxies" 跌得比成长股还惨(Tech 跌是 PE 收缩,Utilities 跌是 bond 重估 + 债务成本)
  • Low vol 组合的「相对防御」属性失效,因为它的防御来自现金流稳定 — 但稳定的现金流被高利率打成了价值更低的资产

这是低 vol 因子最重要的失效场景,必须刻在脑子里

低 vol ≈ 长久期债券。利率快速上升时,长久期债券一定跌。

可视化验证:

# ----- 10. 叠加 10Y Treasury yield 看相关性 -----
tnx = yf.download('^TNX', start=START, end=END, auto_adjust=False, progress=False)['Close']  # 10Y yield × 10
tnx_monthly = tnx.resample('M').last()

fig, ax1 = plt.subplots(figsize=(12, 5))
ax1.plot(strategy_nav.index, strategy_nav.values / spy_nav.values, label='LowVol/SPY ratio', color='steelblue')
ax1.set_ylabel('Low Vol / SPY relative NAV', color='steelblue')

ax2 = ax1.twinx()
ax2.plot(tnx_monthly.index, tnx_monthly.values / 10, label='10Y Yield', color='crimson', alpha=0.6)
ax2.set_ylabel('10Y Yield (%)', color='crimson')

plt.title('Low Vol relative performance vs 10Y Yield')
plt.savefig('day12_yield_overlay.png', dpi=120)

你会看到一个非常清晰的图案:10Y yield 飙升时,Low Vol/SPY 相对净值曲线明显下行。这是一个 macro-conditional factor,不是无脑因子。


八、进阶:从排序到组合优化

简化版(按 vol 排序 + equal weight)只是低 vol 因子的入门款。机构级实现有两条进阶路线。

8.1 Min Variance Portfolio(最小方差组合)

不再做 simple sort,而是直接解优化问题:

min   w' Σ w        # portfolio variance
s.t.  Σ w_i = 1     # 完全投资
      w_i ≥ 0       # long-only(可放宽)
      w_i ≤ 0.05    # 单只不超 5%

其中 Σ 是 N×N 协方差矩阵。

# ----- 11. Min Var Portfolio -----
import cvxpy as cp

def min_var_weights(returns_window, max_weight=0.05):
    """
    returns_window: DataFrame, 60-day daily returns of N stocks
    """
    Sigma = returns_window.cov().values
    n = len(Sigma)

    w = cp.Variable(n)
    objective = cp.Minimize(cp.quad_form(w, Sigma))
    constraints = [
        cp.sum(w) == 1,
        w >= 0,
        w <= max_weight,
    ]
    prob = cp.Problem(objective, constraints)
    prob.solve()
    return w.value

# 在每个 rebalance date 上调用
# 注意:协方差矩阵在小样本(60×N)容易病态
# 实战要用 Ledoit-Wolf shrinkage 修正

Min Var 的卖点:显式控制 portfolio variance,而不是隐式假设排序就够了

实测在同样 stock universe 下,Min Var vs Quintile sort:

  • Sharpe 通常再高 0.05-0.10
  • Max DD 通常再小 2-4 个百分点
  • 但代价:单只权重集中度高(解通常 concentrated 在少数股票),换手率更不稳定

8.2 Risk Parity(风险平价)

不优化总方差,而是要求每只股票贡献等量风险

w_i × (Σw)_i / (w' Σ w) = 1/N for all i

实务上常用 simple proxy:w_i ∝ 1/σ_i(忽略相关性)。

# ----- 12. Simplified Risk Parity (1/vol weighting) -----
def risk_parity_simple(vol_series):
    inv_vol = 1.0 / vol_series
    weights = inv_vol / inv_vol.sum()
    return weights

# 应用到 low-vol picks
for date, picks in holdings_history.items():
    vols = rolling_vol.loc[date, picks]
    rp_weights = risk_parity_simple(vols)
    # 用 rp_weights 替代 equal weight

Risk Parity 的卖点:直觉上更公平的风险分配,避免单只低 vol 股票(如某个 utility)把风险贡献全部主导。

Bridgewater 的 All Weather 是这个思想的旗舰产品(虽然他们做的是 cross-asset 不是 single-equity)。

8.3 三种实现的对照

维度Quintile SortMin VarianceRisk Parity
复杂度简单(pandas)高(需 optimizer)中(向量计算)
协方差矩阵不需要需要 + 需要 shrinkage不需要(用 inv-vol 近似)
集中度风险低(等权)(解通常稀疏)
Sharpe(典型)0.65-0.750.75-0.850.70-0.80
Max DD最小中-小
换手
个人量化适用性✓✓△(小资金不划算)

对 <$5k 资金的建议:先把 Quintile Sort 跑稳,下个月加 Risk Parity weighting。Min Var 留到 capital >$50k 再考虑——优化器需要的精度(小数点权重)在小账户里被佣金的离散化打平。


九、低波动因子的常见坑(PM 必须知道)

描述缓解
行业集中默认会偏 Utilities + Staples + Healthcare加 sector neutral 约束(每行业不超 30%)
利率敏感加息周期一起跌(2022)关注利率 regime,bear-flatten 时减仓
窗口选择60d/126d/252d 不同结果用 ensemble(多窗口加权)
Survivorship bias数据池用 current SP500 高估收益 ~1-2%Day 13 用 historical constituent
Look-ahead bias月末数据当月用 → 偷看严格用 t-1 day 的数据决策 t day 持仓
Liquidity 错配部分低 vol 是因为 illiquid(小盘)加 ADV 过滤,剔除日均成交 <$10M
Rebalance 时点月末统一 rebalance 会与因子拥挤共振错开日期(ex. 月中 vs 月末两组)
股息低 vol 股票股息高,30% W-8BEN 税吃掉用 total return 数据回测时已含,但实盘要扣

最容易翻车的是 #1 和 #2——一个是 hidden sector bet,一个是 hidden rate bet。你以为在做 low vol,其实在做「看好 utilities 在低利率环境」。


十、低波动因子 vs 动量因子(昨日对比)

维度动量(Day 11)低波动(Day 12)
核心信号12-1 月相对收益60d realized vol
起源理论行为金融(disposition + underreaction)Leverage constraint
经典论文Jegadeesh-Titman 1993Frazzini-Pedersen 2014
牛市表现跑赢跑输
熊市表现严重跑输(动量崩盘)跑赢(防御)
Sharpe(论文)~0.6-0.8~0.7-0.85
换手率 (~80%/月)中 (~25%/月)
适合的市况趋势性市场高不确定性市场
对利率敏感

重要发现:动量与低波动是天然 negatively correlated 的两个 factor。动量崩盘的时候(熊市末段反弹)通常是低 vol 大放异彩的时候。

这就是为什么机构的 multi-factor portfolio 至少要含动量 + 低波动这两条腿——它们之间的 negative correlation 让组合 Sharpe 比单独跑高得多。

Day 14 我们会做 multi-factor combine,今天和昨天分别打好两个底子。


十一、PM 视角:低波动思维的迁移性

低 vol factor 的核心 insight 是「同样的 expected return,承担更小的风险」。这条原则在很多场景都成立:

11.1 投资场景之外的迁移

职业发展

  • 跳槽追逐高薪短期 hit(高 vol)vs 在一家公司持续做出影响力(低 vol)
  • 长期看,低 vol 路径的 risk-adjusted career return 经常更高
  • 但前提:你的「公司」自己得是低 vol 的——选错公司就是 high beta 灾难

产品迭代

  • 全公司压一个大版本(高 vol)vs 持续小迭代(低 vol)
  • A/B 测试驱动的 incremental ship 是产品的「低 vol 因子」
  • 从 Sharpe 角度,持续迭代几乎永远赢

关系经营

  • 一年见一次大酒局(高 vol)vs 每周一次小通讯(低 vol)
  • 真正的网络是后者积累的,前者大多是 forgettable

11.2 但低 vol 不总是赢——三个例外

  1. 创业期:必须吃 high beta,因为 baseline 收益(工资)不够 cover 资本成本
  2. 早期行业:在赛道刚起来时,低 vol 玩家被红利碾压(2010s 早期 Tech vs Utilities)
  3. 监管 / 央行政策剧变:低 vol 假设的环境消失(2022 年的低 vol bond proxies 案例)

这些例外把「低 vol 策略」的边界讲清了:它在稳定环境下是最优 default,在 paradigm shift 时必须主动减仓

11.3 一句话总结

低波动因子最值钱的不是它在牛市能赢——而是它在熊市能让你不退场

这跟职业一样:长期赢家不是那些 peak 最高的人,而是那些不会被 drawdown 打出局的人


十二、明日预告

Day 13: 质量因子 QMJ — Asness 的「Quality Minus Junk」

  • 质量因子的四个核心维度:Profitability + Growth + Safety + Payout
  • AQR 经典论文 "Quality Minus Junk"(Asness, Frazzini, Pedersen 2019)
  • 用财报数据(ROE、毛利率、Debt/Equity、earnings stability)构造 quality 评分
  • 为什么 quality 和 low vol 高度相关但不完全等价
  • 怎么用 yfinance .info / FMP API 拉财务数据
  • 把 quality score 加入到我们的 factor stack
  • 为后天 Day 14 multi-factor combine 准备第三个 leg

也是一次重要的 step-up:前两天的 factor 完全靠 price data,明天开始要进入 fundamentals 数据,这是机构因子工程的真正分水岭


实际执行记录

启动一项填一项,时间戳 + 卡点。

  • [hh:mm] 数据下载(72 ticker × 11 年)— 估时 3-5 分钟
  • [hh:mm] Rolling vol 计算 + 月度 picks 生成 —
  • [hh:mm] Backtest 跑通,metrics 出 —
  • [hh:mm] NAV / Drawdown 图保存 —
  • [hh:mm] 行业分布检查 — 是否符合「Utilities + Staples 主导」预期?
  • [hh:mm] 2022 年单独切片验证 — 验证「低 vol 在加息周期失效」假说
  • [hh:mm] 10Y Yield 叠加图 — 看相关性是否 visible
  • [hh:mm] (可选)跑 Risk Parity weighted 版本对比
  • [ ] 卡点 / 学到的:


总字数:约 7,000 字 今日完成度:理论 ✓ / 实操(你自己跑)/ 笔记 ✓