Build · 从零到跑通

搭建方案

不是纸面计划——文中的每条「实测」都来自 2026-11-15 的真实验证,配套代码已跑通、数据已入库、仪表盘已生成。

0 · 一页摘要

先明确边界:做什么、不做什么、用什么做。

做什么

在本机搭一个三件套:档案(持仓与目标的持久记忆)、哨兵(估值/波动/偏离的状态监控)、纪律(±5pct 偏离刻度),输出一张每天看一眼的仪表盘。

不做什么

不预测涨跌、不荐股、不生成任何「建议买入/卖出」。输出只有客观状态:PE 分位 98.4% 过热 超配 +7.5pct

维度选择理由
技术栈Python 3.11 + SQLite + Pandas零成本、全本机、可审计,AI 改代码出错时可逐行验收
数据源天天基金(净值)+ 蛋卷(估值)+ 新浪(行情)免费、无 Key、稳定,均有明确口径
存储单个 platform.db备份 = 复制一个文件
输出单文件站点 / HTML 仪表盘双击即看、可打印、无外部依赖
成功标准查看次数与操作次数 双双下降晨报替代刷屏,提醒替代情绪

1 · 系统架构

数据层 → 存储 → 计算 → 展示 → 一句话维护。每一层都可单独替换。

┌─────────────── 数据层(每天/每周定时跑)───────────────┐
│  fetch.py                                             │
│  ├─ 天天基金 lsjz ──→ 复权净值(日增长率反推,含分红)   │
│  ├─ 蛋卷 index_eva ─→ PE / PE分位 / PB(每日快照累积)   │
│  └─ 新浪 hq/K线 ───→ 盘中价 + 降级备用(不复权,标注)   │
└──────────────────────┬────────────────────────────────┘
                       ▼
            data/platform.db(SQLite,6 张表)
                       ▼
┌──────────────── 计算层(calc.py / sentinel.py)────────┐
│  净值合成(月末再平衡)→ 年化 / 回撤 / 夏普              │
│  收益贡献 Σ w·r | 风险贡献 w(Σw)/σ²                   │
│  哨兵:分位阈值 85%/15% | 偏离阈值 ±5pct              │
└──────────────────────┬────────────────────────────────┘
                       ▼
        site/(本页面)+ out/dashboard.html(单文件版)
                       ▼
        cli.py 一句话维护:python3 -m src.cli all

2 · 数据源决策(2026-11-15 实测)

选型原则:免费公开、口径可追溯、失败可降级。每个数字都能说出出处,说不出就不显示。

用途接口实测口径与坑
复权净值 ★主源 api.fund.eastmoney.com/f10/lsjz ✓ 30/30 单页固定 20 条(pageSize 被服务端忽略),需分页约 96 页/标的;用官方「日增长率 JZZZL」反推复权净值 = 分红再投口径;实测 30 只全量 6.1 万行 / 170 秒
估值分位 ★主源 danjuanfunds.com/djapi/index_eva/detail/<code> ✓ 18/21 PE、PB、历史分位一次返回;分位为全历史口径(与课件的「中证近十年」不同,页面必须标注);半导体/光伏/有色无公开分位 → 降级为仅波动监控
历史价格(降级) 新浪 CN_MarketData.getKLineData ✓ 可用 单次约 2000 条;不复权,直接当净值会低估分红,仅用于波动率与兜底,页面标注「低估分红」
盘中现价 hq.sinajs.cn/list=… ✓ 可用 GBK 编码需转码;ETF 支持完整
中证官网 PE 序列 csindex.com.cn/csindex-home/perf/index-perf ⚠ 部分 官方 PE(peg 字段)可查,实测仅返回至 2025-12;作近十年分位的校验备源,不作主源
腾讯前复权 K 线 web.ifzq.gtimg.cn ✗ WAF 501 被腾讯 WAF 拦截,东财 push2his 亦连接失败。前复权价格口径不可得时,用净值口径替代并标注
降级链写在代码里,不是口号:基金净值失败 → 新浪不复权价(标注「低估分红」);估值失败 → 显示「暂缺」;每次抓取的结果与失败都写入 runs 表留痕。

