第 3 章 · 02 riskfolio 全功能与有效前沿(对应 QS014)


文档摘要

第 3 章 · 02 riskfolio 全功能与有效前沿(对应 QS014) 速查摘要:本节精读 riskfolio 的"全家桶"演示——一个脚本走完优化、有效前沿、6 种可视化、Excel 报告。数据是 25 只资产 + 5 只因子 ETF(MTUM/QUAL/VLUE/SIZE/USMV),2018-2023。核心流程: 建对象 → 用历史法估均值和协方差(d=0.94 是 EWMA 衰减系数) → 用半标准差做最大化夏普 → 画 20 点前沿 → 6 种 出图 → 一键导出 Excel。riskfolio 是研究报告的瑞士军刀。 涉及脚本:原项目 (约 135 行,本章最长) ⚠️ 注意:本节的目标不是"教你优化算法",而是"展示 riskfolio 能干什么"。

第 3 章 · 02 riskfolio 全功能与有效前沿(对应 QS014)

速查摘要:本节精读 riskfolio 的"全家桶"演示——一个脚本走完优化、有效前沿、6 种可视化、Excel 报告。数据是 25 只资产 + 5 只因子 ETF(MTUM/QUAL/VLUE/SIZE/USMV),2018-2023。核心流程:Portfolio(returns=Y) 建对象 → assets_stats(method_mu='hist', method_cov='hist', d=0.94) 用历史法估均值和协方差(d=0.94 是 EWMA 衰减系数) → optimization(model='Classic', rm='MSV', obj='Sharpe') 用半标准差做最大化夏普 → efficient_frontier(points=20) 画 20 点前沿 → 6 种 rp.plot_* 出图 → rp.excel_report 一键导出 Excel。riskfolio 是研究报告的瑞士军刀。

涉及脚本:原项目 QS014-riskfolio/01_riskfolio.py(约 135 行,本章最长)

⚠️ 注意:本节的目标不是"教你优化算法",而是"展示 riskfolio 能干什么"。25 行的 assets = [...] 是 25 只精选个股(JCI/TGT/MO/JPM/BAX/MSFT/NVDA...),不是指数成分;5 只因子 ETF 是 iShares 的 MSCI 因子系列。跑通需要 pip install riskfolio-lib(依赖 cvxpy,装起来稍重)。

学习目标

阅读完本节,你应当能够:

  1. Portfolio + assets_stats 完成风险参数估计,理解 d=0.94 的 EWMA 含义。
  2. 说清 rm='MSV'(半标准差)为什么只惩罚下行波动。
  3. 画出 20 点有效前沿并解释其金融含义。
  4. 一次性调出 riskfolio 的 6 种可视化(plot_series/frontier/pie/table/risk_con)。
  5. excel_report 一键导出完整绩效报告。

工具与原理

半标准差(MSV,Semi Standard Deviation)

普通标准差对上行和下行一视同仁,但投资者只厌恶下行波动。半标准差只对"低于均值(或阈值)"的部分计算:

σ_semi = sqrt( (1/N) · Σ_{r_i < r̄} (r_i - r̄)^2 )

rm='MSV' 做优化,组合会自动规避"频繁大跌"的资产,即使它们整体波动不大。这更贴近行为金融对风险的真实感知。riskfolio 支持 10+ 种风险度量:MV(方差)、MAD(绝对偏差)、MSV(半方差)、CVaREVaRWR(最差实现)、MDD(最大回撤)等,把 rm 改成不同字符串即可切换。

EWMA 与 d=0.94

assets_stats(method_cov='hist', d=0.94)d 是 EWMA(指数加权移动平均)的衰减系数。协方差估计:

Σ_t = d · Σ_{t-1} + (1-d) · r_t r_t'

