一句话摘要
从零构建量化投资组合的方法
如何从零构建一个量化投资组合(2026 版) 2026 年 7 月 14 日 · 16 分钟阅读 · 查看原文 ↗ 量化
不是选股指南。而是资本配置背后真正的数学——从协方差估计,到你何时彻底砍掉一个策略。
问十个人如何构建投资组合,九个人会告诉你要分散。
他们几乎没人能给你展示那个证明它有效的方程,或者那个能精确告诉你、在你组合的具体对象下它能帮多少的方程。"别把所有鸡蛋放进一个篮子"是建议。它不是工程。一个建立在建议而不是工程之上的投资组合,往往恰恰在它本该保护你的那一刻崩掉。
收藏这篇!
我是 Ruuj,一名后端开发者、研究者,正在做量化系统。私信开放,欢迎有深度的讨论和合作。
这篇文章是工程版本,从头到尾。不是投资组合理论的综述。而是我今天从零构建一个投资组合时会用的、按顺序排列的实际决策与公式序列。从那个证明分散有效的方程开始,经过那个"教科书协方差矩阵如果直接用就会悄悄毁掉你的配置"的具体原因,经过那个能扛过这个问题的配置方法,最后以那条精确的操作规则收尾——什么时候彻底砍掉一个策略,什么时候只是削减一个仓位。
读完这篇文章,你会理解:把东西组合起来降低风险背后真正的数学,以及如何精确衡量那个收益;为什么样本协方差矩阵直接喂给任何优化器是危险的,以及修复方法是什么;为什么经典均值-方差优化倾向于产生脆弱、不稳定的组合,以及严肃的配置者改用什么;如何把你自己真实的市场观点融入配置,而不让一个不稳的预测接管它;以及再平衡和在一个策略让你付出整个回撤之前关停它的确切规则。
注:本文刻意写得彻底。每一章都建立在前一章之上。按顺序读。
第 1 章:分散的真实数学
从公式开始,因为本文其余一切都依赖精确理解它。
的对比
对于一个两资产组合,权重为 w₁ 和 w₂,各自波动率为 σ₁ 和 σ₂,它们之间的相关性为 ρ,组合的方差是:
σ_p² = w₁²σ₁² + w₂²σ₂² + 2w₁w₂σ₁σ₂ρ
仔细看第三项。它是相关性进入公式的唯一地方,而"分散"实际上所指的全部工作,都是它在做。
如果 ρ = 1,两个资产完美同步移动,公式退化为 σ_p = w₁σ₁ + w₂σ₂。组合波动率只是各自波动率的加权平均。把它们组合起来没给你任何东西。你只有一个风险,通过两个代码表达出来。
如果 ρ = 0,两个资产真正不相关,那个第三项完全消失。组合方差变成 w₁²σ₁² + w₂²σ₂²,严格小于加权平均所暗示的值。这是你听过的每一条分散建议底下的数学事实:把真正不相关的东西组合起来,会把总风险降到任何单个资产单独承担的水平之下,纯粹是代数的结果,不需要改变预期回报。
如果 ρ 为负,收益更大。那个第三项变成减法,组合方差可以降到任何一个单独资产的方差之下。
对 N 个资产,这用完整的协方差矩阵 Σ 直接推广:
σ_p² = w'Σw
分子是单个资产波动率的加权平均:如果一切都完美相关,你的总风险会是多少。分母是你实际的组合波动率,由完整协方差矩阵算出。一个集中在单一资产的组合,分散比率恰好是 1,毫无收益。任何大于 1 的值,都意味着相关性结构在真正为你干活。
这是我在决定一个新策略或资产是否属于组合时,实际会追踪的数字。加入某样能提高分散比率的东西,是在增加真正的分散。加入某样让它大致持平的东西,即便它单独看很诱人,也没有分散任何东西。它只是对你已有的一个风险的更多敞口。
而那个坑,就是定义本文其余部分的那个坑:这些公式里的每一个量都必须从历史数据估计。那个估计远不如公式的优雅所暗示的那样可靠。

