做量化研究时,我们很容易把“有没有未来函数”当成一道是非题。代码没有读取下一天的价格,财务数据也加了披露日期,于是检查结果变绿,实验便被描述为 point-in-time。

但代码能看到什么,和历史上的研究者能知道什么,是两个需要分别证明的问题。

今天拿到的一条历史记录,可能已经吸收了后来发生的更正。今天整理出的股票名单,可能已经排除了后来退市的公司。今天下载的价格序列,可能已经按几年后的拆股重新表达。每一行都有日期,却不代表整张表重建了当时的信息状态。

本文所说的时点数据,即 point-in-time data,指的是按特定历史时刻能够获得的信息来组织的数据。这个要求并不是给数据库加一个日期字段就能满足的。它需要我们说明:哪个事实、哪个版本、通过什么渠道、在什么条件下,进入了哪一次决策。

通过时间戳检查,不等于拥有一套已经证明历史时点完整性的数据。

1. 一条历史记录可以包含未来才知道的事实

假设一家公司的财年在 3 月 31 日结束,财报于 5 月 15 日 15:00 日本时间披露。财报中的营业收入是 1,000 亿日元。

今天的数据表可能把它整理成这样:

会计期末       3 月 31 日
营业收入       1,000 亿日元

如果研究程序按会计期末把这条数据接到每日行情上,4 月初的策略就可能已经在使用这个收入数字。它没有读取未来价格,却仍然知道了未来。

问题出在两个时间被混在了一起。会计期末回答的是“这个数字描述哪个经济期间”;披露时间回答的是“外界从什么时候开始有机会知道这个数字”。属于 3 月的财务事实,并不自动成为 3 月可交易的信息。

J-Quants Pro 的财务数据文档将 CurrentPeriodEndDate 与 DisclosedDate、DisclosedTime 分别列出。字段的区分很有意义:数据所属的期间,和数据被披露的时刻,本来就不是同一件事。

然而,披露也不是研究系统可用时间的全部。一个公告已经公开,不代表研究者使用的渠道已经交付数据,也不代表本地程序已经完成下载、解析与检查。J-Quants Pro 另有数据更新时点说明,研究设计应当查清自己使用的数据产品与获取方式。

这里至少有四个需要区分的时间:

时间它回答的问题
经济所属时间这个数字描述哪个期间?
公开时间这份信息何时向外界披露?
系统可用时间指定渠道和系统何时可以使用它?
策略决策时间策略何时形成这次判断?

研究目标会影响如何使用这些时间。如果想研究公开信息之后的市场反应,需要合理重建当时的公开可见性与处理延迟;如果想复盘自己曾经运行的程序,本地实际接收记录就格外重要。今天下载文件的时间,不能直接替代两年前的公开时间;两年前的公告时间,也不能凭空证明当时自己的系统已经收到它。

我们可以采用保守的延迟假设,但必须把它写成假设。人为多滞后一天,也不会自动恢复缺失的历史版本或股票池。

2. available_at 解决的是一个具体问题

在研究系统中,一个很有用的规则是:

available_at ≤ decision_at

它的含义很直接:一条记录只有在声明的可用时间不晚于决策时间时,才能进入这次决策的信息集。

在上面的假设里,如果 available_at 是 5 月 15 日 15:00,那么 5 月 15 日 14:00 的决策就不能看到那条记录。系统可以明确挡住它,而不是寄希望于每个因子作者都记得手工处理财报延迟。

这个规则值得实施,也值得测试。但它证明的是一个有条件的命题:根据提供给系统的时间元数据,这条输入没有晚于决策时刻。

它并不独自证明时间元数据正确。如果一条更正后的记录沿用了原始披露时间,比较仍然可能通过。如果供应商交付延迟被忽略,比较也可能通过。缺少时间戳时,拿会计期末补进去,只会把不知道的事情变成一个看起来完整的字段。