d=0.94 是 RiskMetrics 的经典取值(J.P. Morgan 1996),意为"每天旧协方差保留 94%、新收益贡献 6%"。越接近 1 越平滑(反应慢),越小越敏感(噪声大)。0.94 在日频金融数据上是工业标准。注意本脚本 method_cov='hist' 用的是简单历史等权,d=0.94 只在切到 EWMA 时生效,但传上不影响、留作切参用。

有效前沿(Efficient Frontier)

马科维茨的核心理念:在给定预期收益下最小化风险(或在给定风险下最大化收益)。所有"最小方差组合"在 (风险, 收益) 平面上连成的曲线就是有效前沿。前沿上的点都"有效"——不存在另一个组合风险更低同时收益更高。前沿最左端是最小方差组合,最右上端(通常)是最高收益单资产。脚本里 efficient_frontier(points=20)rm='MSV' 风险度量下描 20 个点连成前沿,再叠上"最大化夏普"那个红星(w1)——它在前沿上斜率最大。

脚本精读

1. 数据与资产/因子分离

assets = ['JCI','TGT','CMCSA','CPB','MO','APA','MMC','JPM', 'ZION','PSA','BAX','BMY','LUV','PCAR','TXT','TMO', 'DE','MSFT','HPQ','SEE','VZ','CNP','NI','T','NVDA'] factors = ['MTUM','QUAL','VLUE','SIZE','USMV'] tickers = assets + factors data = yf.download(tickers, start=start, end=end) data = data.loc[:,('Adj Close', slice(None))] data.columns = tickers returns = data.pct_change().dropna() Y = returns[assets] X = returns[factors]

assets 是 25 只个股(覆盖金融/消费/医疗/科技/能源),factors 是 5 只 MSCI 因子 ETF(动量 MTUM / 质量 QUAL / 价值 VLUE / 规模 SIZE / 低波 USMV)。Y 给组合优化用,X 留给因子风险分解(本脚本没用,但 excel_report 内部可用)。

2. 建对象、估参数

port = rp.Portfolio(returns=Y) rm = 'MSV' method_mu = 'hist' method_cov = 'hist' port.assets_stats(method_mu=method_mu, method_cov=method_cov, d=0.94) mu = port.mu cov = port.cov

Portfolio 是个空壳对象,assets_stats 才真正估参数:历史均值进 port.mu,历史协方差进 port.cov。换 method_mu='ewma1'/'ledoit'/'oas' 可切到 EWMA 或收缩估计(防小样本噪声)。

3. 最大化夏普 + 20 点前沿

w1 = port.optimization(model='Classic', rm=rm, obj='Sharpe', rf=0.0, l=0, hist=True) ws = port.efficient_frontier(model='Classic', rm=rm, points=20, rf=0, hist=True)
  • model='Classic':用历史数据估参数(对应 'BL' Black-Litterman、'FM' 因子模型、'BLFM')。
  • obj='Sharpe':目标函数是最大化夏普(也可 'MinRisk' 最小风险、'MaxRet' 最大收益、'Utility' 效用)。
  • rf=0.0:无风险利率,夏普分母用。
  • ws 是 20 行的 DataFrame,每行一个前沿组合的权重。

4. 6 种可视化

# 1) 累计收益曲线:画前沿上所有组合的历史累计收益 ax = rp.plot_series(returns=Y, w=ws, cmap='tab20', height=6, width=10, ax=None) ax = rp.plot_series(returns=Y, w=w1, cmap='tab20', height=6, width=10, ax=None) # 2) 有效前沿:风险-收益散点 + 夏普红星 ax = rp.plot_frontier(w_frontier=ws, mu=mu, cov=cov, returns=Y, rm=rm, rf=0, alpha=0.05, cmap='viridis', w=w1, label='Max Risk Adjusted Return Portfolio', marker='*', s=16, c='r', height=6, width=10, t_factor=252) # 3) 甜甜圈饼图:最优组合权重 ax = rp.plot_pie(w=w1, title='Portfolio', height=6, width=10, cmap="tab20") # 4) 绩效表:画一张含夏普/索提诺/最大回撤等指标的表格图 ax = rp.plot_table(returns=Y, w=w1, MAR=0, alpha=0.05) # 5) 风险贡献:每只资产对组合 MSV 风险的贡献 ax = rp.plot_risk_con(w=w1, cov=cov, returns=Y, rm=rm, rf=0, alpha=0.05, color="tab:blue", height=6, width=10, t_factor=252)

