跳转至

M04 资金管理与风险控制

层级:L1 策略与回测 | 优先级:★★★ | 预计学时:12 小时 对应原书:陈 第 6 章、7.8;黑箱 第 10 章 前置知识:M00 的杠杆与融资利差;M01 的夏普与肥尾;M03 的 shift(1) 与费用。 读书笔记:陈第 6 章与 7.8 · 黑箱第 10 章 状态:reviewed 数据截至:2026-09|最近复核:2026-10-28


学习目标

  1. 从几何布朗运动的对数漂移推出连续凯利杠杆 f⋆ = (μ − r) / σ²,并用一注赔率 1:1 的赌局手算半凯利的对数增长。
  2. 把波动率目标写成「用昨日波动决定今日仓位」。在本仓库的 SPY 种子上,它缩小了回撤,没有提高夏普。
  3. 区分止损有用的动态(动量、状态切换)和只会砍掉期望的动态(随机游走)。
  4. 用单位净值衡量回撤,使入金出金不制造、也不掩盖回撤。本轮账户的杠杆上限是 1.0。
  5. 把 2007 年 8 月的量化平仓和 2020 年的波动目标放在同一条链上:杠杆和同向减仓会让你在反弹前失去仓位。

本章知识拓扑图

flowchart TB
    MU["超额均值 μ − r"] --> KELLY["凯利杠杆 f* = (μ − r) / σ²"]
    SIG["波动 σ"] --> KELLY
    KELLY --> CAP["政策上限:本轮杠杆 ≤ 1"]
    YDAY["截至昨日的波动"] --> VT["仓位 = min(目标 / 预测波动, 上限)"]
    VT --> CAP
    NAV["单位净值,入金不改高水位"] --> DD["回撤触及阈值才减仓"]
    DD --> STOP["停新开仓要人工恢复"]
    CROWD["同向持仓 + 保证金"] --> UNWIND["平仓发生在价格反弹之前"]

仓位是下游模块的输入。M12 接收风险预算,M15 接收「停了之后谁来恢复」。本章不产生 alpha 预测。


🟢 入门层:先留下复利

1. 回本需要的涨幅大于跌幅

从净值 1 − d 回到 1,需要的涨幅是

1 / (1 − d) − 1.

d = 0.20 时,1/0.8 − 1 = 0.25。跌 20% 要涨 25% 才回本。跌得更深时,分子不变、分母变小,所需涨幅上升得更快:

亏损 d 回本涨幅
10% 11.1%
20% 25%
33.3% 50%
50% 100%
80% 400%

资金管理控制的是 d 的右尾。一个很少出现深回撤的 10% 复利,和偶尔腰斩的 20% 算术均值,长期不是同一笔财富。

2. 波动怎样吃掉复利

−σ²/2 是波动磨损:颠簸本身会吃掉一段复利,算术平均还在,几何增长已经变小。 算术年化 10%、波动 40% 时,磨损是 0.08,能复利的对数漂移只剩 0.02。 杠杆把磨损按波动的平方放大,所以加仓有一个顶点,过了顶点对数财富的期望往下走。 下面的 g = μ − σ²/2 就是这道磨损的连续复利写法。

几何布朗运动 dS/S = μ dt + σ dW 的对数漂移是

g = μ − σ²/2.

这里的 μ 是算术漂移,σ 是同一时间单位上的波动。算术年化 10%、波动 40% 时,g = 0.10 − 0.16/2 = 0.02。高波动直接降低你能复利的增长率,所以杠杆有一个顶点,过了顶点再加杠杆,算术均值还在升,对数财富的期望在降。

日频简单收益还有一项量级为 μ²/2 的修正:E[log(1 + R)] ≈ μ − (σ² + μ²) / 2。μ = 12%、σ = 30% 时,几何布朗运动公式给出 7.5%,再减去 μ²/2 = 0.72 个百分点是 6.8%。正文的手算和右图用前一个公式,并写明它是连续复利下的精确漂移。

3. 对手是谁

行为 财富上发生的事 文献里的人
把换手当作行动 1991–1996 年,交易最多的一档家庭,扣费后年化几何收益 11.4%,同期市值加权市场 17.9% Barber & Odean (2000, JF 55(2)),66,465 个折扣券商家庭
盈利卖得快、亏损拿得久 价差和税后的实现盈亏不对称 Shefrin & Statman (1985, JF 40(3));Odean (1998, JF 53(5))
亏损后加大注码 不利赌局里注码上升,破产概率上升 与凯利相反的方向,见第 4 节
回撤中关掉、反弹后打开 减仓发生在低点附近,仓位在高点恢复 第 9 节的均线叠加,55 个月半仓

Barber & Odean 的 6.5 个百分点主要来自当时的佣金和买卖价差。毛收益在高低换手之间差不多。今天的美股佣金低得多,不能把 6.5 当作每多交易一年就要扣的固定数。它说明的是:换手的好处要先盖过你自己的费用表。


🟡 进阶层:杠杆、波动目标和回撤

4. 连续凯利

把仓位想成油门。收益随油门线性增加,风阻式的方差惩罚按油门的平方上涨,对数增长是一条抛物线。 顶点 f⋆ 是全凯利。正好两倍全凯利时,超出现金的对数增长回到 0;再加大就变成负的。 半凯利把颠簸砍半,超额对数增长留下全凯利的 ¾,让出的是那 ¼。 75% 乘在超出 r 的那一段上,不乘在含现金利率的总增长率上。本轮杠杆上限 1.0 比多数顶点更低。