甚至等号也需要解释。披露和决策都标为 15:00,是否足以让后者使用前者?这取决于时间精度、事件顺序和处理延迟。一个只精确到分钟的标记,不能证明同一分钟内的因果顺序。时间戳门控需要配合明确的事件与延迟规则。

因此,审查时应该继续追问不同的问题:

证据维度需要证明的内容
决策时可见性这条输入在决策前能否被指定信息渠道取得?
历史版本被输入的值是否是当时可见的那个版本?
历史股票池这只证券当时是否属于策略允许研究的范围?
公司行动处理价格、股数与收益是否使用了相容的口径?
来源与转换能否解释这条输入怎样从原始资料变成策略特征?

这些问题不能互相代替。一个干净的时间戳,不会补上版本历史;一个完整的版本档案,也不会替我们重建证券资格。

“时点数据不是一个布尔值”的意思,并不是时点要求无法检验。每个具体检查都可以有通过或失败的结果。问题在于,不能用某一个检查的布尔结果,代替整个历史信息集的证据。

3. 修订可以保留日期,却改写过去

继续使用同一家假设公司。5 月 15 日首次披露时,营业收入是 1,000 亿日元。6 月 10 日,公司发布更正,把数字改为 920 亿日元。

对描述这个财年的最新财务状态而言,920 亿可能是我们应当使用的数字。对重建 5 月 20 日的决策而言,当时可见的却仍是 1,000 亿。

如果数据库只保留最新值,今天返回的记录可能是:

会计期末       3 月 31 日
营业收入       920 亿日元

给这一行补上 5 月 15 日的原始披露时间,不能解决问题。那会让后来的数字借用旧时间戳,回到它尚不存在的日期。

能支持历史重建的记录,需要同时保留不同版本:

描述期间版本公开时间营业收入版本
截至 3 月 31 日的财年5 月 15 日 15:00 JST1,000 亿日元原始披露
截至 3 月 31 日的财年6 月 10 日 15:00 JST920 亿日元后续更正

这样,5 月 20 日和 6 月 11 日可以得到不同答案,同时都保持对各自信息时点的忠实。

这里的 vintage 指某个时刻能够取得的数据版本。它不一定是最终正确的版本。历史上的投资者会面对错误、不完整和后来才被纠正的信息;重建他们的决策条件,就要保留这些不完美。

版本问题也会进入派生特征。假设我们用累计值相减,计算某个单季度指标。如果其中一个累计值后来被重述,今天重新计算出的季度值可能与当时不同。因此,不只是结果需要时间戳,参与计算的原始输入及其版本也需要可追溯。

这不要求每个个人研究者都先搭建复杂的数据库。可以从保留原始文件、披露标识、抓取时间和转换脚本开始。但如果历史版本不可取得,就应该把这项限制留在研究结论里。

重复计算能够证明过程一致,却不能证明输入具有正确的历史身份。两次都用同一份后来修订过的数据,可以得到完全一致的结果,也可以完全一致地把后来才知道的事实送回过去。

4. 股票池也会泄露未来信息

未来信息不一定藏在财务数字里,也可能藏在一个证券代码列表里。

假设今天取得某个指数的当前成分股,再把这些股票过去十年的行情下载下来做回测。所有价格都来自真实交易记录,信号只读取决策日前的数据。看上去,时间处理没有问题。

但名单本身是今天才知道的。

过去十年里,一些公司可能退市、破产、被收购,或被移出指数。今天的成分股名单通常不会完整呈现这些历史成员。把当前名单带回过去,等于提前决定了哪些证券有资格留在研究样本里。

这类问题通常被称为幸存者偏差。不过它不只涉及“还活着”的公司,也涉及指数增删、上市时间、证券类别变化、代码变更,以及策略筛选规则依赖的信息。

真实的历史价格,不等于真实的历史股票池。

历史股票池需要在每次决策时重建。某只股票何时上市,何时进入或离开目标指数,何时改名或变更代码,都是证券身份的一部分。流动性筛选也应使用截至当时的成交信息,而不能按整个回测期间的平均成交额,提前选出后来交易最活跃的公司。