t_factor=252 是年化系数(252 个交易日)。alpha=0.05 用于 VaR/CVaR 类风险度量的 95% 置信。plot_pie 在 riskfolio 新版是中间挖空的"甜甜圈"样式。plot_risk_con 是检验"风险是否集中"的关键图——如果一两只资产贡献了大部分风险,说明组合没分散好。

5. 一键 Excel 报告

rp.excel_report(returns, w1, rf=0, alpha=0.05, t_factor=252, ini_days=1, days_per_year=252, name="QS014-riskfolio/excel-report")

这一行直接生成 excel-report.xlsx(原仓库里就附带了一份 633KB 的样本),内含:权重表、绩效指标、风险贡献、压力测试、因子暴露、回撤分析等多个 Sheet。对给老板/客户做汇报是降维打击——你写 5 行调用,riskfolio 替你产出一份完整尽调报告。

关键技巧

  1. riskfolio 是"研究报告工具",不是"回测引擎"。它的强项是一次性产出丰富图表和 Excel,弱项是没有 skfolio 那种 fit/predict 流水线。所以典型用法是:用 riskfolio 出报告、用 skfolio 做工程化回测。

  2. d=0.94 是工业默认值,但本脚本用 'hist' 没生效。要真正启用 EWMA,得改 method_cov='ewma1'(单指数)或 'ewma2'(双指数)。这是常见困惑点:参数传了但模式没切,等于白传。读源码时盯紧 method_*

  3. 风险度量可一键切换rm='MSV' 换成 'CVaR''EVaR''MDD''WR',整条流程(优化/前沿/可视化/Excel)自动适配,不用改其他代码。这是 riskfolio 最爽的特性。

  4. obj 决定优化目标'Sharpe'(本脚本)求夏普最大、'MinRisk' 求最小方差(左端点)、'MaxRet' 求最大收益(右端点)、'Utility' 求效用函数最大。配合 points=20 扫描就是有效前沿。

  5. 因子 ETF 是为了因子归因。5 只因子 X 在本脚本里没直接用,但 excel_report 内部会算组合对各因子的暴露(回归 beta),写进报告 Sheet。如果你做因子投资研究,把 factors 换成你的因子组合即可。

💡 速查要点:riskfolio 工作流五步——Portfolio 建对象 → assets_stats(d=0.94) 估参数 → optimization(obj='Sharpe', rm='MSV') 单点优化 → efficient_frontier(points=20) 描前沿 → 6 种 plot_* + excel_report 出报告。换 rm 切风险度量,换 obj 切优化目标,其余参数基本固定。

本节要点

  1. 半标准差 MSV 只惩罚下行波动,更贴近真实风险感知;rm='MSV' 是 riskfolio 10+ 风险度量之一,可一键切。
  2. d=0.94 是 EWMA 衰减系数(RiskMetrics 经典值),但本脚本用 method_cov='hist' 实际没生效,切到 'ewma1'/'ewma2' 才生效。
  3. 有效前沿是给定收益下最小风险的组合曲线,20 点描出;obj='Sharpe' 的组合在前沿上斜率最大(红星)。
  4. 6 种 plot_* 覆盖了研究报告需要的所有图:收益曲线、前沿、饼图、绩效表、风险贡献。
  5. excel_report 一键导出完整绩效 + 因子暴露 + 回撤分析的 xlsx,是 riskfolio 最杀器功能,做汇报首选。

下一节,我们看 HRP 怎么用层次聚类规避协方差求逆,做出比马科维茨更稳健的"风险平价"。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U