EigenLedger:一份可复现的投资组合体检报告,从绩效指标到组合优化
EigenLedger(原名 Empyrial)是一个 Python 库,把 QuantStats 的绩效与风险指标和 PyPortfolioOpt 的组合优化器收进一个 Engine 对象里:填好起止日期、股票代码和权重,调一次 portfolio_analysis(),就得到 17 项指标表格、收益与回撤图和可选 PDF 报告。
本站不复述官方 README,而是回答中文用户真正会卡住的问题:装得上吗、跑得通吗、报告里的数字怎么来的、哪些结果不能当真。全部结论来自仓库源码、issue 记录与本机隔离环境实测,可逐条复核。
项目来源
santoshlite/EigenLedger(原 ssantoshp/Empyrial)
EigenLedger 想解决什么?做一次组合复盘通常卡在哪几步?
把「算收益率、算回撤、画图、优化权重」分开做,代码要写几百行,而且每次换参数都得重来。EigenLedger 想解决的正是这段重复劳动。
多库拼接
行情用 yfinance、绩效用 QuantStats、优化用 PyPortfolioOpt,三个库各有各的数据结构,粘合代码本身就是 bug 来源。
数据清洗
停牌、退市、上市时间不一致会让合并后的价格矩阵出现 NaN,处理方式不同,回测结论就不同。
指标口径
年化按 252 还是 365 天、无风险利率取 0 还是国债收益率,同一组数据能算出两个夏普。
结果复用
参数散落在脚本里,三个月后想复现同一份报告,已经说不清当时用的是哪段区间、什么权重。
| 常见痛点 | EigenLedger 的做法 | 适用场景 | 注意点 |
|---|---|---|---|
| 绩效指标要自己一项项算 | portfolio_analysis() 一次返回 17 项指标表 | 月度/季度组合复盘、给客户或同事看的报告 | 指标口径写在源码里而非文档里,换版本可能变 |
| 回撤、收益曲线要自己画 | 内置收益柱状图、组合权重饼图,并可直接调 QuantStats 出图 | 需要一页纸讲清「赚了还是亏了、怎么亏的」 | 图表样式固定在源码中,改样式要改代码 |
| 不知道该配多少权重 | EF / MEANVAR / HRP / MINVAR 四种优化器,一行参数切换 | 多标的组合,希望有一个可对比的权重起点 | 优化结果强烈依赖历史区间,不等于未来最优 |
| 再平衡要靠手工维护日期 | rebalance 支持周期字符串或自定义日期权重表 | 定投、季度调仓、策略跟踪 | 周期按「天」近似折算,不是自然月 |
| 报告交付格式不统一 | report=True 输出 PDF(依赖 fpdf) | 需要发一份带图的静态报告 | 中文字体不会自动嵌入,需另行配置 |
| 换数据源要改一遍代码 | data= / benchmark_data= 可传入本地 DataFrame | 用本地 CSV、内部行情、非美股标的 | 列名与基准列有硬性约定,见「数据接入」页 |
| 想复现别人报告里的数字 | Engine 把全部参数固化为一个对象 | 研究记录、策略评审、课程作业 | 还需记录库版本与数据截止日,否则仍不可复现 |
EigenLedger 的定位是「把一次组合分析固化成可重跑的对象」,不是数据源,也不是交易系统。行情仍由 yfinance 拉取,优化仍由 PyPortfolioOpt 计算。
EigenLedger 内部怎么把一次分析跑完?
从源码看,一次完整分析会依次经过取数、算收益、算指标、画图四段逻辑。
构造 Engine,固定参数
Engine(start_date="2023-01-02", portfolio=["KO","AMD"], weights=[0.5,0.5], benchmark=["SPY"])。权重省略时默认等权,基准省略时默认["SPY"],结束日期省略时取运行当天。调 portfolio_analysis,触发取数
内部先调
get_returns(),用yf.download(..., auto_adjust=True)["Adj Close"]拉复权收盘价再算日收益;缺数据的标的会抛ValueError并列出缺失代码。算指标、出图表
用 QuantStats 与内置 empyrical 计算年化、波动、夏普、Calmar、信息比率、最大回撤、Sortino、偏度、峰度、尾部比率、VaR、Alpha、Beta 等 17 项,并绘制收益柱状图与权重饼图。
可选落盘为 PDF
portfolio_analysis(pf, report=True, filename="report.pdf")会走 fpdf 分支生成静态 PDF,适合归档与发送。
| 关键函数 | 作用 | 适用场景 | 注意点 |
|---|---|---|---|
Engine(...) | 承载全部输入参数与结果对象 | 任何一次分析的第一步 | 构造时不一定联网,真正取数在分析时 |
portfolio_analysis(pf) | 主入口,返回指标与图表对象 | 日常出报告 | 会打印大量中间结果,Notebook 外运行注意日志量 |
optimize_portfolio(pf) | 按 optimizer 求权重并对比优化前后 | 想知道「优化到底有没有用」 | 未设置优化器会直接抛异常 |
make_rebalance(...) | 生成再平衡日期与各期权重表 | 定期调仓、定投 | 生成出的权重需要自己保存,否则下次要重跑 |
get_returns(...) | 拉取并加权计算组合日收益 | 只想拿收益序列时直接用 | 权重与标的数量必须一致 |
TODAY = dt.date.today()、BENCHMARK = ["SPY"]、DAYS_IN_YEAR = 365 是模块级常量:这意味着「不写结束日期」的报告每次重跑结果都可能不同,严谨复盘应显式写死起止日期。EigenLedger 报告里有什么?17 项指标、4 个优化器、1 个数据源
先看这三张表,就能判断它是不是你要的工具。
17 项指标
覆盖收益类(年化、累计)、风险类(年化波动、最大回撤、VaR)、风险调整类(夏普、Calmar、Sortino、信息比率)与分布类(偏度、峰度、尾部比率)。不含交易次数、胜率、盈亏比。
4 个优化器
EF(最大夏普)、MEANVAR(给定波动上限求最大收益)、HRP(层次风险平价)、MINVAR(最小波动)。也支持传入自定义函数返回权重列表。
1 个默认数据源
yfinance 复权收盘价。A 股用 .SS/.SZ、港股用 .HK 后缀;本地数据可用 data= 传入。
| 报告指标 | 源码口径 | 适用场景 | 注意点 |
|---|---|---|---|
| Annual return 年化收益 | CAGR,按日频年化 | 快速对比不同组合的收益水平 | 区间越短越不稳定,三年以下的年化参考价值有限 |
| Cumulative return 累计收益 | 期末累计净值 − 1 | 判断区间内总盈亏 | 与起始日期强绑定,必须写明区间 |
| Annual volatility 年化波动 | QuantStats 年化波动 | 衡量组合整体抖动 | 与优化器的 max_vol 是两套口径,别直接对照 |
| Winning day ratio 上涨日占比 | 收益 > 0 的天数 ÷ 总天数 | 看胜率感受 | 日频胜率高不代表最终赚钱 |
| Sharpe / Sortino / Calmar | QuantStats 实现,rf 默认 0 | 风险调整后绩效对比 | 默认无风险利率为 0,会系统性抬高夏普 |
| Max Drawdown 最大回撤 | 内置 empyrical 实现 | 评估最坏持有体验 | 它只给「跌了多少」,不给「多久修复」 |
| Alpha / Beta | 对指定基准回归 | 判断收益是否只是跟着大盘 | 基准不同结论不同;默认 SPY 对 A 股组合不适用 |
| Skew / Kurtosis / Tail Ratio | 分布形态统计 | 识别肥尾与极端行情暴露 | 样本少时统计量噪声大 |
| Daily value at risk | 默认 sigma=1, confidence=0.95 | 估日常极端亏损量级 | 参数可调,报告里要注明用的置信度 |
| 优化器 | 求的是什么 | 适用场景 | 注意点 |
|---|---|---|---|
EF | 给定预期收益与协方差,求最大夏普权重 | 想做「性价比最高」的配置 | 默认用历史均值估收益,容易把过去涨幅当成未来预期 |
MEANVAR | 在年化波动不超过 max_vol 的前提下求最优 | 有明确波动预算的产品或账户 | max_vol 默认 0.15,含义与报告里的年化波动口径不同 |
HRP | 层次风险平价,按相关性聚类分配风险 | 标的较多、相关性结构复杂 | 不使用预期收益,天然更分散,但也不追求收益最优 |
MINVAR | 最小化组合波动 | 把风险控制放在第一位 | 低波动组合的收益通常也更低 |
| 自定义函数 | 自己返回权重列表 | 接入内部打分、等风险贡献等自有逻辑 | 权重数量与顺序必须和 portfolio 完全一致 |
EigenLedger 的三条入口,你是哪一种用户?
先选路线,再进对应页面,可以省掉大部分试错。
只想复现一份报告
目标:半小时内跑出第一份组合报告。
路径:安装与运行时边界 → 报告解剖。
你要接受的前提:装依赖时大概率要额外装 wheel,见安装页实测记录。
想知道数字可不可信
目标:判断报告里的夏普、Alpha、回撤能不能用于决策。
路径:结果审计 → 数据接入。
重点:收益来源拆解、区间敏感性、优化过拟合。
想接自己的数据
目标:用本地 CSV、A 股或港股数据跑同一套分析。
路径:数据接入 → 四种优化器。
重点:列名约定、代码后缀、复权口径与基准对齐。
| 你的场景 | 建议先用 | 理由 | 下一步 |
|---|---|---|---|
| 第一次接触,不确定能不能装上 | 安装与运行时边界 | 实测记录里已经写明失败原因与可复现的绕行方案 | 装完后进「报告解剖」 |
| 手上有一组美股代码,想快速出报告 | 报告解剖 | 把 17 项指标逐项讲清,避免看着表格发懵 | 再用「结果审计」检查结论 |
| 想定投或季度调仓 | 再平衡机制 | 周期字符串与自定义日期表两种写法差异很大 | 用「四种优化器」选权重 |
| 主仓在 A 股或港股 | 数据接入 | yfinance 对 A 股港股有覆盖与复权限制,先确认再分析 | 必要时改用本地数据 |
| 报告要交给别人看 | 结果审计 | 先自查结论边界,再交付 | 补「可复现清单」 |
| 已经报错卡住了 | 报错排查 | 按真实 issue 归类,多数是依赖版本问题 | 修完回到对应页面 |
不写 Python 能得到同样的组合结论吗?EigenLedger 与本机技能的分工
下面两张截图来自 EasyClaw 的实际对话界面(用户实拍,2026-09-23),用自然语言完成「区间行情统计」与「技术指标解读」两类任务。它们不是 EigenLedger 的运行结果,标的、数据源与口径都不同,仅用于说明另一种可选路径。
| 你想做的事 | EigenLedger 路线 | 本机技能路线 | 怎么选 |
|---|---|---|---|
| 跑一份含 17 项指标的组合报告 | Engine + portfolio_analysis | quant-analyst 可做风险指标与组合优化,但输出形态不同 | 需要固定格式的批量报告,选前者 |
| 查一只票或一段区间的指标 | 要自己拼代码 | a-stock-analysis、a-share-metrics-card 等技能直接对话取数 | 一次性查询,选后者更快 |
| 把结论画成图 | 内置图表 + QuantStats 出图 | chart-image 生成折线/柱状/K 线等图 | 要嵌进报告选前者,要单张图选后者 |
| 组合优化权重 | EF / MEANVAR / HRP / MINVAR | quant-analyst 声明支持组合优化 | 两套结果都建议交叉验证 |
| 不写代码也能问 | 不支持 | 支持,自然语言即可 | 这是两条路线最大的差别 |
披露:本站核验的是本机技能目录(29 个技能)中的公开描述,EigenLedger 与 EasyClaw 之间没有已证实的集成关系;上表仅为能力对照,不代表两者可以互相调用。
什么情况下不该用 EigenLedger?
把这个项目放回真实工作流里,边界比功能更重要。
适合
投资组合绩效复盘、投研报告配图、量化课程演示、把 QuantStats + PyPortfolioOpt 的组合流程固化成可重跑的脚本。
勉强可用
A 股与港股分析:需要自行确认 yfinance 的代码后缀与数据缺失情况,并用本地数据兜底。
不适合
实时交易、下单与风控执行;逐笔或分钟级高频研究;需要交易次数、胜率、盈亏比等策略统计的报告;对长期维护有硬性要求的生产系统。
| 判断维度 | 现状 | 对你的影响 | 建议 |
|---|---|---|---|
| 维护活跃度 | 主线最近推送 2025-09-14,最新发布 2024-10-28 | 新依赖兼容问题可能长期不修 | 小范围使用,别放进核心生产链路 |
| 依赖约束 | 硬钉 numpy<2、yfinance<0.2、quantstats 锁 0.0.62 | 与其它库同环境时容易冲突 | 用独立虚拟环境 |
| 数据源 | 默认 yfinance | A 股港股覆盖不稳定 | 用本地数据接口,见数据接入页 |
| 指标完整性 | 17 项绩效与风险指标 | 没有交易层面的统计 | 策略类评估另配工具 |
| 许可证 | 仓库 Apache-2.0,README 与 PyPI 口径不一致 | 商用前需自行确认授权 | 以仓库 LICENSE 文件为准并留存证据 |
| 中文支持 | 仓库有 README_CN.md(机翻),官方文档站只有英文 | 报错与文档需要读英文 | 配合本站的中文排查页使用 |
关于 EigenLedger 的常见问题
EigenLedger 和 Empyrial 是同一个项目吗?
是。该项目 2021 年以 Empyrial 之名发布,2024-10-27 的 v2.1.5 发布说明写着「Empyrial becomes EigenLedger」。同一功能现在有两个包名:旧名 empyrial 最新为 2.1.4(2024-02-08),新名 EigenLedger 只有 2.1.5 与 2.1.6 两个版本。README 里不少链接仍指向旧账号地址,属改名遗留,以官方仓库为准。
它是免费开源的吗?许可证到底是什么?
仓库 LICENSE 文件是 Apache License 2.0,GitHub 也标注 Apache-2.0;但 README 徽章写 MIT,PyPI 的 license 字段是「LICENSE」、分类器写着「Other/Proprietary License」,README 正文末尾又写「Apache 许可证 2.0」。四份口径互相矛盾,商用前请自行确认授权范围,并以仓库中的 LICENSE 文件原文为准。
它自己算指标吗?还是调别的库?
混合方案。项目自述是 QuantStats 与 PyPortfolioOpt 的封装器:绩效与风险指标一部分调用 QuantStats,一部分调用内置的 empyrical 副本(位于 EigenLedger/modules/empyrical/),组合优化全部交给 PyPortfolioOpt。因此 QuantStats 或 PyPortfolioOpt 的行为变化会直接影响报告数字。
报告里的数字我能直接引用吗?
可以作为研究参考,但引用时必须同时给出区间、标的、权重、基准、复权方式与所用版本。默认参数下无风险利率为 0、基准为 SPY、结束日期取运行当天,这三项都会让「同一份报告」在不同时间或不同人手里算出不同结果,以官方实现与你的实际输入为准。
支持 A 股和港股吗?
数据层走 yfinance,因此可以用 600519.SS、000001.SZ、0700.HK 这类后缀代码,但这取决于 yfinance 对相应市场的覆盖情况,缺失标的会直接抛错。更稳的做法是把本地行情整理成 DataFrame 后通过 data= 传入,细节见「数据接入」页。
它能帮我决定买什么吗?
不能。它只对给定的标的与权重做历史统计与组合优化,不做选股,也不预测未来。优化器给出的权重是历史区间的数学解,换一段区间结果可能完全不同,因此不能当作投资建议;本页内容仅供项目研究与技术评估。
为什么不推荐在报告里用它自带的 PDF 输出?
PDF 分支依赖 fpdf 1.7.2(一个 2015 年前后定版的旧库),不嵌入中文字体,中文标的名称与说明会出现乱码或方块;同时这个包只提供源码包,是安装失败的常见原因。要交付中文报告,建议先出图再自行排版,具体以官方实现为准。