出处:Kelly (1956), Bell System Technical Journal 35(4),信息率的赌局比例。投资上的连续版本见 Thorp (2006) 收于 Handbook of Asset and Liability Management。分数凯利的路径性质见 MacLean, Thorp & Ziemba 编 (2010), The Kelly Capital Growth Investment Criterion, World Scientific。

资产算术漂移 μ、波动 σ,现金与借款利率都是 r,财富中比例 f 放在资产上。组合的算术漂移和波动是

μₚ = r + f(μ − r), σₚ = fσ.

对数漂移

g(f) = r + f(μ − r) − f²σ²/2.

对 f 求导,g′(f) = (μ − r) − fσ²。令导数为 0:

f⋆ = (μ − r) / σ².

代回后,超出现金的增长率是夏普 S = (μ − r) / σ 的平方的一半:

g(f⋆) − r = S²/2.

半凯利 f⋆ / 2 的超额增长:

g(f⋆ / 2) − r = ¾ · S²/2.

组合波动是全凯利的一半。75% 指的是超出 r 的那一段对数增长,不是把含现金利率的总增长率砍到 75%。

符号 含义 单位
μ 资产算术漂移 与 σ 同一时间单位,本章用手算时用年
r 现金利率,也是借款利率 与 μ 相同
σ 资产波动 同上
f 资产占财富的比例 f > 1 表示借款
S (μ − r) / σ 无量纲

手算。 超额 8%,波动 20%,r 任意但借款利率等于它。f⋆ = 0.08/0.20² = 2。S = 0.4,S²/2 = 0.08,所以全凯利比现金高 8 个对数百分点。半凯利 f = 1:

g − r = 1 × 0.08 − (1² × 0.04) / 2 = 0.06,

是 0.08 的 75%。波动从 2 × 20% = 40% 降到 20%。

融资利率等于 r 时,夏普不随 f 改变(M00)。凯利最大化的是 g(f),那是一条抛物线。夏普平坦和增长率有顶点,两件事同时成立。借款利率高于 r 时,夏普会随杠杆下降,M00 里 12% / 15%、借款 5%、两倍杠杆的夏普从 0.53 降到 0.50。

参数减半。 估计的超额是 6%,波动 15%,f⋆ = 0.06/0.15² = 0.06/0.0225 = 8/3 ≈ 2.67。若真实超额只有 3%,仍按 8/3 下注:

8/3 × 0.03 − ((8/3)² × 0.0225) / 2 = 0.08 − 0.08 = 0.

超出现金的对数增长是 0,波动却是 (8/3) × 15% = 40%。全凯利对 μ 的高估没有容错。半凯利把这个例子的杠杆降到 4/3。本轮 docs/risk_policy.md 的杠杆上限是 1.0,比 4/3 更低。凯利是上界的参照,政策文件里的 1.0 才是下单闸门。

「一半的概率回到一半」。 仅在 r = 0、参数已知、永远按全凯利连续再平衡、价格是几何布朗运动时成立。对数财富的漂移是 S²/2,方差率是 S²。触及初始财富的一半,对数距离是 ln 2。正漂移扩散首次碰到下壁 −ln 2 的概率是

exp(−(2 · (S²/2)) / S² ln 2) = ½.

这是「最终会摸到初始值的一半」的概率,不是「明年有 50% 的机会回撤 50%」。r > 0 时对数漂移更大,这个概率低于 ½。肥尾会让真实路径比这个扩散更差,公式不覆盖跳空。

多资产。 超额均值向量 M、协方差 C 已知时,同一套对数近似的无约束解是 F⋆ = C⁻¹M。它和均值—方差切点在借款利率等于 r 时是同一组权重(M12)。样本均值直接求逆,权重会极端。个人账户先被杠杆上限、单名上限和费用截断,再谈求逆。

5. 一注赔率已知时的离散凯利

胜率 p,净赔率 b(赢了利润是赌注的 b 倍,输了输掉赌注):

f⋆ = p − (1 − p) / b.

p = 0.55、b = 1 时,f⋆ = 0.55 − 0.45 = 0.10。一注的期望对数增长:

g(0.10) = 0.55 ln 1.10 + 0.45 ln 0.90 = 0.005008,

g(0.05) = 0.55 ln 1.05 + 0.45 ln 0.95 = 0.003753,

g(0.20) = 0.55 ln 1.20 + 0.45 ln 0.80 = −0.000138.

半凯利是全凯利的 0.003753/0.005008 = 74.9%,和连续公式的 75% 对齐。两倍凯利的 g 为负:每注期望对数财富下降,一千注的 exp(1000g) = 0.87,中位路径最终低于本金。

这是已知 p 的硬币,不是股票。下面的路径分布用种子 7、1000 条路径、每条 1000 注,只说明散度:

比例 每注 E[ln] exp(1000g) 样本中位终值 样本第 10 百分位 样本中位最大回撤
0.5 倍凯利 0.003753 42.63 42.63 5.21 −61.8%
1 倍 0.005008 149.7 122.4 2.70 −89.0%
2 倍 −0.000138 0.87 0.87 0.00026 −99.9%

