ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

资产配置模型实战:从马科维茨到风险平价,Python实现与避坑指南

资产配置模型实战:从马科维茨到风险平价,Python实现与避坑指南 简介这份资源围绕均值方差资产配置模型展开面向金融工程、量化投资方向的学习者与研究者帮助其理解现代投资组合理论中风险与收益的权衡方法。压缩包共2个文件包含1个m脚本与1个xlsx数据表整体约36KB其中脚本用于实现资产权重的优化计算表格则记录历史收益率、风险参数及优化后的配置结果便于对照验证。已有325人学习下载说明该模型在投资决策场景中具有较高的参考价值。读者可借助代码复现均值、方差与协方差的估算流程掌握在给定收益下最小化风险或给定风险下最大化收益的求解思路并直接查看优化后的资产配置权重作为资金分配参考。资源同时提示模型依赖历史数据与有效市场假设适合作为定量分析的入门实践素材结合定性判断使用。1. 资产配置模型到底在解决什么问题从“拍脑袋买”到“按规则配”很多人第一次接触资产配置模型是因为账户里同时躺着货币基金、债券基金、沪深300、标普500、黄金ETF却完全不知道各自该占多少比例。涨了后悔买少跌了后悔买多最后变成凭感觉调仓。资产配置模型要解决的就是把“买什么、买多少、什么时候调”这三件事从主观判断变成可计算、可复现的规则。它不预测明天哪只涨而是用资产之间的低相关性让组合在同等收益目标下波动更小。适合谁适合有5万以上可投资金、能接受季度级调仓频率、愿意花一个周末把参数跑明白的普通投资者和小团队。核心不是找到圣杯而是让每一笔买入都有依据。2. 资产配置模型的三个理论支点为什么不是简单分散2.1 马科维茨均值-方差模型有效前沿怎么算出来资产配置模型的理论起点是马科维茨1952年提出的均值-方差框架。它把每个资产的预期收益和风险标准差以及资产之间的协方差放进一个二次规划问题在给定预期收益下最小化组合方差或在给定方差下最大化收益。解出来的一串组合点连成有效前沿。实操中你不需要手推矩阵但必须理解两个输入决定输出预期收益向量和协方差矩阵。预期收益哪怕只差1%最优权重可能从30%跳到60%这就是模型最脆弱的地方。常见做法是用历史数据估计这两个输入。我一般会取至少5年周频数据因为日频噪声太大月频样本又太少。下面是一个用Python计算有效前沿最小必要代码import numpy as np import pandas as pd from scipy.optimize import minimize # 假设 returns 是 DataFrame每列一个资产的周收益率 returns pd.read_csv(weekly_returns.csv, index_col0, parse_datesTrue) mu returns.mean() * 52 # 年化预期收益 cov returns.cov() * 52 # 年化协方差矩阵 n len(mu) def portfolio_var(w, cov): return w cov w def neg_sharpe(w, mu, cov, rf0.02): ret w mu vol np.sqrt(w cov w) return -(ret - rf) / vol cons ({type: eq, fun: lambda w: np.sum(w) - 1}) bounds tuple((0, 1) for _ in range(n)) w0 np.ones(n) / n res minimize(neg_sharpe, w0, args(mu, cov), boundsbounds, constraintscons) print(最优权重:, dict(zip(returns.columns, np.round(res.x, 4))))逻辑说明mu和cov是模型仅有的两个输入年化系数52对应周频。neg_sharpe是目标函数求最大夏普等价于求负夏普最小。bounds限制不做空、不加杠杆这是普通账户的硬约束。参数怎么改如果只允许场外基金把单资产上限设为0.4避免过度集中如果加入黄金注意黄金长期收益低但协方差小模型会自动给它10%到15%的权重。失败时先看res.success是否为True再看权重是否全挤在一个资产上那通常是预期收益估计偏差过大。2.2 风险平价为什么桥水全天候不依赖收益预测均值-方差模型对预期收益太敏感于是风险平价思路出现不预测收益只让每个资产对组合总风险的贡献相等。桥水全天候是典型应用它把资产按经济增长和通胀两个维度分成四象限每个象限风险预算25%。风险平价的数学形式是求解权重使得各资产风险贡献RC_i相等RC_i w_i × (Σw)_i / σ_p实操中债券因为波动低会被分配到很大权重股票权重反而小。这解释了为什么全天候看起来“债券比股票多”但风险来源是均衡的。下面用迭代法算风险平价权重def risk_parity_weights(cov, tol1e-8, max_iter5000): n cov.shape[0] w np.ones(n) / n for _ in range(max_iter): port_var w cov w mrc cov w # 边际风险贡献 rc w * mrc / np.sqrt(port_var) # 各资产风险贡献 target np.sqrt(port_var) / n w_new w * (target / rc) ** 0.5 w_new w_new / w_new.sum() if np.max(np.abs(w_new - w)) tol: break w w_new return w w_rp risk_parity_weights(cov.values) print(风险平价权重:, dict(zip(returns.columns, np.round(w_rp, 4))))逻辑说明mrc是边际风险贡献rc是各资产实际风险贡献。迭代公式让风险贡献高的资产权重下降低的上升指数0.5是阻尼系数防止震荡。参数tol控制收敛精度一般1e-8足够max_iter给5000次正常几百次就收敛。这个方法的坑是协方差矩阵估计误差会被放大所以常见做法是加收缩估计或直接用波动率倒数加权做近似。2.3 Black-Litterman把主观观点和模型结合BL模型先用市场均衡反推隐含收益再把你的主观观点作为贝叶斯先验更新最后重新优化。它解决了“模型给的建议我不同意”的尴尬。实操中你只需要设定观点矩阵P、观点收益Q和信心水平Ω。比如你认为未来一年A股跑赢美股3%就写一行观点。BL的完整公式涉及矩阵求逆但用Python的pypfopt库几行就能跑。这里不展开代码因为对多数个人投资者风险平价加再平衡已经够用BL更适合有明确观点且能量化信心的机构场景。3. 从零搭建一个可复现的资产配置模型数据、参数、回测3.1 数据准备取哪些资产、多长历史、怎么对齐资产池决定模型上限。我一般选五类现金货币基金、中国利率债、中国信用债、沪深300、标普500再加黄金ETF。这六类相关性低数据容易获取。历史长度取2015年至今覆盖一轮牛熊和一次快速下跌。数据频率用周频每周五收盘价。对齐时用inner join避免某资产缺失时用前值填充造成虚假低波动。import pandas as pd import yfinance as yf tickers [510300.SS, 513500.SS, 511010.SS, 511260.SS, 518880.SS, 000012.SS] # 注意场内代码仅作示例实际用你账户能买到的标的 data yf.download(tickers, start2015-01-01, end2024-12-31, interval1wk)[Adj Close] data data.dropna(howany) # 严格对齐不填充 returns data.pct_change().dropna() print(returns.corr().round(2))逻辑说明dropna(howany)保证每个时间点所有资产都有价格牺牲样本量换真实性。pct_change算周收益。参数起始时间至少覆盖2018年和2022年两轮下跌否则协方差矩阵低估风险。如果某资产上市晚要么缩短整体区间要么剔除该资产不要用模拟数据补。3.2 参数设定预期收益、协方差、再平衡阈值预期收益我不用历史均值直接外推而是用“历史均值×0.5 长期假设×0.5”做收缩。长期假设股票6%债券3%黄金2%现金1.5%。协方差用Ledoit-Wolf收缩估计Python的sklearn.covariance里有现成实现。再平衡阈值设5%绝对偏离或每季度检查一次哪个先到用哪个。阈值太小交易成本吃掉收益太大则风险漂移。from sklearn.covariance import LedoitWolf lw LedoitWolf().fit(returns) cov_shrunk lw.covariance_ * 52 # 年化 mu_shrunk returns.mean() * 52 * 0.5 np.array([0.06,0.06,0.03,0.03,0.02,0.015]) * 0.5 print(收缩后协方差矩阵对角线:, np.round(np.diag(cov_shrunk), 4))逻辑说明LedoitWolf自动估计收缩强度比手动调参稳。mu_shrunk把历史均值和长期假设各取一半降低极端值影响。参数长期假设可根据自己判断微调但不要超过±2%否则又变成主观择时。3.3 回测框架用滚动窗口模拟真实决策回测不能全样本优化一次就完事那是未来函数。正确做法是滚动窗口用前3年数据算权重持有下一季度再滚动。下面是一个简化回测循环window 156 # 3年周频 rebal_freq 13 # 每季度调仓 portfolio_ret [] for i in range(window, len(returns), rebal_freq): train returns.iloc[i-window:i] mu_t train.mean() * 52 cov_t LedoitWolf().fit(train).covariance_ * 52 w risk_parity_weights(cov_t) # 或换成均值方差优化 test returns.iloc[i:irebal_freq] portfolio_ret.append((test w).sum()) cum_ret (1 pd.Series(portfolio_ret)).cumprod() print(累计净值:, round(cum_ret.iloc[-1], 3))逻辑说明window156是3年周频rebal_freq13是季度。每次只用训练集算权重避免偷看未来。test w是持有期收益。参数窗口太短协方差不稳太长则反应迟钝3年是常见折中。回测结果要看最大回撤和夏普不要只看累计收益。4. 避坑与排查资产配置模型最容易翻车的五个地方4.1 现象优化结果全押一个资产 → 原因预期收益估计偏差 → 解决加约束或改用风险平价这是血泪经验里最常见的一条。历史均值算出来某资产年化15%其他只有3%优化器自然全押它。但历史不代表未来。解决单资产上限设30%到40%或者直接放弃均值方差用风险平价。如果坚持用至少做收缩估计。4.2 现象回测夏普2.0实盘半年跑输 → 原因过拟合和交易成本未计入 → 解决加换手率惩罚和手续费回测漂亮往往因为参数调到刚好拟合历史。实盘一上就翻车。解决回测里每次调仓扣0.1%到0.3%手续费并统计年换手率。如果年换手超过200%说明阈值太敏感把再平衡阈值从3%提到8%。4.3 现象协方差矩阵不可逆 → 原因资产数量接近或超过样本期数 → 解决降维或加正则当资产数大于等于周数时协方差矩阵奇异求逆报错。解决减少资产到5个以内或用Ledoit-Wolf收缩或加对角线小量cov np.eye(n)*1e-6。这是黑匣子最容易卡住新手的地方。4.4 现象再平衡后收益反而下降 → 原因在趋势行情中过早卖出赢家 → 解决改用阈值时间双条件单用阈值会在牛市中不断卖出涨得好的资产导致跑输。解决阈值设宽一点如8%同时每季度只检查一次两者同时满足才调。这样既控制风险漂移又不至于频繁打断趋势。4.5 现象不同数据源算出的权重差很多 → 原因复权方式、时区、缺失值处理不同 → 解决固定一套数据源和清洗规则用前复权还是后复权结果不同。解决固定用后复权固定每周五收盘固定dropna不填充。把清洗脚本存下来每次跑之前先核对资产池和日期范围。后悔药就是版本控制你的数据快照。5. 进阶技巧用风险预算替代权重预算让模型更抗噪最后一章讲一个我实际用下来最稳的改进不直接优化权重而是优化风险贡献。具体做法是给每个资产设定风险预算比如股票40%、债券40%、黄金20%然后求解权重使得实际风险贡献等于预算。这样即使预期收益估计有偏差风险暴露仍然可控。下面是一个带风险预算的优化代码from scipy.optimize import minimize def risk_budget_obj(w, cov, budget): port_var w cov w mrc cov w rc w * mrc / np.sqrt(port_var) target budget * np.sqrt(port_var) return np.sum((rc - target) ** 2) budget np.array([0.4, 0.4, 0.2]) # 对应三个资产的风险预算 n 3 cons ({type: eq, fun: lambda w: np.sum(w) - 1}) bounds tuple((0.02, 0.8) for _ in range(n)) res minimize(risk_budget_obj, np.ones(n)/n, args(cov_shrunk[:3,:3], budget), boundsbounds, constraintscons) print(风险预算权重:, np.round(res.x, 4))逻辑说明目标函数是最小化实际风险贡献与目标预算的平方差。budget之和为1表示风险来源分配。bounds下限0.02避免某资产被完全剔除上限0.8防止债券因低波动占过高权重。参数预算根据自己风险承受力调保守型可以债券60%、股票30%、黄金10%。验证方法算出来的权重代入rc看是否接近budget * sqrt(port_var)。我自己的习惯是每季度第一个周末跑一次这个模型把输出权重和当前持仓对比偏离超过5%才下单。过去三年这个流程帮我避开了两次追高和一次恐慌卖出。模型不会让你暴富但能让你在下跌时知道为什么跌、该不该动。希望帮到你。本文还有配套的精品资源点击获取
返回列表