还需要区分名单公告与成员生效。指数调整可能先公告、后生效。策略究竟研究公告后的预期变化,还是只允许交易当时已经生效的成员,应当在规则中说清楚。

如果现阶段只能取得当前名单,仍然可以研究“今天这组公司过去表现如何”。这个问题有价值,只是不能把答案写成“当年按历史指数成分投资会怎样”。输入范围变了,研究问题也随之改变。

修复股票池之后,退市证券的收益、最后可交易价格和退出处理也不能被随手丢掉。仅让名称重新出现在样本里,却删除最难处理的价格阶段,仍然没有完整重建历史投资条件。

5. 公司行动让历史价格成为一种建模选择

历史价格也需要解释。

假设一只股票发生一拆二。为了让价格序列便于比较,数据服务可能把拆股前的价格除以二。我们今天看到的复权历史因此与当时屏幕上的名义报价不同。

这种转换本身并不错误。只看原始价格,拆股当天可能出现一个并非经济损失的跳变。对于某些收益率和动量计算,使用一致的复权序列有助于避免把单位变化当成市场波动。

但“使用复权价格”还不足以描述研究方法。

首先,要说明调整包含哪些事件。仅处理拆股的价格序列,与计入现金分红的总收益序列,回答不同的问题。现金分红是否再投资、何时进入现金账户,也影响收益计算。

其次,要说明价格进入哪一个环节。信号使用的标准化价格,不一定是模拟买卖的成交价格。回测账本需要让成交价、持股数量、现金流与公司行动保持一致。把复权价直接乘以未经相应调整的股数,可能造成口径错配。

最后,要检查未来调整是否改变了策略判断。对某些比例型指标,如果同一个历史窗口里的价格都乘上相同因子,结果可能保持不变。对名义价格门槛、每股指标或跨字段比较,这种不变性未必成立。不能因为一个收益率计算没受影响,就推断所有特征都没受影响。

JPX 的公司行动数据服务把现金分红、拆股、合并、要约收购以及证券主数据变化列为独立事件类别,并区分公告日、登记日与生效日等检索日期。这提示我们,公司行动应当作为有时间与含义的事件来处理。

研究中需要交代的具体选择包括:信号用原始价还是复权价,拆股怎样改变数量,分红怎样进入收益,调整因子何时可用,以及每股数据与价格是否处于同一单位基础。

因此,不能笼统断言“今天的复权历史都不可用于回测”,也不能把供应商提供的 adjusted close 当作无需解释的历史事实。需要检查的是,所采用的表示方法是否把后来信息带入决策,以及它是否与执行和记账口径相容。

6. KabuForge 的检查究竟支持什么主张

这些区分,也是我在研究基础设施中希望保留下来的边界。

在此前的 KabuForge 研究框架文章中,我介绍了数据、因子、策略、目标组合、风险与订单规划之间的关系。这里更关心其中一个问题:系统的检查结果,应当允许我们说到哪一步?

本文以 KabuForge v0.1.1 为案例,引用的源码固定至对应发行提交,其检查结果不应自动推广到后续版本。该版本的研究方法文档明确区分了时间门控与完整认证。研究输入需要声明决策时间和快照标识,check_point_in_time 与 check_lookahead 用 available_at 检查可见性。文档同时说明,这不是对数据来源、供应商时间、历史修订、幸存者偏差、公司行动或股票池构建的完整科学认证。

时间门控的作用,是使不应进入当前信息集的行能够被识别和限制。它没有把输入元数据自动变成可信的历史档案。

输入身份与运行记录解决的是另一个问题。保留文件哈希、快照标识和清单,可以帮助回答“这次实验究竟读了什么”,也能发现后续文件是否变化。但哈希证明的是所保存对象的身份,不是其内容在历史上是否可知。今天冻结的文件,即使永远不再修改,也仍然可能含有后来修订的数据。