全凯利的理论中位财富高于半凯利,样本第 10 百分位却更低,中位回撤约 −89%。样本中位数 122 与 exp(1000g) = 150 的差距来自 1000 条路径的抽样,增长排序以 E[ln] 为准。

6. 波动率目标

仓位

wₜ = min(σ⋆ / ˆσₜ₋₁, w_max).

ˆσₜ₋₁ 只用 t − 1 及更早的收益。空出来的权重赚现金;超过 1 的部分是杠杆。Moreira & Muir (2017, JF 72(4)) 在市场和若干因子上发现:波动升高后,预期收益没有同比升高,按波动缩小仓位提高了他们样本里的夏普。Harvey, Hoyle, Korgaonkar, Rattray, Sargaison & Van Hemert (2018, Journal of Portfolio Management 45(1)) 认为尾部和回撤的下降更稳,夏普的提高主要出现在股票和信用上。Cederburg, O'Doherty, Wang & Yan (2020, JFE 138(1)) 指出,可实施的样本外构造会把这块 alpha 削掉不少。

本仓库 CovarianceModel.volatility 用固定回溯窗的样本协方差,窗口右端严格落在目标交易日之前,再乘 252。那是配置用的估计,不是指数加权。下面的教学图用 span 为 60 的 EWMA(α = 2/61),并且 shift(1),以便和日收益对齐。两者不要混成同一个函数。

种子 knowledge/Labs/momentum_plus_lab/seed_data/spy.csv,复权收盘价。现金收益记 0,杠杆不付借款利息。目标年化波动 12%,夏普的无风险利率 2%/252,与 metrics.py 的日频定义一致。窗口 2014-01-07 至 2026-09-28,3200 个收益日。

规则 CAGR 波动 夏普 最大回撤
买入持有 13.86% 17.13% 0.73 −33.70%
目标 12%,上限 1.5 10.11% 12.28% 0.68 −16.89%
同一估计,上限 1.0 9.80% 11.47% 0.70 −16.43%

上限 1.5 的权重均值 0.917,39.06% 的交易日权重大于 1,9% 的交易日顶在 1.5。实现波动 12.28% 贴近目标,是因为滞后、截断和 EWMA,不是因为公式保证等于 12%。这段样本里两种上限的夏普都低于买入持有。波动目标在这里换到了更浅的回撤和更低的复利,没有复现 Moreira & Muir 的夏普提升。现金收益记 0 会低估低仓月份;免费杠杆会高估 w > 1 的日子。上限 1.0 的一行把免费杠杆拿掉,夏普仍然是 0.70。

上限 1.0 接入现金利息的对照

上一行和 plot_vol_target.py 的图仍把现金收益记为 0:上限 1.0 的 CAGR 是 9.80%,夏普是 0.70。同一条权重上,没有投资的部分改按年化 2% 计息。日因子取 src/quant/data/cash_yield.py 里 2018 年那一行,也就是 (1.02)^(1/252)。权重已经被截在 1.0,没有借款,所以不用另记融资利息。

平均权重是 0.827,现金大约占 17.3%。CAGR 从 9.80% 升到 10.17%,夏普从 0.70 升到 0.73。波动仍打印为 11.47%。10.17% 低于买入持有的 13.86%。夏普 0.73 与买入持有的 0.73 在两位小数上相同;未四舍五入时大约是 0.728 对 0.727。高息周期里,这段现金利息是波动率目标收益的一部分。它没有把这条规则变成相对买入持有的超额。原图继续画现金收益为 0、上限 1.5 的那条净值。

现金收益 0(原表,上限 1.0) 现金按年化 2%
CAGR 9.80% 10.17%
夏普(r_f = 2%) 0.70 0.73
# goal2-check
"""M04 上限 1.0 的现金利息对照。不写图,不改原表的 9.80% 与 0.70。"""

import math

import pandas as pd

from quant.data.cash_yield import HYBRID_ESTIMATED_DAILY_FACTORS

RF = 0.02
TARGET = 0.12
# 2018 年的冻结日因子就是年化 2% 按 252 日换算的结果。
DAILY = HYBRID_ESTIMATED_DAILY_FACTORS[2018]


def performance(ret: pd.Series) -> tuple[str, str, str]:
    years = len(ret) / 252.0
    cagr = (1.0 + ret).prod() ** (1.0 / years) - 1.0
    std = float(ret.std(ddof=1))
    sharpe = (float(ret.mean()) - RF / 252.0) / std * math.sqrt(252.0)
    vol = std * math.sqrt(252.0)
    return f"{cagr * 100:.2f}%", f"{vol * 100:.2f}%", f"{sharpe:.2f}"


