Files
sanguo_vnpy_v2/docs/portfolio_backtest_result.md
T
claude_dev a68cf4905e feat(portfolio): sanguo_portfolio 组合策略框架(BulletTrade+miniQMT,不用jqdatasdk)
把聚宽"全天候轮动"(post48819)搬到 BulletTrade。融合=pip+扩展点注入
(SanguoMiniQmtProvider 继承 MiniQMTProvider 只 override get_fundamentals,
set_data_provider 公开 API 注入, BulletTrade 源码 0 改动)。

- providers: SanguoMiniQmtProvider 补 get_fundamentals(PershareIndex+自算PE/PS/PB/PCF/市值/ROIC)
- strategies/all_weather: 4选股函数+大小盘轮动+ETF兜底+涨停止损(聚宽风格翻译)
- factors(估值/ROIC自算) + filters(ST/涨跌停/次新/停牌)
- 88/88 测试 Mac+VPS 双过; VPS 回测 pipeline 跑通(修9bug:Capital单位/日期格式/百分数口径/11字段alias)
- 实盘 runner_live+runbook 就绪等交易日; DEFAULT_DATA_PROVIDER=miniqmt env 不装 jqdatasdk
- 文档: sanguo_portfolio_plan / portfolio_backtest_result / portfolio_live_runbook
2026-07-18 19:08:18 +08:00

9.5 KiB
Raw Blame History

sanguo_portfolio 全天候策略 VPS 回测报告

生成日期:2026-07-18 环境:VPS49.232.102.198WindowsPython 3.10.11+ miniQMT 模拟端(userdata_mini 范围:沪深300 子集 39 只权重股,2025-04-17 → 2026-07-17(约 3 个月)

1. VPS pytest 结果

项目
Python CPython 3.10.11 (MSC v.1929 64 bit) @ C:\Python310\python.exe
pytest 9.1.1VPS 预装)
bullet-trade 0.9.2jqdatasdk 列为 required 但 env guard 跳过)
xtquant 内置 xtdata,路径 C:\Python310\lib\site-packages\xtquant
miniQMT 数据路径 C:\国金QMT交易端模拟\userdata_mini
测试结果 88 passed, 1 warning in 1.24s

环境前置(必须,否则 import bullet_trade 报缺 jqdatasdk):

set DEFAULT_DATA_PROVIDER=miniqmt
python -m pytest tests/portfolio -q

2. 字段校准前后对比(关键发现)

VPS 连 miniQMT 实测 600519.SH 茅台 PershareIndex/Balance/Capital/Income/CashFlow 实际字段名, 发现 3 个严重不匹配,全部修复。

2.1 修了哪些 alias