这里还应区分发行包的源码清单与研究输入清单。固定软件版本,不能代替固定数据版本;固定数据版本,也不能代替验证它的历史可见性。两者都对复核有用,承担的证据责任却不同。

公开实现中的真实历史价格研究路径,保留了这样的状态声明:

readiness: RESEARCH-ONLY
pit_guarantee: false

这项声明属于相应研究路径,不能反过来概括所有数据和所有运行的状态。它提醒使用者:真实历史数据可以支持教学、软件流程验证和探索,却不能仅凭“真实”二字就成为历史信息完整性的证明。该版本的价格研究实现还声明了当前下载版本、历史可见性未经验证等假设,并拒绝包含拆股调整的区间。这些限制应当与结果一起保留。

我重视的系统能力,是让已完成的检查与仍未得到支持的主张同时可见。某条路径通过了时间门控,我们就可以报告这项检查;历史版本尚未核实,就不能把检查结果扩展成“数据已具备完整 PIT 保证”。

这也关系到 AI 辅助研究。AI 可以迅速生成读取数据、拼接字段和计算因子的代码,但它不能凭代码执行成功补出缺失的版本历史。如果研究记录保留了输入身份、时间假设和未验证边界,下一次修改才有明确的参照。

当前项目状态可以从 KabuForge 项目页进一步查看。这里讨论的不是某个策略的有效性,也不是模拟结果能否转化为实盘收益,而是研究系统如何把自己能支持的结论说准确。

7. PIT 应当是一条证据主张链

描述一个回测时,“我使用了历史数据”只是起点。

更强的主张,是我阻止了晚于决策时刻的输入进入计算。再进一步,是我能够说明可用时间如何从公开披露和指定数据渠道得到。随后,还需要交代历史版本、证券资格、公司行动与转换过程。

可以把这些主张写成一条逐步展开的证据链:

我使用了历史数据
        ↓
我限制了明显晚于决策时刻的输入
        ↓
我重建了指定渠道下的历史可用时间
        ↓
我保留或重建了当时可见的数据版本
        ↓
我重建了各时点符合规则的证券范围
        ↓
我一致地处理了价格、股数和公司行动
        ↓
我能把每次决策追溯到对应的输入与转换证据

这不是一个通用认证等级,也不是所有研究必须采用的工程顺序。各项责任并不完全线性:一个研究可能保留了完整财务版本,却缺少历史指数名单;另一个研究可能具有可靠的证券历史,但只有近似的渠道延迟假设。

证据链的用处,在于让读者看到主张的组成,而不是用一枚标签覆盖这些差异。

比起“本回测没有未来函数”,更可复核的表述可以是:

本实验按披露时间和明确的延迟假设限制财务输入,使用固定的数据快照与转换规则。财务历史修订尚未完整重建;证券样本采用当前名单,因此结果只描述这组证券的历史表现,不能作为历史指数投资效果的估计。

这个结论没有那么漂亮,却让读者知道结果支持什么,以及下一步应当补哪一项证据。

即使这些信息集问题都处理好了,研究仍可能在大量尝试中挑中偶然表现最好的策略。Bailey 与 López de Prado 在关于回测过拟合的文章中讨论了这种多重尝试带来的选择偏差。历史可知性和统计有效性都需要检验,前者不能替代后者。

对个人研究者而言,这种区分也决定了时间应该花在哪里。缺少版本档案时,继续优化时间戳检查,未必能减少最主要的误差。股票池存在后见选择时,增加更多因子,也不会使样本更接近历史。先说明不确定性的位置,才容易判断下一项工程工作是否值得做。

在 《为什么叫 ArcaViso:在不确定中,以理性为向导》里,我谈到观察、判断与发现自身错误的自律。放到回测中,这种自律意味着:不要让一个实现检查承担它无法承担的证明责任。

研究基础设施的目的,不是把不确定性变成一枚绿色勾号,而是让我们清楚地知道,哪些不确定性已经减少,哪些仍然存在。