Files
simon fce725e13c 初始提交:高股息策略研究与回测系统
从 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。
2026-10-03 13:54:56 +08:00

96 lines
4.0 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================
# 个股特性(StockProfile)配置(★ 可直接修改)
# 对应 plan.md §8–§15:股息率分析 / 估值分布 / 财务质量 / 分红质量 /
# 风险特征 / 安全边际模型
# ============================================================
version: 1
name: default_profile
# 统计窗口(年)。plan.md §13 要求观察 5 / 8 / 10 年趋势。
windows_years: [5, 8, 10]
# ------------------------------------------------------------
# TTM 股息率口径
# ------------------------------------------------------------
ttm_dividend:
# TTM 每股分红的回看天数
window_days: 365
# 宽限期:A 股年度分红除权间隔中位数约 366 天(实测招商银行最长 393 天),
# 严格 365 天窗口会制造「空窗期」把股息率算成 0 —— 统计假象。
# 仅当严格窗口结果为零时,回退到 window_days + grace_days。
grace_days: 45
# 单个窗口内最少样本数(日频),不足则该窗口统计标记为 insufficient
min_obs_days: 500
# 序列落库上限(每股每指标),供 HTML 画图;超出时等间隔降采样(统计量仍用全量日频)
series_max_points: 1500
# 哪些指标需要落序列(供图表);不在此列表的指标只算统计量,不落序列
series_metrics: [dv_yield, pe_ttm, pb, close, drawdown]
# ------------------------------------------------------------
# 计算哪些指标
# ------------------------------------------------------------
metrics:
# 估值:PE / PB / PS / 股息率(plan.md §9/§12)
valuation: [dv_yield, pe_ttm, pb, ps_ttm]
# 财务质量:plan.md §13
financial:
[roe, roic, revenue, net_profit, gross_margin, net_margin,
ocf, fcf, debt_to_assets, interest_cover]
# 分红质量:plan.md §14
dividend:
[dps, dps_cagr, dps_volatility, payout_ratio,
fcf_dividend_cover, dividend_continuity_years]
# 风险特征:plan.md §11 + §28.2
risk: [vol_60d, vol_250d, max_drawdown_3y, beta_300, avg_amount_20d]
# 收益特征
return: [ret_1y, ret_3y, ret_5y, cagr_5y]
# ------------------------------------------------------------
# 分位数(plan.md §9 明确要求)
# ------------------------------------------------------------
percentiles: [10, 25, 50, 75, 90]
# ------------------------------------------------------------
# 股息率波动分析(plan.md §11)
# 各频率下的滚动窗口长度(交易日 / 月 / 季 / 年)
# ------------------------------------------------------------
dividend_yield_volatility:
daily_window: 250
monthly_window: 60
quarterly_window: 20
annual_window: 10
# 至少多少个观测才输出,否则记为 insufficient
min_obs: 20
# ------------------------------------------------------------
# 安全边际模型(plan.md §15)
# ------------------------------------------------------------
safety_margin:
# separate —— 分项展示(第一版,plan.md §15 建议)
# composite —— 加权综合评分
mode: separate
weights:
dividend_yield: 0.30
valuation: 0.25
financial_quality: 0.25
balance_sheet: 0.10
dividend_quality: 0.10
score_bounds: [0, 100]
# 分项打分时的分位锚点(分位越高/越低对应满分)
score_anchors:
# 股息率:分位 >= 90 得满分,<= 10 得 0 分
dividend_yield: { best_percentile: 90, worst_percentile: 10 }
# 估值(PE/PB 越低越好):分位 <= 10 得满分
valuation: { best_percentile: 10, worst_percentile: 90 }
financial_quality: { metric: roe, best_abs: 0.20, worst_abs: 0.00 }
balance_sheet: { metric: debt_to_assets, best_abs: 0.20, worst_abs: 0.80 }
dividend_quality: { metric: fcf_dividend_cover, best_abs: 3.0, worst_abs: 0.0 }
# ------------------------------------------------------------
# 数据充分性门槛:不足时画像页显式标注「数据不足」,不猜
# ------------------------------------------------------------
sufficiency:
min_history_years_dividend: 5
min_history_years_price: 3
min_dividend_records: 5