close = pd.read_csv(
    "knowledge/Labs/momentum_plus_lab/seed_data/spy.csv",
    parse_dates=["session"],
).set_index("session")["adj_close"].astype(float).sort_index()
ret = close.pct_change().dropna()
vol = ret.ewm(span=60).std(bias=False) * math.sqrt(252.0)
# 今日仓位只用昨日及更早的波动,并且不超过本轮杠杆上限 1。
weight = (TARGET / vol).clip(upper=1.0).shift(1)
held = ret.reindex(weight.dropna().index)
w = weight.reindex(held.index)
zero = (w * held).dropna()
# 未投资的权重赚日因子,已投资的权重赚股票。权重不超过 1,没有融资腿。
with_cash = (w * held + (1.0 - w) * (DAILY - 1.0)).dropna()
zero_cagr, zero_vol, zero_sharpe = performance(zero)
cash_cagr, cash_vol, cash_sharpe = performance(with_cash)
print("cap1_weight_mean", f"{float(w.reindex(zero.index).mean()):.3f}")
print("cap1_zero_cagr", zero_cagr)
print("cap1_zero_sharpe", zero_sharpe)
print("cap1_zero_vol", zero_vol)
print("cap1_cash_cagr", cash_cagr)
print("cap1_cash_sharpe", cash_sharpe)
print("cap1_cash_vol", cash_vol)
assert (zero_cagr, zero_sharpe) == ("9.80%", "0.70")
assert (cash_cagr, cash_sharpe, cash_vol) == ("10.17%", "0.73", "11.47%")
assert f"{float(w.reindex(zero.index).mean()):.3f}" == "0.827"

上面的 2% 是回测里没投资的那一段权重怎么计息。个人账户里,这段现金要有一个放得下的载体。券商对闲置现金的计息、货币基金,和美股超短债 ETF(SGOV、BIL 这一类)不是同一张账单。买卖短债 ETF 要付大约 1–2 bps 的买卖价差,卖出款按美股现货的 T+1 交收,不能把在途的钱再拿去买股票。非美居民提交的是 W-8BEN。ETF 分红可能被预提;分配里若有合格利息收入(QII),年底有退税规则。税率和表样以当年券商税表为准,这里不写一个税率。

点差会吃掉持有太短的利息。来回取区间上沿 2 bps,每 5 个交易日进出一次,一年按 252 个交易日大约是 252 / 5 = 50.4 次,摩擦 50.4 × 2 = 100.8 bps。这是点差的年化,不是 SGOV 或 BIL 的收益,也不是上面那张表的 10.17%。100.8 bps 已经超过第 6 节年化 2% 现金对照的一半。持有短于 5 天,次数更多,点差更先吃掉利息。费率以基金当时的说明书为准。

左:SPY 买入持有与目标波动 12%(上限 1.5)。右:μ=12%、σ=30%、r=0 时对数增长对杠杆的抛物线,顶点在 1.33 倍。

右图不是历史回测。μ = 12%、σ = 30%、r = 0 时 f⋆ = 0.12/0.09 = 1.333,顶点 g = 8%。两倍杠杆的几何近似是 2 × 12% − (0.60)² / 2 = 6%,低于不加权的 7.5%。

import math

import pandas as pd

# 教学脚本用 EWMA。生产估计在 quant.risk.volatility,窗口右端不含当日。
vol = daily_ret.ewm(span=60).std(bias=False) * math.sqrt(252)
# shift(1):今天的仓位只能看见昨天收盘后的波动。上限 1 对齐本轮杠杆政策。
weight = (0.12 / vol).clip(upper=1.0).shift(1)
# 现金收益记 0。w<1 时会低估有利息的年份;若把上限放到 1 以上,还要另记借款。
managed = (weight * daily_ret).dropna()

可运行的完整脚本是 figures/M04/plot_vol_target.py。图上的蓝线用上限 1.5,是为了看见截断;账户闸门用 1.0 那一行。

分年(上限 1.5,仍是日频夏普、r_f = 2%):

年 买入持有 CAGR / 波动 / 夏普 / 回撤 目标波动
2020 18.29% / 33.39% / 0.61 / −33.70% 4.44% / 13.43% / 0.24 / −16.89%
2022 −18.24% / 24.24% / −0.79 / −24.50% −12.09% / 12.80% / −1.10 / −15.63%

2020 年回撤大约减半,全年复利从 18.29% 降到 4.44%,因为减仓后波动仍高,反弹时仓位恢复得慢。2022 年亏损的幅度变小,夏普更差:收益的改善赶不上波动的下降。两条都是日历年里的日收益,最大回撤是年内路径,不是年末一点。

7. 固定风险与单位净值

单笔股数用的是这一封袖套愿意亏掉的钱,不是整个账户的净值。 袖套是策略独立分仓:总账户拆成几个信封,各策略先在自己的信封里算风险预算,再汇总。 本轮这一封的回撤线是单位净值 12%,写在风险政策里。入金不加高水位。 下面的股数公式用的是这笔愿意亏掉的 E × q,除以每股计划亏损,再向下取整。

单笔股数

n = ⌊(E × q) / (P_in − P_stop)⌋.

E 是权益,q 是允许这笔亏损占权益的比例,分母是每股计划亏损。账户 5 万美元、q = 1%、入场 100、止损 92:风险预算 500 美元,每股 8 美元,500/8 = 62.5,取整 62 股。账户 3 万美元、q = 0.75%、入场 250、止损 235:30000 × 0.0075 = 225,除以 15 等于 15 股。

跳空会让成交价差于止损价,实际亏损可以大于 E q。财报和隔夜是常态,不是例外。公式给出的是计划风险,不是成交保证。

回撤在本仓库用单位净值:UnitNav 把入金出金记成份额变动,高水位只跟着份额价格走。入金不会把回撤洗掉,出金也不会凭空造出回撤。触发之后要人明确恢复,程序不会在第二天自动开张。

