M04 资金管理与风险控制¶
层级:L1 策略与回测 | 优先级:★★★ | 预计学时:12 小时 对应原书:陈 第 6 章、7.8;黑箱 第 10 章 前置知识:M00 的杠杆与融资利差;M01 的夏普与肥尾;M03 的
shift(1)与费用。 读书笔记:陈第 6 章与 7.8 · 黑箱第 10 章 状态:reviewed 数据截至:2026-09|最近复核:2026-10-28
学习目标¶
- 从几何布朗运动的对数漂移推出连续凯利杠杆 f⋆ = (μ − r) / σ²,并用一注赔率 1:1 的赌局手算半凯利的对数增长。
- 把波动率目标写成「用昨日波动决定今日仓位」。在本仓库的 SPY 种子上,它缩小了回撤,没有提高夏普。
- 区分止损有用的动态(动量、状态切换)和只会砍掉期望的动态(随机游走)。
- 用单位净值衡量回撤,使入金出金不制造、也不掩盖回撤。本轮账户的杠杆上限是 1.0。
- 把 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 天,次数更多,点差更先吃掉利息。费率以基金当时的说明书为准。
右图不是历史回测。μ = 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% | 这条规则在这段样本里不保留 |
| 止损总是风控 | 随机游走下止损降低期望 | 先写收益有没有动量或状态,再写止损 |
费曼自测¶
- 为什么夏普可以不随杠杆变,对数增长率却有一个最优杠杆?
- 波动目标在 2020 年的 SPY 上「成功」了吗?用哪四个数回答?
- 单位净值为什么要在入金时增加份额,而不是把高水位重置?
- 两倍凯利的每注 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. 概念题¶
- 写出 g(f),推出 f⋆,并说明 75% 乘在哪一段增长率上。
- 止损在哪类动态下会降低期望,在哪类动态下才可能改善风险调整收益?
- 2007 年 8 月上旬的平仓链和 2024 年初的微盘平仓,哪一步是相同的?
- 为什么
docs/risk_policy.md里的 1.0 可以否决本章算出的 2.67?
B. 计算题¶
- 超额 6%,波动 15%。全凯利、半凯利各是多少?真实超额为 3% 时,按全凯利下注的超额对数增长是多少?
- 算术漂移 12%,波动 30%,r = 0。一倍和两倍杠杆的几何布朗运动对数漂移各是多少?顶点杠杆和顶点漂移是多少?
- 权益 3 万美元,单笔风险 0.75%,入场 250,止损 235。买入多少股?若开盘跳空到 220 才成交,这笔实际亏损占权益的比例是多少?
- p = 0.55、b = 1。计算 f = 0.05, 0.10, 0.20 的每注 E[ln],并给出一千注的 exp(1000g)。
C. 编程实战题¶
- 用 SPY 种子复现第 6 节的三行表:买入持有、上限 1.5、上限 1.0。夏普用
r_f = 2%和 √252。 - 在 M02 的 10 个月均线上加入「月初回撤已达 10% 则半仓」,打印 CAGR、夏普和月末最大回撤,并与不加规则的 7.40% / 0.51 / −22.95% 比较。
- 用种子 7 模拟第 5 节的 1000×1000 路径,打印半凯利、全凯利、两倍凯利的样本中位终值和中位最大回撤。
D. 个人实战思考题¶
- 对照
docs/risk_policy.md,列出你账户上已经生效的四条数量限制。哪一条会切断第 5 题的全凯利? - 若你的持仓和一只公开的动量 ETF 高度相关,你用哪些公开序列观察拥挤,而不是用「别人也喜欢这个因子」这句话?
- 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)
📌 章节知识总结¶
一句话核心洞察¶
- f⋆ = (μ − r) / σ² 最大化的是对数增长。借款利率等于 r 时夏普不随杠杆变。估计的 μ 减半,全凯利的超额对数增长可以变成 0。
- 半凯利保留约 75% 的超额对数增长,波动减半。75% 不乘在含现金利率的总增长率上。
- SPY 种子上,目标波动 12% 把最大回撤从 −33.70% 收到约 −17%,夏普从 0.73 降到 0.68(上限 1.5)或 0.70(上限 1.0)。现金按年化 2% 计息后,上限 1.0 的 CAGR 是 10.17%,夏普是 0.73,与买入持有的夏普在两位小数上相同。
- 回撤用单位净值。入金不加高水位。触发后要人恢复。本轮杠杆上限 1.0,策略袖套回撤 12%。
- 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% 写在哪份文件里