sanguo 代码原用字段 miniQMT 实际字段 修复方式
PershareIndex roe du_return_on_equity(或 equity_roe _get_multi() 多 alias 回退
PershareIndex eps s_fa_eps_basic 同上
PershareIndex gross_profit_margin sales_gross_profit(或 gross_profit 同上
PershareIndex net_profit_margin du_profit_rate(或 net_profit 同上
PershareIndex inc_revenue_year_on_year inc_revenue_rate 同上
PershareIndex inc_operation_profit_year_on_year inc_net_profit_rate 同上
PershareIndex inc_total_revenue_year_on_year inc_total_revenue_annual 同上
Balance total_liability tot_liab 同上
Balance total_sheet_owner_equities tot_shrhldr_eqy_excl_min_int(或 total_equity 同上
Balance retained_profit undistributed_profit 同上
Balance short_loan / long_loan shortterm_loan / long_term_loans 同上

2.2 三个严重 bug 修复

bug 修复前 修复后
Capital 单位 _to_float(...) * 10000.0(按"万股"放大) 直接用,实证单位 = 股(茅台 1,256,197,800 股 = 12.56 亿股,符合现实)
日期格式 _to_date_str 输出 YYYY-MM-DDxtdata end_time 报"结束时间错误" _to_yyyymmdd()YYYYMMDD
百分数口径 miniQMT 返回 10.57=10.57%),策略阈值 roe > 0.15=15%)按小数设计 → 全部误通过 _pct_to_decimal() 在 provider 输出归一到小数(0.1057),对齐聚宽 indicator 口径

2.3 其他口径偏差(已记录,未改)

现状 说明
ROE 口径 miniQMT du_return_on_equity 是 YTD 累计(Q1=10.57%,年化约 30% 策略阈值 roe > 0.15 是 TTM 年化口径,Q1 累计数据通过率低。未自动年化(季节性偏差大),策略层后续可改取 Q4 报告或自算 TTM
PE 口径 EPS 来自单季,×4 近似 TTM 茅台 PE=14.4(实际 ~25),偏差源于 Q1 EPS × 4 不等于 TTM EPS(茅台 Q4 业绩最重)
PS / PCF / ROIC Income/CashFlow trading hours 下载超时,oper_profit/cash_flow NaN provider 加了 EPS × total_capital 兜底单季净利润,但 oper_profit/cash_flow 无替代源,PS/PCF/ROIC 实测 0% 非空
ROA 口径 PershareIndex 无 roa 字段 用 ROE × (归母权益/总资产) 自算,茅台 0.0895(≈8.95%

3. Provider 冒烟实证(600519.SH 茅台)

provider.get_fundamentals_df(['600519.SH'], date='2026-07-17') 返回:

字段 实测值 用户期望 验证
roe(归一小数) 0.1057 ROE≈10%
gross_profit_margin 0.8976 毛利率≈92% Q1 季节性略低)
eps(元) 21.76 合理
market_cap(亿元) 15663 1.5-2 万亿 close=1253
circulating_market_cap(亿元) 15663 同上
pe_ratio 14.4 实际 ~25Q1×4 偏低 ⚠️(口径偏差,见 2.3
pb_ratio 5.78 合理
roa(自算) 0.0895 合理
total_liability(元) 38.8B 财报匹配
total_sheet_owner_equities(元) 270.9B 财报匹配
ps_ratio 0.97 Income 下载成功后能算
pcf_ratio NaN CashFlow 缺
roic NaN oper_profit 缺

4. 短回测结果

配置39 只 HS300 权重股子集,2025-04-17 → 2026-07-1715 个月),单次选股快照, 等权持仓至期末。

4.1 字段非空率(39 只子集)

字段 非空数 占比
roe / roa / market_cap / pb / net_profit_margin / inc_revenue_yoy 38/39 97%
eps / pe_ratio 37/39 95%
ps_ratio(依赖 Income 38/39 97%
gross_profit_margin 26/39 67%(银行/券商PershareIndex 该字段为 NaN
pcf_ratio(依赖 CashFlow 0/39 0%
roic(依赖 oper_profit 0/39 0%

4.2 选股名单(4 个 filter 函数分别执行)

函数 选出 名单
small() (roe>0.15, roa>0.10, market_cap asc) 1 600585.XSHG 海螺水泥
big() (pe∈0-30, ps∈0-8, pcf<10, eps>0.3, roe>0.1, npm>0.1, gpm>0.3, rev_yoy>0.25) 0 (pcf NaN 被过滤掉,Q1 累计 roe 不达 0.1 年化阈值)
bm() (中市值价值股,pcf<4) 0 (同 pcf NaN 问题)
roic_big() (roic>0.08) 0 roic 全 NaN
合并选股 1 600585.XSHG

选股少的原因

  1. ROE 是 Q1 累计(10.57% 对茅台这种 TTM 30% 的股),归一到 0.1057 < 0.15 阈值,大部分被过滤
  2. pcf_ratio 全 NaN,触发 df["pcf_ratio"] < 10 时 NaN 行被丢弃
  3. roic 全 NaNroic_big 空产

4.3 收益曲线(等权持仓 2025-04-17 → 2026-07-17

项目 收益率
组合(600585 等权) -30.21%
基准 HS300 (000300.XSHG) +24.55%
超额收益 -54.77%

说明:单只选股 + 单期快照不构成有效策略回测,仅用于验证 pipeline 连通。 真实回测需要每月调仓 + 多期 + 完整 HS300 池 + 完整 TTM ROE/PCF/ROIC 数据。

5. 聚宽数值对账状态

状态
聚宽同期数值对账 缺基准(用户不续费 jqdata,铁律不装 jqdatasdk
自洽验证 provider 连通 miniQMT,所有可计算字段(ROE/毛利率/PE/PB/PS/市值/负债/权益)数值合理
选股合理性 选股逻辑跑通,filter 函数无报错,每只股的财务指标符合行业常识
茅台 ROE/毛利率实证 10.57% / 89.76%Q1 累计),与公开财报一致
茅台 PE 实证 ⚠️ 14.4Q1×4 近似 TTM 偏低,实际 ~25),口径差异已记录

6. 已修 / 待修清单

已修(本次提交)

  1. provider 字段 alias11 个字段加 _get_multi() 多 alias 回退
  2. Capital 单位 bug:移除 ×10000miniQMT 实际返回股数)
  3. 日期格式:_to_yyyymmdd() 转 YYYYMMDD 给 xtdata end_time
  4. 百分数归一:PershareIndex 的 ROE/ROA/毛利率/净利率/同比全部 ÷100 到小数口径
  5. Income 空表兜底:EPS × total_capital 算单季净利润(calc_pe 内 ×4 近似 TTM
  6. ROA 自算:ROE × (归母权益 / 总资产)
  7. 收窄 download_financial_data 默认表清单到 ['PershareIndex', 'Balance', 'Capital']trading hours Income/CashFlow 常超时)
  8. conftest Capital mock 单位对齐(万股 → 股)
  9. test_provider 过滤断言对齐归一后口径(>30>0.3

⚠️ 待修(策略层,下个迭代)

  1. ROE TTM 化:当前 Q1 累计导致 roe>0.15 过滤过严,应取 Q4 报告或自算滚 4 季度 TTM
  2. PCF / ROIC 数据源CashFlow/oper_profit 全空,考虑:
    • 盘后批量下载 CashFlow 表(trading hours 超时)
    • 用 PershareIndex 的 s_fa_cfps × total_capital 兜底经营现金流
    • net_profit / (1 - tax_rate) 兜底 oper_profit
  3. 真实回测驱动:当前 mini_backtest.py 是单期快照;接 bullet-trade BacktestEngine 跑月度调仓序列需另做(runner_backtest.py 已写框架,需对齐 BT 0.9.2 API
  4. ** benchmark 沪深300 完整 300 只**:当前子集 39 只只验证 pipeline,扩到全 300 只再跑完整调仓

7. 复现命令(VPS

:: 1. 同步代码(Mac 端)
cd ~/.openclaw/sanguo_projects/sanguo_vnpy_v2
tar -czf /tmp/sp.tar.gz --exclude='__pycache__' --exclude='*.pyc' sanguo_portfolio/ tests/portfolio/
scp /tmp/sp.tar.gz 49.232.102.198:C:/sanguo_vnpy_v2/sanguo_portfolio_sync.tar.gz

:: 2. VPS 端解压 + 测试
ssh 49.232.102.198
cd C:\sanguo_vnpy_v2
tar -xzf sanguo_portfolio_sync.tar.gz
set DEFAULT_DATA_PROVIDER=miniqmt
C:\Python310\python.exe -m pytest tests/portfolio -q

:: 3. provider 冒烟(茅台)
C:\Python310\python.exe -X utf8 _smoke_provider.py

:: 4. 预下载 HS300 子集 + 回测
C:\Python310\python.exe -X utf8 _predl.py
C:\Python310\python.exe -X utf8 _mini_backtest.py

8. 关键代码位置

  • provider 主文件:sanguo_portfolio/providers/sanguo_fundamentals.py
  • 策略层:sanguo_portfolio/strategies/all_weather.py
  • 因子(ROIC/估值自算):sanguo_portfolio/factors/{roic,valuation}.py
  • 过滤器:sanguo_portfolio/filters.py
  • 回测入口(框架):sanguo_portfolio/runner_backtest.py(接 BacktestEngine 待迭代)
  • 简化回测驱动(本次用):VPS _mini_backtest.py(探针脚本,未提交)