docs/risk_policy.md 的示例表有账户回撤 15%、杠杆 1.0、单名 10%、单笔 5%。同一文件写明,本轮模拟的单策略熔断是单位净值回撤达到 12%,严于「回测最大回撤的 1.5 倍」。settings 里的风险参数不能比这份政策更松。教材里的 2.67 倍凯利不能写进配置。

8. 止损取决于收益的动态

Kaminski & Lo (2014, Journal of Financial Markets 18):收益若是随机游走,止损降低期望收益,换不来风险调整后的改善;收益若有动量或状态切换,止损可以参加这个动态。趋势策略的离场条件本身就是止损(跌破均线)。均值回复要另设「关系已经断了」的灾难止损和最长持有时间,否则价差可以在模型里永远回归、在账户里先穿仓。截面组合通常在组合层控制波动和回撤,而不是对每只股票用同一个百分比止损。

9. 回撤减仓的代价:同一条 10 个月均线

M02 的 SPY 月末均线,shift(1),现金收益 0,月频夏普用 r_f/12 和 √12。2014-11-30 至 2026-09-30,143 个月:CAGR 7.40%,夏普 0.51,月末最大回撤 −22.95%。

在这条账户上加一条规则:月初若单位净值回撤已经达到 10%,本月把信号仓位乘 0.5;回到高水位、回撤重新低于 10% 之后恢复满仓。减仓比例用的是本月收益发生前的净值。结果:CAGR 5.26%,夏普 0.38,月末最大回撤 −19.58%,143 个月里有 55 个月处于半仓。回撤只浅了约 3 个百分点,复利和夏普都下降。这条规则在这段样本里不值得保留。它防的是「规则已经坏了仍满仓」,不是日常的收益增强。月末回撤仍然看不见月中的低点。


🔴 深入层:踩踏、保证金和纪律

10. 同向杠杆怎样失去等待的权利

模型风险是代码和设定错了。结构变化是市场规则变了,旧的条件期望不再成立。外生冲击是你的模型里没有的政策、战争和疫情。这三件用测试、样本外和杠杆上限应对。

拥挤是第四件。许多账户持有相近的多空,价格下跌触发保证金,平仓把价格再打低一档。标的的基本面可以没有变化。被平掉的人在反弹时已经没有仓位。Khandani & Lo (2011, Journal of Financial Markets 14(1)) 写的就是 2007 年 8 月上旬这条链。本章不另引一个原文表格之外的累计跌幅。

流动性是同一条链的出口:要卖的时候买盘不在。限制单名占过去日成交额的比例,比在回测里假设收盘价能吸收任意数量更接近这件事。参与率的实现见 M03,用的是过去成交量。

操作风险(断线、重复下单)归 M15。本章只要求:停了以后不会自动恢复。

11. 保证金规则在 2026 年改了什么

SEC 于 2026-04-17 在 Federal Register 公布对 FINRA 提案 SR-FINRA-2025-017 的加速批准(Release 34-105226)。提案删除 pattern day trader、日内购买力和 25,000 美元最低权益,改为日内保证金。生效日是 FINRA 在 Regulatory Notice 里宣布的日期,文本写的是通知公布后 45 天;会员可以在通知公布后 18 个月内分阶段切换。2026 年 10 月不能默认每一家券商都已切完。多头股票的维持保证金长期要求仍在 Rule 4210 里,常见底线是 25%,以你的券商通知为准。规则放宽日内次数,不改变 M03 里小账户高频的费用结构。

港股孖展比例由券商按股票设定,波动上升时可以下调,下调本身就会造成追加保证金。杠杆 ETF 按日再平衡。指数算术漂移 10%、波动 20% 时,三倍工具的算术漂移按 30%、波动按 60% 算,对数漂移约 0.30 − 0.18 = 0.12。指数自身的对数漂移约 0.10 − 0.02 = 0.08,三倍是 0.24。0.12 对 0.24 的缺口是波动拖累的教学计算,不是某一只杠杆 ETF 的历史业绩。

12. 事先写下来的停机条件

Shefrin & Statman (1985) 和 Odean (1998) 记录的处置效应,是盈利仓位离场过早、亏损仓位留得过久。Barber & Odean (2001, QJE 116(1)) 记录男性账户交易更频繁。规则化的价值是回撤当天不再重新发明阈值。阈值已经在 docs/risk_policy.md:单日亏损示例 2% 停止新开仓,账户回撤示例 15% 暂停,本轮策略袖套是 12% 的单位净值回撤。改这些数要改政策文件,不是在盘中改策略代码。


真实案例

案例 1:2007 年 8 月上旬的多空平仓

Khandani & Lo (2011, JFM 14(1)) 的机制:某处的亏损带来保证金压力,高流动性的股票多空被卖掉;同类账户的持仓重叠,价格冲击变成它们的亏损;风控再平一次。基本面可以原封不动,价格在很短的时间内回弹。已经按保证金卖掉的账户吃不到这段回弹。个人账户的对应物是:杠杆和自动减仓让「等基本面」这个选项在最需要它的时候不可用。本轮把杠杆上限放在 1.0,就是在拒绝用等待权去换一个纸面上的凯利倍数。

