初始提交:高股息策略研究与回测系统

从 Point-in-Time 股票筛选到统一 Web 前端的完整链路:
筛选 → 画像 → 策略 → 回测 → Walk-forward → 绩效分析 → 报告/前端。

架构
- 数据层与策略层分离;策略代码不写 SQL,只经 data/repo.py 取数
- 所有业务阈值集中在 config/*.yml,代码零硬编码(字段写错直接报错)
- 报告只做「run_id → SQL → 渲染」,不做任何计算,数字可追溯
- 前后端分离:output/ 静态站点 + hdiv web 提供的 REST API

数据安全
- 只增不删:SQL 钩子拦截 DELETE/DROP/TRUNCATE,并有源码扫描测试守护
- qlib 原有表只读,本项目数据写入 hd_ 前缀表
- 回补使用 INSERT IGNORE,保证既有行零改动
- .env 存密钥且已 gitignore;output/、logs/、.venv/ 不入库

交付物
- 30 张 hd_* 表、7 个 YAML 配置、283 项自动化测试
- 统一 Web 前端(hash 路由 SPA)+ nginx 部署配置与 launchd 托管脚本

如实声明的限制
- 策略缺少稳定的样本外超额收益(Walk-forward 7 窗口均值 -0.95%,
  基准 +2.29%);其价值体现在回撤控制,而非超额收益
- 涨跌停/停牌约束仅覆盖 2019 年起;index_weight 尚未填充
- AI Agent 层(plan.md 第四版 P8)未实现

详见 docs/user-guide.md 与 docs/implementation-status.md。
This commit is contained in:
2026-10-03 13:54:56 +08:00
commit fce725e13c
127 changed files with 28001 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
# ============================================================
# 股票筛选条件(★ 可直接修改)
# 对应 plan.md §4/§5 的 MarketFilter / RiskFilter / DividendFilter /
# FinancialQualityFilter。
#
# 所有阈值只允许出现在本文件;代码中不得硬编码。
# 修改后 config_hash 变化,历史 run 仍可完整复现。
# ============================================================
version: 1
name: high_dividend_universe
evaluation:
# point_in_time —— 每个 asof 日期独立求值(回测必须用这个)
# latest —— 仅在最新交易日求值一次
mode: point_in_time
asof: latest
# ------------------------------------------------------------
# MarketFilter —— 市场属性
# ------------------------------------------------------------
market:
# 交易所白名单。需要北交所时加 BSE。
exchanges: [SZSE, SSE]
# 板块白名单:主板 / 创业板 / 科创板 / 北交所
markets: [主板, 创业板, 科创板]
# 上市年限下限(年)—— plan.md §4「上市 ≥ 10 年」
min_listing_years: 10
# 总市值下限(元)—— plan.md §4「市值 ≥ 500 亿」
min_market_cap: 50000000000
# 流通市值下限(元);null = 不限制
min_float_market_cap: null
# 近 20 日日均成交额下限(元)—— 流动性过滤
min_avg_amount_20d: 20000000
# 要求 asof 当日正常交易(非停牌)
require_trading_on_asof: true
# ------------------------------------------------------------
# 行业豁免(对 RiskFilter 与 FinancialQualityFilter 同时生效)
# 银行/保险/证券的负债率天然在 90% 上下、且没有「自由现金流」的概念,
# 若不做豁免,高股息策略里最重要的银行板块会被全部误杀
# (实测:招商银行 90.2% 会被 risk.max_debt_to_assets 直接淘汰)。
# ------------------------------------------------------------
industry_exemptions:
# 豁免资产负债率上限的行业
leverage: [银行, 保险, 证券, 信托]
# 豁免「自由现金流为正 / FCF 覆盖分红 / 经营现金流对利润」要求的行业
free_cash_flow: [银行, 保险, 证券, 信托]
# ------------------------------------------------------------
# RiskFilter —— 风险过滤
# ------------------------------------------------------------
risk:
# 排除 ST / *ST(依据 stock_name_history 按日期还原,而非只看当前名)
exclude_st: true
st_lookback_from_history: true
# 排除退市整理 / 已退市
exclude_delisting: true
# 排除 asof 当日停牌
exclude_suspended: true
# 排除净资产为负
exclude_negative_equity: true
# 资产负债率上限;null = 不限制。金融股由 industry_exemptions.leverage 豁免
max_debt_to_assets: 0.80
# 大股东质押比例上限;null = 不限制(需额外数据源)
max_pledge_ratio: null
# 重大诉讼;当前无数据源,保持 false
exclude_major_litigation: false
# 商誉异常;当前无数据源,保持 false
exclude_goodwill_anomaly: false
# ------------------------------------------------------------
# DividendFilter —— 分红过滤
# ------------------------------------------------------------
dividend:
# 股息率口径:
# computed —— 自算 PIT-TTM(按 imp_ann_date 生效),无未来函数【回测主口径】
# dv_ttm —— 直接用 daily_basic.dv_ttm(仅交叉校验)
yield_source: computed
# 当前股息率下限 —— plan.md §4「股息率 ≥ 3%」
min_dividend_yield: 0.03
# 连续分红年限下限 —— plan.md §4「连续现金分红 ≥ 5 年」
min_continuous_years: 5
# 认定一次分红的规则(D6 决策):
# cash_div_tax_gt_0 —— 税前现金分红 > 0,且 div_proc='实施',且有 ex_date 或 pay_date
continuous_rule: cash_div_tax_gt_0
# 考察窗口(年)
window_years: 6
# 窗口内最少分红年数
min_dividend_years_in_window: 5
# 分红支付率上下限;null = 不限制
max_payout_ratio: 1.00
min_payout_ratio: null
# 5 年 DPS 复合增速下限;null = 不限制
min_dps_cagr_5y: null
# 要求自由现金流为正
require_positive_fcf: true
# 自由现金流对分红的覆盖倍数下限(FCF / 现金分红总额)
min_fcf_dividend_cover: 1.0
# 当「验证所需的数据缺失」时如何处理(安全边际策略的关键取舍):
# pass —— 放行(宽松)。避免因数据未同步而误杀,但会让「无法验证现金流」
# 的股票进入组合,与「安全边际」的初衷相悖。
# reject —— 淘汰(严格)。忠于「FCF 必须为正」的策略逻辑,
# 但结果会依赖数据完整度(数据补齐前后股票池会变化)。
# 实测:当前全部在市股票均有现金流数据,缺失的 10 只均为 1990 年代退市股
# (已被 risk.exclude_delisting 排除),因此两种设置结果相同。
# 若你希望「宁可错过、不可踩雷」,改为 reject。
on_missing_data: pass
# ------------------------------------------------------------
# FinancialQualityFilter —— 财务质量过滤
# ------------------------------------------------------------
quality:
# 5 年平均 ROE 下限
min_roe_5y_avg: 0.08
# 5 年平均 ROIC 下限;null = 不限制
min_roic_5y_avg: null
min_gross_margin: null
min_net_margin: null
# 经营现金流 / 净利润 下限(盈利质量)
min_ocf_to_profit: 0.60
# 覆盖 risk.max_debt_to_assets;null = 不覆盖
max_debt_to_assets: null
# 利息保障倍数下限;null = 不限制
min_interest_cover: null
# 兼容字段:留空则使用顶层的 industry_exemptions
exempt_industries: []
# PIT 纪律:只使用公告日 <= asof 的财报
pit_rule: announce_date_le_asof
# 用哪一期财报:latest_announced(最近已公告)/ ttm
report_basis: latest_announced
# ------------------------------------------------------------
# 输出控制
# ------------------------------------------------------------
output:
# 成员数少于该值触发 WARN(可能是条件过严或数据缺口)
min_members: 10
# 成员数上限;null = 不限制。用于回测时控制持仓候选规模
max_members: 200
warn_on_empty: true