数据与数值约定

这些是每个模块都遵循的规则。若某个函数另有做法,它自己的文档会说明。

数据帧与时间

原生 fincore::dataframe 是 hmdf::StdDataFrame,索引是带符号 64 位 UTC 纳秒时间戳。因此可表示范围是 1677-09-21T00:12:43.145224192Z 到 2262-04-11T23:47:16.854775807Z;超出范围的日历值会抛 input_error,而不是回绕。日内精度被完整保留,utc_year 向更早的时间取整 —— 纪元前一纳秒属于 1969 年,而不是 1970 年。

索引要求由每个 API 自己决定,而且是有意不同的:

要求

出现位置

严格升序、无重复

风险估计、回测与滚动前推验证 —— 索引重复或乱序会抛 input_error

不要求有序,按行处理

模拟路径与分析输入 —— 保留调用方的行顺序,索引按原样复制

按相邻判断唯一性

归因对齐:那里“索引已排序”是未写明的前提(记为 F10-D11)

不要假设函数会替你排序或去重。如果某个 API 需要特定顺序,它会校验并说明。

收益率、单位与年化

除非函数另有说明,收益序列都是小数简单收益:0.01 表示 1%。daily_annualization 为 252。按 sqrt(annualization) 缩放的比率直接使用该因子;annualization_factor(frequency) 把 daily/weekly/monthly/quarterly/yearly 映射为 252/52/12/4/1,并原样返回显式覆盖值 —— 包括 0 或负数,因为校验责任在调用方。

权重、价格与金额沿用调用处的单位,从不做隐式换算。需要基点的函数会明确说明。

缺失值与对齐

NaN 是原生的缺失数值标记;它既不是很小的数,也不是 0。三种行为并存,每个函数都会说明自己用哪一种:

  • 丢弃该观测(涉及两个序列时按配对丢弃)。大多数标量风险与收益指标如此。

  • 整体拒绝非有限输入。压力测试与部分风险内核会拒绝含 NaN 的收益,而不是跳过它。

  • 传播:窗口只要触到缺失值,该窗口就产出 NaN,而不是部分统计量。

对齐同样显式:严格相等、公共索引、内连接,或文档写明的外连接策略。缺失标签从不被静默替换为 0。

加载列时,hmdf::nan_policy::dont_pad_with_nans 按给定值保留;补齐策略会为缺失位置插入 NaN。请选择与帧自身契约一致的那种,并记住空结果常常以空的类型化列返回,而不是缺失列。

所有权与生命周期

  • make_series 与 load_column 会复制或接管所有权;函数返回的帧拥有自己的数值。validate_returns 返回副本,因此通过结果写入永远不会影响输入。

  • portfolio_inputs 在接收时复制,materialize() 每次调用都返回新帧。

  • 有些访问器返回视图(列视图、std::string_view)。视图只在其帧存活且未被修改期间有效。

  • analysis_context 会缓存已算出的指标,因此单个实例在构造上就是单线程的。帧可以随意共享;上下文只在你自己加锁之后共享。

确定性与摘要

需要比较、存储或重放的结果携带摘要,而不是裸浮点数:

  • 运行时摘要给每个字段加长度前缀,并为每个值标注声明的类型,因此分隔符或 bool 与 1 的混淆都不会让两份不同载荷哈希成同一个值。

  • 浮点值序列化为小写 IEEE-754 位模式,因此 NaN 载荷与带符号零可以完整往返。部分写出器会把负零规范成正零,因为字节会被哈希。

  • 覆盖输入的摘要回答“输入是否相同?”;覆盖输出的摘要回答“结果是否相同?”。因子模型的 fingerprint 哈希的是输入,因此两次运行在比较数值之前就能确认一致。

确定性是按函数而言的,不是全局的:带种子的模拟只保证在本库内复现同一序列,只有文档写明 NumPy 映射的函数才承诺与参考实现给出相同数值。

错误

所有库错误都派生自 fincore_error,并带有分类、代码与结构化字段:

情形

类型

参数错误、列缺失或类型不符、内嵌 NUL、非法索引

input_error

因子面板或配置格式错误

factor_data_error

指标中的定义域校验(例如超出范围的 cutoff)

返回 NaN,不抛异常

结构合法帧内的越界值通常以 NaN 回应(例如 (0, 1) 之外的 cutoff),而结构性问题会抛异常。测试会逐字比较拒绝消息,因此两种不同诊断不会合并成一条通过的断言。

报告与文件

报表文档有自己的模式版本,独立于运行时序列化信封与 artifact bundle 清单。写出器会拒绝不安全的目标 —— 空路径、无法创建的目录、契约禁止覆盖的既有文件 —— 并在文档说明的情况下清理部分输出。CSV 是交换格式;它不携带结果模型的溯源信息,那正是摘要与 JSON 清单的用途。

频率与标签

输入的周期名是规范词;ME、QE、YE 这类字母别名只在输出中出现,使转换后的频率在现代日期范围里对应同一个边界。标签顺序也是契约的一部分:周聚合按日历年与 ISO 周标签排序,而不是按桶起点,因此可能出现 1 月的观测排在同一年的 12 月行之后。