案例 2:2024 年初的雪球、基差和微盘

2024-01-02 至 2024-02-05 前后,雪球产品敲入后,对冲盘卖出股指期货,基差走阔;DMA 一类产品以较低保证金维持数倍多头,微盘下跌触发平仓,平仓又压低微盘。中证 2000 在这段窗口下跌约三成,与 M00 同一句,点位可在中证指数公司核对。精确的保证金比例和年化贴水以交易所和券商记录为准,本章不把报道里的区间写成合同条款。传导和 2007 年是同一句话:杠杆、同向暴露、卖出时没有对手。A 股的涨跌停和港美股的隔夜跳空形状不同,失去仓位这一步相同。

案例 3:2020 年波动目标错过的是反弹

Cboe 的 VIX 在 2020-03-16 收在 80 以上。同一年,上表的 SPY 目标波动把最大回撤从 −33.70% 收到 −16.89%,全年 CAGR 从 18.29% 收到 4.44%,夏普从 0.61 收到 0.24。被削掉的主要是 3 月以后的恢复,因为波动率下来得比价格慢,仓位也恢复得慢。这是波动目标的典型账单:尾部变浅,V 型反弹里少赚一截。2022 年的账单不同:跌幅变小,夏普变差。两段都在第 6 节的表里,都可以复跑脚本核对。


方法论来源

概念 / 模型 核心文献或规范出处
凯利比例 Kelly (1956), Bell System Technical Journal 35(4);连续版本见 Thorp (2006)
分数凯利的路径 MacLean, Thorp & Ziemba 编 (2010), The Kelly Capital Growth Investment Criterion
处置效应 Shefrin & Statman (1985), JF 40(3);Odean (1998), JF 53(5)
过度交易 Barber & Odean (2000), JF 55(2)
波动目标 Moreira & Muir (2017), JF 72(4)。Harvey 等 (2018), JPM 45(1);Cederburg 等 (2020), JFE 138(1)
账户上限 杠杆上限 1.0;target_volatility_scale 的放大倍数默认不超过 1
波动估计 quant.risk.volatility 用窗口止于交易日之前的样本协方差,乘 252

💡 思考回顾与巩固

核心认知纠偏

误区 反例 用法
凯利杠杆是账户应该用的倍数 超额 6%、波动 15% 得到 2.67 倍;真实超额减半时期望超额增长为 0 凯利是上界参照。本轮闸门是杠杆 1.0
融资利率等于 r 时,加杠杆能提高夏普 夏普对这种杠杆是平的;g(f) 才有顶点 要提高的是对数增长时才看 f⋆,并先被政策截断
半凯利拿到全凯利 75% 的财富 75% 是超出 r 的对数增长率,波动是一半 用第 4 节的 8% 与 6% 核对
全凯利有 50% 的概率在明年回撤 50% 该概率是 r = 0 时最终摸到初始值一半,且假设几何布朗运动 肥尾和跳空另计;r > 0 时概率更低
波动目标会提高夏普 本种子上上限 1.5 的夏普 0.68,上限 1.0 是 0.70,买入持有 0.73 引用 Moreira & Muir 时同时给出这段样本
补上 2% 现金利息后就跑赢了买入持有 上限 1.0 的夏普升到 0.73,与买入持有相同到两位小数;CAGR 10.17% 仍低于 13.86% 原表 9.80% / 0.70 是现金为 0
回撤 10% 就半仓,能改善均线策略 同一条均线夏普从 0.51 降到 0.38,回撤从 −22.95% 到 −19.58% 这条规则在这段样本里不保留
止损总是风控 随机游走下止损降低期望 先写收益有没有动量或状态,再写止损

费曼自测

  1. 为什么夏普可以不随杠杆变,对数增长率却有一个最优杠杆?
  2. 波动目标在 2020 年的 SPY 上「成功」了吗?用哪四个数回答?
  3. 单位净值为什么要在入金时增加份额,而不是把高水位重置?
  4. 两倍凯利的每注 E[ln] 为什么是负的?这和「期望收益仍为正」矛盾吗?
自测要点 1. 借款利率等于 r 时,超额收益和波动按同一个 f 缩放,比值不变。对数漂移里有 −f²σ²/2,二次项把抛物线拉下来,顶点在 f⋆。 2. 没有,如果成功指夏普或复利。2020 年买入持有 CAGR 18.29%、夏普 0.61、回撤 −33.70%;目标波动是 4.44%、0.24、−16.89%。回撤变浅是真的,全年少赚的反弹也是真的。 3. 高水位若跟着入金上移,新钱会把旧的亏损比例洗掉,熔断可以永远不触发。份额增加后,价格仍是旧的单位净值,回撤还在。 4. f = 0.20 时 0.55 ln 1.2 + 0.45 ln 0.8 = −0.000138。算术期望 0.55 × 0.2 − 0.45 × 0.2 = 0.02 > 0。对数把亏损的比例惩罚得更重,所以算术期望为正时对数期望可以为负。一千注之后理论中位财富是 0.87。

四维习题

A. 概念题

  1. 写出 g(f),推出 f⋆,并说明 75% 乘在哪一段增长率上。
  2. 止损在哪类动态下会降低期望,在哪类动态下才可能改善风险调整收益?
  3. 2007 年 8 月上旬的平仓链和 2024 年初的微盘平仓,哪一步是相同的?
  4. 为什么 docs/risk_policy.md 里的 1.0 可以否决本章算出的 2.67?