第 2 章:那个搞坏一切下游的协方差矩阵问题
本文的每一个方法都依赖一个输入:对 Σ,即协方差矩阵的一个准确估计。把这个搞错,第 1 部分的优雅数学就会主动跟你作对。
这里有一个几乎没人会在伸手去拿优化器之前处理的问题。准确估计一个协方差矩阵需要大量数据,相对于你在估计多少个东西而言,而实际上你几乎永远没有足够的数据。
对 N 个资产或策略,Σ 包含 N(N+1)/2 个都需要从历史估计的唯一数字,而不是 N 个数字。十个收益来源意味着 55 个独立的协方差项,都从一个有限、有噪声的样本里估计。二十个意味着 210 个。当这个数字相对于你可用的历史增长时,估计误差会严重复合。
那个朴素方法——直接从历史收益计算样本协方差矩阵——恰恰在这个设置下表现很糟。它系统性地高估了在你特定历史窗口里恰好表现最好的那种组合的可靠性,并低估了表现最差的那些的风险。把那个有噪声的矩阵喂进任何优化器,它就会把估计噪声当成真实信号,产生极端的、不稳定的权重,它们会随输入数据的微小变化而剧烈摆动。这正是为什么如果 Σ 本身不可靠,第 1 部分的分散比率会严重误导你。你可以在一个根本没有真实分散收益的组合上算出一个 1.8 的比率,纯粹因为你的协方差估计是伪装成结构的噪声。
收缩估计是标准修复,而且已经二十年了。
Ledoit 和 Wolf 在 2003 年发表了原始解法。不是完全信任有噪声的样本协方差矩阵,而是把它朝一个更简单、更稳定的结构收缩:
Σ_shrunk = δ × F + (1 - δ) × S
其中 S 是样本协方差矩阵,F 是一个稳定的结构化目标,比如常数相关矩阵,δ 是收缩强度,由数学推导而不是猜出来。
跑完这个之后要检查的东西是矩阵的条件数,np.linalg.cond(cov_matrix)。高条件数意味着矩阵接近奇异:输入数据的微小变化会在矩阵逆里产生巨大的、不稳定的变化,而矩阵逆正是第 3 章配置方法需要执行的那个运算。收缩显著改善了这种条件。这不是一个表面调整。它是"一个产生稳定权重的优化器"和"一个在喂给它的那个确切窗口上看起来很亮眼、条件一变就散架的优化器"之间的区别。2025 年以前的研究继续用非线性和二次收缩变体进一步细化它,但核心的线性 Ledoit-Wolf 估计器仍然是久经检验的实用默认值。
我永远不会在一个原始样本协方差矩阵上计算分散比率,也永远不会在它上面运行任何配置方法。先收缩,永远如此。
下
第 3 章:选择配置方法
有了一个恰当估计的协方差矩阵,下一个决策是如何把它变成实际的组合权重。有三个真实的候选值得精确理解。
均值-方差优化是 1952 年原始的 Markowitz 框架,仍然是学术起点,而且在朴素形式下仍然脆弱。给定预期回报和一个协方差矩阵,它找到在给定风险水平下最大化回报的权重。更深的问题不再是协方差矩阵了,第 2 部分已经解决了那个。问题是均值-方差优化还需要对每个收益来源的预期回报估计,而那些估计比协方差估计噪声大得多。预测上的一个小差异,8% 的预期回报而不是 7.5%,就能把最优配置从组合的 5% 摆动到 60%。这就是为什么朴素的均值-方差组合几乎从不会在没有大量额外约束的情况下运行,只为让输出可用。
风险平价几乎完全把预期回报从方程里移除。它不在给定风险水平下最大化回报,而是问一个更稳健的问题:什么配置能让每个收益来源贡献总组合风险的相等份额。这是 Bridgewater 从 1996 年起构建 All Weather 基金所依据的框架,而且它今天仍然是最广泛使用的机构方法之一,Bridgewater 和 AQR 现在都在它的变体上跑真实资本。资产 i 的总风险贡献是:
TRC_i = w_i × (Σw)_i
目标找到每个贡献都相等的权重,TRC_i = TRC_j 对所有 i, j 成立。
层级风险平价(HRP),由 Marcos Lopez de Prado 在 2016 年引入,修复了两个先前方法共享的一个结构弱点:它们都需要求协方差矩阵的逆,而矩阵求逆正是那个最暴力地放大小估计误差的运算。HRP 完全绕开了这一点。它基于你的收益来源实际行为的相似程度,把它们聚成一个层级树——用聚类而不是矩阵求逆——然后沿着那棵树递归地向下分配风险。因为它从不求 Σ 的逆,HRP 在结构上对第 2 章所说的那种估计噪声更稳健。2024 年发表的正式理论工作直接确认了这一点,证明 HRP 可以证明地解决 Markowitz 不稳定性问题,而且这个方法持续在 2025 年前发表的研究中被积极验证。
那两个辅助函数,get_quasi_diag 用于从聚类树提取叶序,recursive_bisection 用于自顶向下拆分风险预算,都是标准的,在大多数组合库(如 riskfolio-lib 或 PyPortfolioOpt)里都有,所以我会从那里拉取它们,而不是手工重新实现树逻辑。
我实际会做的调用:HRP 作为基础配置,不是均值-方差,也不是普通风险平价。比较这些方法的实证结果确实喜忧参半,一些研究发现 HRP 在样本外胜过简单等权,另一些发现等权在任何方法下都难得出奇地难以被击败。研究里一致的是,HRP 在结构上对第 2 章确立的估计噪声问题是受保护的,而均值-方差和标准风险平价在结构上暴露于它。我宁愿跑那个受保护的方法,即便在某个特定历史窗口上,回测偶尔偏爱那个脆弱的方法。
第 4 部分:把你的观点融进去而不搞坏组合
一个纯风险基础的配置,刻意忽略你对未来回报的真实看法。当你的看法有噪声时,这是对的,但当你有一个真正校准良好的、值得移动配置的观点时,它就是一个真实的局限。

