大佬持仓板 — 从 SEC 13F 里把动作挖出来
抄作业网站满地都是。它们的问题不是数据错,是把一份滞后 1.5 到 4.5 个月的 残缺快照,渲染成一块看起来像实时行情的板子。这块板子的设计目标反过来: 每一格都先告诉你它有多旧、缺了什么,再谈里面有什么。
skills/whale_watch/ + scripts/whale_watch.sh,纯 stdlib,cron 驱动。
和 market_board 同一条规矩:数字不经过模型。
三层
① 确定性仪器层 skills/whale_watch/whales.py
SEC EDGAR → 按 CUSIP 合并 → 逐仓和上季度相减
写 output/quant/whales/latest.json,交回模型的只是一句话计数摘要
② cron 哨兵 scripts/whale_watch.sh
先 5 秒前置探测(只读 submissions):没人交新的一期 → 静默退出
有人交了 → 全量抓取 + 渲染 + 推送
③ 板面 output/quant/whales/board.html
数据内联的单文件页,双击就开;终端版走 --action board
13F 的边界(这块板子的全部前提)
- ●只有美股多头。 做空、债券、现金、以及港股 A 股日股欧股的持仓,全都不在 13F 里。段永平的茅台、李录的邮储银行,这块板子一个字都看不到。
- ●是历史,不是现在。 季末快照,季后 45 天才披露。看到的持仓最新也是 1.5 个月
前的,最旧的接近 4.5 个月前。每一格都带
staleness_days,就是给这件事标价。 - ●门槛是 $100M 的机构投资顾问。 一个人自己的账户不在里面。
- ●用途是「看见公开申报里发生了什么」,不是投资建议,也不构成跟单依据。
这一层挡掉的七种错
每一条都是实测撞出来的,不是假想。这也是为什么这件事值得写代码而不是让 agent 去读网页 —— 下面每一种错,agent 读网页时都会照单全收:
| 陷阱 | 不处理会怎样 | 判据 |
|---|---|---|
| 一个仓位申报成多行 | 伯克希尔 2026Q2 的 89 行合并后其实是 29 个仓位;不合并则"持仓数"翻倍、权重全错 | 按 CUSIP 相加 |
value 单位 2023 年换过 | 之前千美元、之后整美元。跨线做差组合凭空千倍,两份文件都完全合法 | 看隐含股价 value/shares 落在哪一档 |
| 拆股不是加仓 | 4 拆 1 让股数变四倍而一股没买,板面出现"加仓 300%"的假头条 | 市值基本没动 + 股数比咬合整数倍 |
| 换证券编号不是一买一卖 | 伯里 2025Q3 的 BRUKER:清仓 116794108、同季"新建" 116794207 | CUSIP 前六位是发行人,前六同后二不同 = 换号 |
| 换申报主体不是换仓 | 阿克曼 2026Q2 把账本从老 LP 迁到新实体,新实体 Q1 只有 1 个仓位 → 误报新建 13 个 | 名册 also_cik 把两个实体的时间线合并 |
| 修正案有两种 | RESTATEMENT 整表重报 vs NEW HOLDINGS 只补几行。混为一谈,一份补充件会把原件里几十个仓位判成"全部清仓" | 读 primary_doc.xml 的 amendmentType |
| 微额仓位上头条 | 伯克希尔那笔 3,564 股 D.R. Horton 占组合 0.0002%,和百亿建仓并排显示 | 权重 < 0.1% 挡掉,但条数记进 moves.dust |
还有一条不是判据是纪律:截断要留痕。量化基金一个季度动几千个仓位,每类
只列前 25 条,砍掉多少写进 moves.truncated。静默截断会让一块只覆盖 2% 的板子
看起来像覆盖了全部。
一条自己踩过的:漏报比误报更难发现
拆股判据最早把 1.5 放进比例表。结果段永平 2026Q2 真金白银减掉三分之一的 UNH (60.1 万股 → 40.0 万股,同期股价 270 → 415,市值反而没动)被判成"1:1.5 拆股", 从信号里整条抹掉。板面上不会有任何报错、任何空白 —— 它只是安静地少了一条。 后来把零碎比例全删了:3:2 拆股确实存在,但它和"减仓三分之一"在数据上无法区分, 宁可当减仓报出来。
抱团视图
一块板子相对单只基金页面的全部意义:一个人建仓是观点,九个人同一季度建同一个
仓是拥挤。consensus 有四格 —— 同期买入 / 同期卖出 / 共同重仓 / 有人买有人卖。
最后一格是抱团的反面,是有分歧的标的。
名册
30 位,skills/whale_watch/managers.json。CIK 全部由 --action resolve 从
EDGAR 查得并核对过最近一份 13F 的报告期,不是手写的 —— CIK 写错一位就是另一家
机构的持仓,而且照样返回 HTTP 200、照样解析成功、照样渲染出一块好看的板子。
同名实体很常见,resolve 按「有没有真报过 13F + 最近一期多新」排序。加人:
python3 skills/whale_watch/whales.py --action resolve --query "Baupost"
用法
python3 skills/whale_watch/whales.py --action snapshot --manager all # 全量 python3 skills/whale_watch/whales.py --action check # 5 秒探测 python3 skills/whale_watch/whales.py --action board # 终端板 python3 skills/whale_watch/whales.py --action html # 单文件页 bash scripts/whale_watch.sh # cron 入口
依赖与限速
纯 stdlib。SEC 要求 User-Agent 带得到人的联系方式(SEC_USER_AGENT 可覆盖),
请求节流 8/秒(政策上限 10/秒)。股票代码走 OpenFIGI 免密钥接口,结果落
cusip_cache.json;查不到就留 null,不按公司名猜一个填进去 —— 那是把幻觉
写进确定性层。