# sanguo_factor/fundamental_adapter.py """财务因子适配层: NAS 静态域三表+forecast parquet → PIT 日频特征列. 口径红线(docs/fundamental_factor_survey_20260907.md §7): - R1 单季差分: Q1 直接取累计,其余 = 本期累计 − 年内上期累计;缺上期置 NaN 不填 0 - R2 TTM: 连续 4 个单季之和,不足 4 期 NaN - R3 PIT: NOTICE_DATE ≤ 决策日才可见(有效披露日 = 三表 NOTICE_DATE 最大值,保守); NOTICE_DATE 缺失的报告期整期跳过(宁缺毋假) - 金融股(OPERATE_COST 缺失/为 0 的银行模板): 盈利质量/成长族特征置 NaN(估值族保留) 数据形态(NAS 实测 2026-09-07): - 三表按股: static/{income,balance,cashflow}/{code}.{SH|SZ}_{table}.parquet (北交 920xxx 残留零行文件、沪深退市 355 只文件不存在 → 读取容错跳过) - forecast 按报告期全市场: static/forecast/{YYYYMMDD}_forecast.parquet(中文列, 一股多行=按「预测指标」,归母净利润行优先) - 日期列为 "YYYY-MM-DD 00:00:00" 字符串;东财金额单位=元 - valuation(中文列)不读: 估值类因子市值 = close × SHARE_CAPITAL 自算(表达式层) P1-B 四新域(NAS 实测 2026-09-08): - dividend 按股: static/dividend/{code}.{SH|SZ}_dividend.parquet;code 列为 baostock 小写格式(sh.600519)与文件名不同 → 以文件名路由;日期/数值列为 字符串('' 为空);一行=一次分红事件,同年可多行 - gdhs 按期: static/gdhs/{YYYYMMDD}_gdhs.parquet(53 期 2013Q1→2026Q1); 用 代码/股东户数-本次/股东户数统计截止日-本次/公告日期 四列(实测列名 无第二连字符;噪声行情快照列不读) - top_holders: 只读聚合产物 factor_cache/top_holders_agg.parquet(static 兄弟目录;由 scripts/factor_research/preaggregate_top_holders.py 一次性 预聚合 108,610 个按股×期小文件) - valuation_baostock 按年: data/valuation_baostock/{year}.parquet(static 兄弟目录);date 为字符串,exchange 实测为 SH/SZ(映射回 SSE/SZSE); 2026 文件仅 08-13 起(bs 日喂起点)→ 01-01~08-12 缺口用 static/valuation(ak em 中文列 PE(TTM)/市净率)倒数补 - 四域缺任一 → 相关特征列全 NaN + 一次性 warning(优雅降级,本地可跑通) 输出: vt_symbol × datetime(日频) × FEATURE_COLUMNS,join 到 alpha_df 后 供 cs_rank(列) 表达式直接消费。 模块拆分(2026-09-10,纯结构重构零行为变化): 本文件保留为门面,re-export 全部原模块级名字(引用方与测试零改动),实现按数据域拆为: - fundamental_schema.py 常量/列契约(FEATURE_COLUMNS 等) - fundamental_statements.py 三表读取层(报告期宽表) - fundamental_report_features.py 报告期级指标预计算(单季化/TTM/比率族) - fundamental_forecast.py 业绩预告事件层 - fundamental_domains.py P1-B 四新域事件层 - fundamental_pit.py PIT 对齐 + 分块 join 主入口 """ from __future__ import annotations from .fundamental_schema import ( # noqa: F401 FEATURE_COLUMNS, FORECAST_TYPE_SCORE, DEFAULT_STATIC_DIR, _BALANCE_COLS, _BEAT_COLS, _CUM_MAP, _DA_PARTS, _DATE_COLS, _DOMAIN_COLS, _FIN_NULL_COLS, _FORECAST_COLS, _IBD_PARTS, _SYM, _VT_TO_FILE_SUFFIX, ) from .fundamental_statements import ( # noqa: F401 _TABLE_RAW, _dedupe_reports, _load_statements, _norm_dates, _read_static, _vt_to_file_code, ) from .fundamental_report_features import ( # noqa: F401 _cagr5, _compute_report_features, _delta4, _mean4, _qidx, _safe_ratio, _single_quarter, _std16, _ttm_of, _yoy4, ) from .fundamental_forecast import ( # noqa: F401 _ANNUALIZE_FACTOR, _load_forecast_events, ) from .fundamental_domains import ( # noqa: F401 _DIVIDEND_CHAIN, _EMPTY_EVENTS, _GDHS_CUTOFF_CANDIDATES, _VB_GAP, _code6_to_vt, _inv_guard, _load_dividend_cum, _load_extra_domains, _load_gdhs_events, _load_topholder_events, _load_vb_daily, _missing_warned, _warn_domain_missing, ) from .fundamental_pit import ( # noqa: F401 BATCH_CODES, _build_beat_events, _build_grid, _load_feature_events, _prepare_days, build_fundamental_features, iter_fundamental_feature_chunks, )