SweetValueLab
Write for us
← 博客English

这些数字从哪来:申报文件,以及它们何时公开

· · 5 分钟

同一个财年以相差一天的两个日期到达,被收敛成表格里最终显示的那一行
目录

估值模型是容易的那一半。本站每晚在 518 家公司上跑十二个模型,算术从来不是出问题的地方。出问题的是:一个拆股之前的股数被摆在今天的股价旁边;同一个财年在一张表里出现两次,因为两个数据源给它起了不一样的名字;一个二月才公布的数字,被当成一月就能知道的东西展示出来。

这篇讲的就是那另一半:站内每个数字从哪来,在送到你屏幕之前被做了什么,哪些部分是尽力而为。它是十二个模型那篇的配套,而且里面的例子全是真实的代码、真实的日期——因为每一个都先是一个 bug。

两个数据源,有固定的先后

财务报表读的是公司自己在 SEC EDGAR 上的 XBRL 申报。这是首选源:10-K 和 10-Q,按公司自己打的标签,跟一个人翻文件看到的数字是同一个。EDGAR 覆盖不到的申报人,以及某些更早的年份,缺口由 Financial Modeling Prep 补上。

这两个源交回来的东西并不一样,而其中一处差别大到需要一个专门的函数。EDGAR 给你的是申报原值。FMP 给你的是已经按此后所有拆股复原过的值。英伟达 FY2019 那一行,FMP 读出来是 250 亿股上每股 $0.17;公司 2019 年真正申报的是 6.25 亿股上每股 $6.63。两个说的是同一年。如果把 FMP 那一行再按拆股调整一次(代码对 EDGAR 行就是这么做的),就会再除一遍 4,得到一个哪里都不存在的数字。所以代码靠「EDGAR 映射器从不产出的字段」把两类行分开,只有原值那一类会被调整。

每一行都知道自己是什么时候公开的

每一行入库都带一个 known_at:它来自的那份申报被受理的时间戳。绝不是我们抓取它的时刻。

这是一行代码,它决定了历史视图有没有意义。一个季度在 6 月 30 日结束。10-Q 在 8 月 5 日被受理。这五个星期里,那些数字在公司外面并不存在,而一个把它们摆在 7 月股价旁边的页面,描述的是一个谁也没法交易的世界。

一个季度结束,五周后申报被受理,13F 则在它所描述的季度之后 45 天才到
示意图。季报在它覆盖的期间结束之后数周才被受理;13F 持仓报告的截止期是季末后 45 天,所以投资人页上最新的持仓,可能描述的是六周前的组合。入库的每一行都带着受理时间戳,所以任何一个过去日期的视图,只会显示那时已经申报过的东西。

最极端的是 13F。一位管理人的持仓报告在它所描述的季度结束后 45 天才到期,也就是说,任何人手上关于伯克希尔或桥水最新的持仓,在它出现的那天就已经可以是六周前的了。这是披露制度本身的事实。在把某个仓位的变动当成新闻之前,值得先知道这一点。

拆股在读出来的时候才调整

苹果 FY2019 申报的每股盈利是 $11.89。它 FY2020 的申报写的是 $3.28。中间没发生什么坏事:2020 年 8 月有一次一拆四,两行的分母是不同的股。

入库的行严格保持申报原样,所以复原发生在读取的时候。每股类字段被除以「该行财年日期之后所有拆股的累乘比例」,股数类字段乘以同一个比例。被动过的行会带一个标记说明倍数是多少,页面因此可以把这件事讲出来。

这样修掉两件事。一是八年 EPS 走势图上不再有一个从未发生过的断崖。二是模型不会再拿申报股数去配今天的股价——Booking Holdings 那次一拆二十五,当时页面上每个模型印出来的都是股价的 25 倍。

表里的八年应该真的是八年

这一个我事先没想到。报表缓存以「代码 + 期间 + 财年日期」为键,而同一个财年会以不止一个日期到达。

52/53 周财年的公司,年度结束在月末附近的某个周六。开市客(Costco)FY2019 结束在 9 月 1 日,FMP 把这一年标成 2019-08-31,EDGAR 标成 2019-09-01。Ciena 的 FY2019 从一个源来是 2019-10-31,从后来一份 10-K 的比较列来是 2019-11-02。安捷伦(Agilent)采用了一项会计准则变更,把一个期初余额打在年末的第二天,于是 2018-10-31 和 2018-11-01 同时存在。没有谁是错的。一个想看「最近八年」的读者拿到的是十行,其中两行是重复,而跨着一行重复算出来的增速是垃圾。

三行日期相差一两天的记录收敛成一个财年,留下字段最多的那一行
财年日期相差在 14 天以内的行视为同一期间。开市客 FY2019 以 2019-08-31 和 2019-09-01 两个日期到达;胜出的是数值字段最多的那一行——一个老年份的 EDGAR 副本可能只有寥寥几个标签,开市客 2019 年的现金流量表只有六个,引擎吃到那一行就彻底失去自由现金流和资本开支。打平时,先申报的那一行胜出。

所以在读取时,财年日期相差 14 天以内的行被当作同一个期间。一个季度大约 90 天,所以这个窗口不可能把两个真正相邻的期间并掉。胜出的是数值字段最多的那一行,打平则取先申报的那一行,也就是原始的时点申报优先于后来的比较列。

投资人页背后的四种申报

投资人页和每支股票的内部人标签页,是由四种申报建起来的,全部直接读 EDGAR。每一种都有自己的口径,也都有自己说不了的事。

13F 持仓。 读每位管理人的 13F-HR,作为不可变的季度快照存下来。季度环比的变化(新建、加仓、减仓、清仓)是在这里由相邻两个快照算出来的。13F 只覆盖美股多头:没有空头、没有债券、没有海外上市、没有现金。报告用 CUSIP 标识证券,而 CUSIP 到股票代码的映射是本站手工维护的一张表;映射不到的就按申报里的发行人名称显示。

13D 与 13G。 受益所有权申报,按标的公司读。13D 意味着带意图的主动持股,13G 意味着被动持股。持股百分比取自封面页上申报人写的那个数,这件事天然就是尽力而为。

8-K。 重大事件。条目代码取自 EDGAR 的申报索引,不从文档正文里解析。这样枯燥得多,也可靠得多:不管正文那段话是谁写的,条目 5.02 就是董事或高管发生了变动。

Form 4。 内部人交易,从所有权文档本身解析。这比读一个汇总接口费事,换来的是大多数免费数据源会丢掉的两个字段:SEC 交易代码,于是公开市场买入能跟期权行权、代扣税股区分开;以及 10b5-1 标记,它说明这笔交易是按事先设立的计划执行的。一笔按八个月前就定好的计划卖出的股票,和一笔上周二临时决定卖出的股票,是两件不同的事。

金额按原始数字存

金额就按它本来的数字入库,格式化留到浏览器里最后一刻。任何东西在被计算之前都不会先被四舍五入。估值、行业体检板、情绪读数这些快照是不可变的,并且盖上产生它的代码版本号,所以站内在某个过去日期显示过的任何数字都可以重新跑出来。

这就是全部的约定。原始申报、按公开时刻打上时间戳、只在讲明白的地方做调整、存成可以再跑一遍的样子。十二个模型坐在这一层上面,它们的上限就是这一层的质量。

打开投资人页 →

订阅周报

每周一封英文周报:本周的 13F 持仓申报、内部人交易、财报,以及站内的新研究。不需要注册。

更多文章