EigenLedger 的数据从哪里来、算什么口径?
理解这一步,才能解释「为什么我的收益和账户不一样」。
| 环节 | 源码行为 | 含义 | 注意点 |
|---|---|---|---|
| 数据源 | yfinance 下载历史行情 | 免费、无需 Key,但受上游接口变更影响 | 项目把 yfinance 锁在 0.1.96,上游接口已多次变动 |
| 价格字段 | 取 ["Adj Close"](复权收盘价) | 近似把分红与拆股计入 | 没有单独的现金分红记录,无法统计股息收入 |
| 权重语义 | initial_alloc = wts ÷ 首日价 | 权重是「买入时的资金分配」,之后不再自动平衡 | 所以组合会自然漂移,不是每日再平衡 |
| 收益计算 | 组合市值序列做 pct_change() 并丢掉第一行 | 日频收益率序列 | 首行被丢弃,区间起点实际晚一个交易日 |
| 单标的 | 走单独分支,直接对价格序列求收益率 | 单票也能算 | 单标的时基准仍会另行取数 |
| 访问行情接口 | 即使用 data= 传入本地数据,基准仍会走 yfinance 联网取数 | 无外网或 Yahoo 不可达时,分析会在基准环节失败 | 先确认基准能取到,再谈本地数据 |
| 本地数据仅覆盖组合 | 发布版 2.1.6 中基准不受 data= 影响 | “完全离线”这一目标在发布版里实现不了 | 基准问题需另行解决,详见下方说明 |
| Pandas 版本 | 项目未约束 pandas 上界 | 会被解析到 pandas 3.x,导致绘图报错 | 见「安装与运行时边界」页的实测记录 |
本机实测(Python 3.11.9 / yfinance 0.1.96):yf.download(["KO"], ...) 返回 0 行数据、无异常抛出,随后 portfolio_analysis() 在 assets.iloc[0] 处抛出 IndexError: single positional indexer is out-of-bounds;把 pandas 降到 2.1 后,报错点前移到基准取数的 ValueError: attempt to get argmax of an empty sequence。两个报错都指向同一件事:本机取不到行情数据。能否取到与你所在网络能否访问 Yahoo 行情接口直接相关,官方 issue 中也记录了旧版 yfinance 无法下载数据的问题。
A 股、港股、指数在 EigenLedger 里怎么写代码?
代码后缀写错不会报「代码不存在」,通常表现为取数失败或数据为空。
| 市场 | 代码写法 | 示例 | 注意点 |
|---|---|---|---|
| 上交所 A 股 | 6 位数字 + .SS | 600519.SS 贵州茅台 | 后缀是 .SS(Shanghai),不是 .SH |
| 深交所 A 股 | 6 位数字 + .SZ | 000001.SZ 平安银行 | 深市代码常以 0/3 开头,前后不要丢零 |
| 港股 | 4 位数字 + .HK | 0700.HK 腾讯控股 | 必须补足 4 位(700.HK 可能取不到) |
| 美股 | 直接写 ticker | KO、AMD | 大小写均可,建议统一大写 |
| 美股指数 | 以 ^ 开头 | ^GSPC 标普 500、^IXIC 纳斯达克 | README 示例里就把 ^IXIC 当作组合成分使用 |
| A 股指数 | 指数代码 + 交易所后缀 | 000001.SS 上证指数 | 与平安银行的 000001.SZ 仅后缀之差,极易混淆 |
| 港股指数 | ^HSI 等 | ^HSI 恒生指数 | 覆盖率与数据长度需自行验证 |
EigenLedger 怎么用自己的 CSV 或 DataFrame 跑分析?
这是让 A 股与港股分析可复现的最稳做法:把取数环节从库里挪到你自己手上。
准备一张价格表
行是交易日(按日期升序),列是标的代码。
data.filter(stocks)会按你传入的portfolio挑列,因此列名必须与代码字符串完全一致。把基准问题单独解决
发布版 2.1.6 的基准总是联网取数,
data=不会改变这一点(仓库主分支新增了「基准列存在则用本地数据」的判断,但该版本尚未发布)。因此:本地数据能让组合链路可复现,但无法让它完全离线。传入 data= 并显式写死区间
Engine(start_date=..., end_date=..., portfolio=[...], weights=[...], benchmark=[...], data=df)。区间要落在这张表的日期范围内。核对首日是否有值
首日缺价会直接抛
ValueError: Some stock is not available at initial state!。数据表应从所有标的都有价格的第一个交易日开始。
import pandas as pd
from EigenLedger import Engine, portfolio_analysis
# 行=交易日,列=标的与基准代码,值=复权收盘价
df = pd.read_csv("prices.csv", index_col=0, parse_dates=True).sort_index()
pf = Engine(
start_date="2022-01-04",
end_date="2024-12-31",
portfolio=["600519.SS", "000001.SZ", "0700.HK"],
weights=[0.4, 0.3, 0.3],
benchmark=["000300.SS"], # 注意:发布版仍会联网取基准,此处仅作代码示例
data=df,
)
portfolio_analysis(pf)| 数据要求 | 具体规定 | 违反了会怎样 | 自查方式 |
|---|---|---|---|
| 列名 | 与 portfolio 中的代码字符串完全一致 | 该标的被静默丢弃,收益按剩余标的计算 | 打印 df.filter(portfolio).columns 逐项核对 |
| 索引 | 日期索引,升序且唯一 | 排序错误会让首日价变成尾部价格,权重完全错位 | 打印 df.index[[0, -1]] |
| 首日值 | 所有标的首日都不能为空 | 抛 ValueError: Some stock is not available at initial state! | 检查 df.iloc[0].isna().any() |
| 价格口径 | 统一复权方式(建议后复权) | 混用复权口径会让收益被低估或虚高 | 记录数据来源的复权说明 |
| 基准列 | 代码里可以带上,但发布版不会使用它 | 库仍会为基准联网取数,离线环境直接失败 | 确认基准代码能联网取到,或自行改造代码 |
| 数据截止日 | 覆盖到 end_date | 末尾交易日被截断,区间与实际不符 | 打印 df.index[-1] |
哪六类数据问题会让 EigenLedger 报告失真?
它们都不会让程序报错,只会让结论悄悄偏掉。
| 问题 | 现象 | 对报告的影响 | 处理建议 |
|---|---|---|---|
| 上市时间晚于起点 | 该标的早期无价格 | 优化器会把缺失价填成 1,早期出现人为低价区,污染收益与协方差 | 把区间起点挪到所有标的都有数据之后 |
| 停牌 | 出现连续空值或价格不变 | 波动被低估,回撤被平滑 | 剔除长期停牌标的,或改用可交易样本 |
| 拆股与复权 | 前后价格量级突变 | 未复权数据会产生跳变式收益 | 统一使用复权价并记录复权方式 |
| 代码变更或退市 | 取数直接失败或历史被截断 | 组合里静默少一只标的 | 核对标的数量与 pf.portfolio |
| 时区不一致 | 不同市场交易日错位 | 跨市场组合在非共同交易日出现虚假收益 | 先按共同交易日对齐再分析 |
| 币种不一致 | A 股人民币、港股港币、美股美元 | 收益率被汇率波动混入,收益归因失真 | 统一本币口径,或明确说明未做汇率处理 |
同样是拿 A 股数据,EigenLedger 与本机技能有什么差别?
本机技能目录里有多个面向国内市场的取数技能,和 yfinance 的分工很不一样。
| 取数需求 | EigenLedger 路线 | 本机技能路线 | 建议 |
|---|---|---|---|
| A 股日线行情 | yfinance + .SS/.SZ 后缀,覆盖面与稳定性需实测 | akshare-finance、tushare-finance、mx-data 等技能面向国内数据源 | 对稳定性有要求时优先本地数据源 |
| 港股行情 | yfinance + .HK 后缀 | 部分技能覆盖港股,需逐个确认 | 先做小样本验证再批量 |
| 指数作为基准 | 需找到对应指数代码(如 000300.SS) | 可通过技能直接查询指数行情 | 基准代码务必先验证可取 |
| 基本面与财务数据 | 不支持,只做价格序列分析 | fp-dcf、a-share-metrics-card 等技能覆盖财务与估值 | 基本面分析走技能路线 |
| 数据可复现 | 导出快照后用 data= 固化 | 取数过程依对话,留痕需自行记录 | 正式研究统一导出快照 |
披露:本机技能目录已核验(29 个技能),但 EigenLedger 与 EasyClaw 无已证实集成;上表是取数能力的对照,不代表可以互相调用,也不表示数据口径一致。
关于数据接入的常见问题
能直接分析加密货币或期货吗?
只有 yfinance 覆盖并返回复权收盘价的品种才可能走下去。库本身不区分资产类别,它只处理「价格矩阵 → 收益序列」;期货的展期、保证金、合约切换都不在范围内,不要用它做期货绩效评估,以官方实现为准。
为什么我的 A 股代码取不到数据?
按可能性排序:后缀写错(.SH 应为 .SS)、港股代码未补足 4 位、该标的在 yfinance 覆盖范围内缺失、当前网络无法访问 Yahoo 行情接口。先单独下载一次该代码并打印行数,可以快速区分是代码问题还是网络问题。
可以用 baostock 或 akshare 的数据吗?
可以,只要你把它们整理成「日期索引 + 标的列」的价格表,再通过 data= 传入即可。库关心的是列名与索引,不关心数据最初来自哪里。建议统一使用同一复权口径,并在报告里注明来源。
权重是每日再平衡的吗?
不是。源码按「权重 ÷ 首日价格」计算份额,之后价格变化会让实际权重自然漂移,相当于买入并持有。需要定期再平衡必须显式传 rebalance 参数,否则报告描述的是 buy-and-hold 结果,以官方实现为准。
基准要写在 portfolio 里吗?
不要。基准通过 benchmark 参数单独指定,写进 portfolio 会被当作组合成分参与权重计算。另需注意:发布版 2.1.6 中基准无论如何都会联网取数,本地数据只覆盖组合部分,所以「想让整条链路离线」在发布版里做不到,需要改造代码或等待仓库主分支的逻辑发布,以官方实现为准。
跨市场组合(A 股 + 美股)要注意什么?
至少要处理两件事:交易日对齐(不同市场假期不同,直接用会造成虚假收益)与币种统一(否则收益里混入汇率波动)。库不做这两件事,所以跨市场组合的结论需要额外说明处理方式,以官方实现与你的数据口径为准。
数据要保存成什么格式才能长期复现?
建议存成 CSV 或 Parquet,包含日期索引与全部标的列,并在旁边记录:来源、复权方式、导出时间、覆盖区间、单位与币种。只保存最终图片或指标表,无法在依赖升级后重算,等于放弃了复现能力。