一个策略内的亏损期是正常的,每一个真正的收益生成过程都把预期回撤内置进了它的正常运作里。那单独并不证明哪里出了问题。真正发出问题信号的是不同的东西:策略自己对自身模型信心的内部度量持续退化,独立于它当前在赢还是在输。一个预测误差在增长、或底层统计关系在减弱的策略,即便名义上仍有利可图,也已经坏了。一个正在经历艰难月份、而内部诊断保持健康的策略,根本就没坏。
这强制了一种纪律:把"这个策略当前在亏钱吗"与"这个策略起作用的原因是否已经不再成立"分开。大多数时候,这是两个有不同答案的不同问题。把它们混为一谈,就是组合要么恐慌地抛出一个暂时倒霉、但根本上健全的策略,要么骑着一个真正坏掉的策略一路到底,因为亏损还没追上底层的恶化。
总结
这是完整的架构,从地基向上组装。
从分散为什么有效的真实数学开始——组合方差公式,以及那个把"这分散了吗"从一种感觉变成一个你可以直接计算和优化的数字的分散比率。用收缩来估计那个公式所依赖的协方差矩阵,因为原始样本估计太吵,无法信任任何建立在它之上的方法,包括分散比率本身。用层级风险平价作为基础配置,因为它对恰好损害均值-方差优化和标准风险平价的那种估计噪声,在结构上是受保护的。用 Black-Litterman 混合,在顶层叠加上真实的、校准过的观点,这样一个低信心的直觉永远不会像一个有充分证据的观点那样移动组合。以阈值基础而不是固定日历再平衡。并且始终明确地把"削减一个亏损仓位"的决策与"砍掉整个收益来源"的决策分开。
这里没有任何单个部件是稀奇的。组合方差公式已经七十多岁了,从不需要修订。Ledoit-Wolf 收缩已经二十多年了,仍然是实用默认值。Black-Litterman 已经三十多年了,2026 年仍然跑在高盛的配置流程里。层级风险平价已经十年了,并且持续在今年的研究里被积极验证。大多数组合内容搞错的不是任何单个数学部件,而是跳过解决"为什么那个优化器的输入从一开始就不可靠",直接冲到优化器。
这是我实际会运行的架构。每一层之所以存在,是因为它下面那层有一个具体的、有记录的弱点,而下一层正是为处理那个弱点而构建的。
这里有一个值得坐着想想的问题。
在这五层里——分散数学、协方差收缩、HRP 配置、Black-Litterman 观点混合、以及操作性再平衡规则——哪一层你会放心拿自己的资本去信任,而你会构建什么不同的东西来补偿它?

Prompts
from scipy.cluster.hierarchy import linkage
from scipy.spatial.distance import squareform
def hrp_weights(returns_df):
corr = returns_df.corr()
cov = returns_df.cov()
dist = np.sqrt(0.5 * (1 - corr))
link = linkage(squareform(dist.values, checks=False), method='single')
# order assets by cluster structure, then recursively split
# risk budget top-down between each pair of sub-clusters
order = get_quasi_diag(link)
weights = recursive_bisection(cov, corr.index[order].tolist())
return weights.sort_index()
def strategy_status(confidence_history, lookback=60,
cut_below=0.30, trend_below=-0.005):
recent = confidence_history[-lookback:]
avg = np.mean(recent)
trend = np.polyfit(range(len(recent)), recent, 1)[0]
if avg < cut_below:
return 'CUT'
elif trend < trend_below:
return 'REDUCE'
return 'NORMAL'
def bl_posterior(cov, pi, P, Q, omega, tau=0.05):
tau_cov = tau * cov
A = np.linalg.inv(np.linalg.inv(tau_cov) + P.T @ np.linalg.inv(omega) @ P)
b = np.linalg.inv(tau_cov) @ pi + P.T @ np.linalg.inv(omega) @ Q
return A @ b
def rebalance_needed(current_w, target_w, threshold=0.05):
drift = (current_w - target_w).abs()
return drift[drift > threshold]
from sklearn.covariance import LedoitWolf
def shrunk_covariance(returns_df):
lw = LedoitWolf().fit(returns_df.values)
return pd.DataFrame(lw.covariance_,
index=returns_df.columns,
columns=returns_df.columns), lw.shrinkage_
def diversification_ratio(weights, cov_matrix):
w = np.array(weights)
vols = np.sqrt(np.diag(cov_matrix))
port_vol = np.sqrt(w @ cov_matrix @ w)
return (w @ vols) / port_vol
标签:# X # 量化 # 指南 相关文章 目前 Polymarket 上最赚钱的交易机器人 模型检测到 Up 上的优势 -> 机器人开始买入 Up -> 标的资产反转 -> 公平概率向 Down 偏移 -> 机器人开始买入 Down -> 原来的 Up 仍然是总量的一部分…… 量化
原文参考:https://maxed.wiki/posts/how-to-build-a-quant-portfolio-from-scratch-2026-edition/ (Maxed.wiki,本页为站内中文整理)