3 · 数据库设计(6 张表)

够用就好。没有 ORM、没有微服务——一个文件,六张表。

表关键字段职责
instrumentscode PK · name · asset_class · bucket · sina_symbol · fund_code · index_code · pe_applicable30 只标的池;bucket 是五大资产归类(纳指/创业板/红利低波/黄金/国债)
nav(code,date) PK · nav · source复权净值;source 记录 fund_nav / sina_price_unadjusted,口径可追溯
valuation(index_code,date) PK · pe · pe_pct · pct_window · pb · source每日估值快照累积;pct_window 永远记录「蛋卷口径(全历史)」这类标签
holdings(account,code,as_of) PK · shares · market_value多账户持仓档案;Excel 导入 / 截图识别的落点
targets(portfolio,bucket) PK · weight目标配置——纪律的刻度来源
alerts / runs状态告警 / 运行留痕出问题时能回溯「哪天开始、哪只标的、哪个源」
未归类持仓的处理原则(课件的「宁缺毋假」):归不进五大资产的标的按标的名单列,绝不硬塞一个近似答案。

4 · 指标口径(每个数字可追溯)

口径不一致是投研平台最常见的坑。所有公式集中在 calc.py 一个文件里。

指标公式实现要点
复权净值nav[t−1] = nav[t] ÷ (1 + r[t]),r 为官方日增长率从最新单位净值往回反推 ⇒ 等价分红再投,消除 ETF 分红断层
年化收益(期末/期初)^(252/交易日数) − 1不足一年按实际交易日折算
最大回撤max( nav[t]/max(nav[0..t]) − 1 )用净值而非收盘价,避免折溢价噪声
夏普比率(年化收益 − 1.5%) ÷ 年化波动无风险利率取现金计息率,与档案口径一致
收益贡献Σₜ wᵢ,ₜ₋₁ · rᵢ,ₜ(百分点)逐日权重漂移 + 月末再平衡;合计 ≈ 累计算术收益
风险贡献RCᵢ = wᵢ·(Σw)ᵢ ÷ σ²ₚ全区间日收益协方差年化;回答「钱占比 ≠ 风险占比」
配置偏离当前权重 − 目标权重(±5pct)越线标黄、只报差距;阈值在 config.yaml 可改
波动分位当前 20 日年化波动率在近 3 年序列中的位置≥85% 异动偏高,≤15% 极低

5 · 搭建七步(每步带验收标准)

照着做,第一天就能跑起来。验收标准对应第「验收三问」,不是走过场。

  1. 环境
    Python 3.11 + pip install pandas numpy pyyaml requests
    验收:在干净环境重装一遍,报错信息是否可读。
  2. 建库与标的池
    编辑 config.yaml 的 30 只标的(code / sina / index / bucket),运行 python3 -m src.cli init
    验收:查 instruments 表应有 30 行,targets 与目标一致。
  3. 数据入库
    运行 python3 -m src.cli update(首跑约 3 分钟)
    验收:nav 表 ≥ 5 万行、0 只降级(或降级原因写在 runs 表);抽 1 只与行情软件对价,误差 < 0.1%。
  4. 口径校准
    跑 status,把策略池数字与课件对照
    验收:本方案稳健 5.0% / 平衡 10.5% / 激进 16.0% 年化,与课件差 0.5–1.2pct,源于净值 vs 价格口径——写进页面而不是硬凑。
  5. 哨兵上线
    运行 python3 -m src.cli sentinel,检查分位合理性
    验收:极端案例——把阈值改成 0% / 100%,全部标的应变「过热 / 低温」。
  6. 录入真实持仓
    三选一:Excel 模板导入 / 持仓截图让 AI 整理 / 模拟账户(demo 命令)
    验收:偏离表与你自己算的 Excel 一致;未归类标的不参与合计。
  7. 生成仪表盘并建立节奏
    运行 all,按「运维与验收」页的 SOP 维护
    验收:页面双击可看、断网可看、数字与终端 status 命令一致。