B. 计算题

  1. 超额 6%,波动 15%。全凯利、半凯利各是多少?真实超额为 3% 时,按全凯利下注的超额对数增长是多少?
  2. 算术漂移 12%,波动 30%,r = 0。一倍和两倍杠杆的几何布朗运动对数漂移各是多少?顶点杠杆和顶点漂移是多少?
  3. 权益 3 万美元,单笔风险 0.75%,入场 250,止损 235。买入多少股?若开盘跳空到 220 才成交,这笔实际亏损占权益的比例是多少?
  4. p = 0.55、b = 1。计算 f = 0.05, 0.10, 0.20 的每注 E[ln],并给出一千注的 exp(1000g)。

C. 编程实战题

  1. 用 SPY 种子复现第 6 节的三行表:买入持有、上限 1.5、上限 1.0。夏普用 r_f = 2% 和 √252。
  2. 在 M02 的 10 个月均线上加入「月初回撤已达 10% 则半仓」,打印 CAGR、夏普和月末最大回撤,并与不加规则的 7.40% / 0.51 / −22.95% 比较。
  3. 用种子 7 模拟第 5 节的 1000×1000 路径,打印半凯利、全凯利、两倍凯利的样本中位终值和中位最大回撤。

D. 个人实战思考题

  1. 对照 docs/risk_policy.md,列出你账户上已经生效的四条数量限制。哪一条会切断第 5 题的全凯利?
  2. 若你的持仓和一只公开的动量 ETF 高度相关,你用哪些公开序列观察拥挤,而不是用「别人也喜欢这个因子」这句话?
  3. 2020 年那一行里,你愿意用多少 CAGR 换多深的回撤?写一个你能事先执行的交换,而不是事后看图。
完整参考答案与解析 **A1.** g(f) = r + f(μ − r) − f²σ²/2。g′(f) = (μ − r) − fσ² = 0 给出 f⋆ = (μ − r) / σ²。g(f⋆) − r = S²/2,g(f⋆ / 2) − r = (3/4)(S²/2)。75% 只乘在超出 r 的对数增长上。组合波动减半。 **A2.** Kaminski & Lo (2014):随机游走下止损降低期望收益。动量或状态切换下,止损可以跟上动态。趋势规则的均线离场属于后一种里的信号本身。均值回复需要单独的灾难止损,因为模型里的回归可以晚于账户的保证金。 **A3.** 相同的一步是:亏损触发减仓或保证金约束,减仓打在重叠的持仓上,价格在基本面未变时偏离,被迫离场的人赶不上随后的修复。2007 年是股票多空的流动性腿(Khandani & Lo, 2011)。2024 年初是雪球对冲、期指基差和微盘杠杆的组合,中证 2000 约下跌三成。保证金比例不要写成一个未核对的常数。 **A4.** 2.67 是在超额和波动都被当成已知常数、借款利率等于 r、没有费用和跳空时,对数增长的无约束驻点。政策文件把杠杆钉在 1.0,是因为参数会错、肥尾存在、并且本轮模拟不加杠杆。闸门读配置,不读教材里的驻点。 **B5.** 0.06/0.0225 = 8/3 ≈ 2.667,半凯利 4/3 ≈ 1.333。真实超额 3% 时,(8/3) × 0.03 − (8/3)² × 0.0225/2 = 0.08 − 0.08 = 0。 **B6.** 一倍:0.12 − 0.09/2 = 0.075。两倍:0.24 − 0.36/2 = 0.06。顶点 f⋆ = 0.12/0.09 = 1.333,g⋆ = 0.12² / (2 × 0.09) = 0.08。右图的虚线在这个杠杆上。 **B7.** 30000 × 0.0075 = 225,250 − 235 = 15,225/15 = 15 股。跳空到 220:每股亏 30,共 450 美元,占权益 450/30000 = 1.5%,是计划 0.75% 的两倍。股数公式没有承诺成交价。 **B8.** f⋆ = 0.10。g(0.05) = 0.003753,g(0.10) = 0.005008,g(0.20) = −0.000138。exp(1000g) 分别是 42.63、149.7、0.87。半凯利相对全凯利的比值是 0.749。 **C9–C11.** 与 `figures/M04/plot_vol_target.py` 同一契约,脚本已运行。日频窗口 2014-01-07 至 2026-09-28,3200 天。买入持有 13.86% / 17.13% / 0.73 / −33.70%。上限 1.5:10.11% / 12.28% / 0.68 / −16.89%。上限 1.0:9.80% / 11.47% / 0.70 / −16.43%。均线半仓规则:CAGR 5.26%,夏普 0.38,月末回撤 −19.58%,半仓 55 个月。硬币模拟的样本中位数见第 5 节的表;增长排序以 E[ln] 为准,不以某一次样本中位数为准。
import math
from pathlib import Path

import pandas as pd

RF = 0.02
px = pd.read_csv(
    Path("knowledge/Labs/momentum_plus_lab/seed_data/spy.csv"),
    parse_dates=["session"],
).set_index("session")["adj_close"].astype(float).sort_index()
daily = px.pct_change().dropna()
# EWMA 含当天。shift(1) 后,收益日 t 的仓位只用 t 之前的波动。
vol = daily.ewm(span=60).std(bias=False) * math.sqrt(252.0)


def run(cap: float) -> pd.Series:
    weight = (0.12 / vol).clip(upper=cap).shift(1)
    return (weight * daily).dropna()


def sharpe(ret: pd.Series) -> float:
    excess = float(ret.mean()) - RF / 252.0
    return excess / float(ret.std(ddof=1)) * math.sqrt(252.0)
**D12.** 文件里已经写明的四条可以是:杠杆上限 1.0、单名不超过净值 10%、单笔不超过净值 5%、本轮策略袖套的单位净值回撤 12%。切断 2.67 倍的是杠杆上限 1.0。若你的 `settings` 比这份政策更松,发送闸门应拒绝,而不是教材让路。 **D13.** 用公开的动量组合或 ETF 的持仓重叠、换手和相对成交额,以及你的收益相对这个 ETF 的滚动相关。相关上升同时成交额下降,比「这个因子最近很热」更接近拥挤。相关不是保证金通知,账户里的杠杆上限仍然先起作用。 **D14.** 第 6 节给出的可执行交换是:接受 2020 年这种从 18.29% 降到 4.44% 的全年复利,换回撤从 −33.70% 到 −16.89%。若这个交换你不愿意事先签,就不要把目标波动写成收益增强,只把它写成尾部约束,并把上限放在政策允许的 1.0。

📌 章节知识总结

一句话核心洞察

  1. f⋆ = (μ − r) / σ² 最大化的是对数增长。借款利率等于 r 时夏普不随杠杆变。估计的 μ 减半,全凯利的超额对数增长可以变成 0。
  2. 半凯利保留约 75% 的超额对数增长,波动减半。75% 不乘在含现金利率的总增长率上。
  3. SPY 种子上,目标波动 12% 把最大回撤从 −33.70% 收到约 −17%,夏普从 0.73 降到 0.68(上限 1.5)或 0.70(上限 1.0)。现金按年化 2% 计息后,上限 1.0 的 CAGR 是 10.17%,夏普是 0.73,与买入持有的夏普在两位小数上相同。
  4. 回撤用单位净值。入金不加高水位。触发后要人恢复。本轮杠杆上限 1.0,策略袖套回撤 12%。
  5. 10% 回撤就半仓,在这条均线上把夏普从 0.51 降到 0.38。规则可以增加痛苦的路径长度。

公式与阈值

对象 表达式或数值 前提
回本涨幅 1 / (1 − d) − 1 单段亏损,中间没有现金流
对数漂移 g = μ − σ²/2 几何布朗运动;日频简单收益另有 μ²/2
连续凯利 f⋆ = (μ − r) / σ² 借款利率 = r,参数已知
最优超额增长 S²/2 同上
半凯利超额增长 全凯利的 ¾ 同上
离散凯利 f⋆ = p − (1 − p) / b 独立重复,赔率固定
波动目标 wₜ = min(σ⋆ / ˆσₜ₋₁, w_max) 波动用 t − 1 及更早
上限 1.0 的现金利息 CAGR 10.17%,夏普 0.73 同一估计;现金年化 2%。原表 9.80% / 0.70 仍是现金为 0
本轮杠杆 1.0 docs/risk_policy.md
本轮袖套回撤 单位净值 12% 严于「回测最大回撤 × 1.5」
单笔股数 ⌊E q / (P_in − P_stop)⌋ 不含跳空

跨模块

结论 交给 工程位置
杠杆上限和回撤熔断 下单前的闸门 src/quant/risk/breakers.py 的单位净值;docs/risk_policy.md
截至昨日的协方差 风险预算,不是 EWMA 教学图 src/quant/risk/volatility.py,窗口不含当日,乘 252
夏普的日频定义 和第 6 节的表同一口径 src/quant/backtest/metrics.py
均线的时点 回撤规则不能把当月收益算进当月减仓 M02 的 shift(1)
参与率和费用 止损距离不是实际亏损上限 M03

学习指引

概念卡片:凯利公式

  • 精读:陈第 6 章的杠杆推导;7.8 只取「高杠杆和高 beta 不是同一件事」。黑箱第 10 章的风险名单,用本章的四个案例核对机制,不摘录原书表格。
  • 对照:Kelly (1956);Thorp (2006);Moreira & Muir (2017, JF);Cederburg 等 (2020, JFE);Kaminski & Lo (2014);Khandani & Lo (2011)。
  • 项目:先读 docs/risk_policy.md 的杠杆 1.0 和 12% 袖套,再决定教学脚本里的 w_max。不要为了贴近 f⋆ 去放宽政策。
  • 下一步:L1 的策略、回测和仓位三条线到此齐。M05 进入收益为什么有截面差异。

自检清单

  • 能从 g(f) 推出 f⋆,并手算超额 8%、波动 20% 的全凯利与半凯利
  • 能说明 75% 乘的是超额对数增长,以及 r = 0 时「摸到一半」的概率假设
  • 能复述 SPY 目标波动的三行表,并说明它没有提高夏普
  • 能解释单位净值为什么不被入金洗掉
  • 能指出本轮杠杆 1.0 和袖套 12% 写在哪份文件里