ray-household-finance — 家庭财务管理框架
Overview
家庭财务的通用管理框架,当前以投资组合分析为核心、面向家庭财务全场景扩展。
数据源无关——无论输入是天天基金 Excel 导出、手机截图 OCR、手动录入还是未来接入的 API,都先经「数据源适配器」归一化为标准化持仓 JSON,下游分析(分类/对比/轮动/比例控制/预测/可视化)只认这个 JSON,与输入源完全解耦。
双契约(v2.2 起):①持仓快照 JSON(现状,存量资金有多少、结构如何);②交易流水 transactions(历史,append-only 记买入/卖出/分红)。快照回答「现在怎么样」,流水回答「从头到尾真实赚了多少」——真实收益率/XIRR 只有流水才能算,快照里的 gpct 只是阶段收益。无流水时全部场景照常工作(流水是增强项,非前置依赖)。
核心流水线:数据源适配 → 标准化 JSON → 对比快照 → 按场景分析 → 生成 HTML → 验证 → 交付。
定位演进:本 skill 由「个人基金投资组合分析」演进为「家庭财务通用管理」,未来按需扩展收支记账、预算、保险、储蓄目标、资产负债全景——新场景沿用同一「数据源适配 + 标准化 JSON」架构,增量接入。已规划的扩展:收支场景引入「财务健康评分」四维度(储蓄率/必要支出占比/消费波动/应急储备 3-6 个月),待收支数据源接入后落地。
标准化持仓 JSON(全流程的唯一契约)
所有适配器的产出、所有分析步骤的输入,都遵循同一 schema(完整字段定义见 references/json-schema.md,交易流水 schema 亦在该文件)。核心字段:acls 四类 bond|index|qdii|mixed;四类资产口径 = 活期宝/国内债基/美债QDII/ETF权益(指数型+纳指QDII 归 ETF 权益);yield_rate/gpct_s 是字符串(可能含 --)。任何新数据源,只做「把原始数据映射成这个 JSON」这一件事,下游零改动。
数据源适配层(新增数据源的唯一接入点)
| 数据源 | 适配方式 | 现状 |
|--------|---------|------|
| excel(天天基金导出) | scripts/adapters/excel.py 位置解析 | ✅ 已实现 |
| screenshot(手机截图) | OCR(pytesseract/tesseract.js)→ 提取持仓文本 → 映射 JSON | 🧩 待接入 |
| manual(手动录入) | 对话中直接口述持仓 → 构造 JSON | 🧩 待接入 |
| api(未来开放接口) | 调 API → 映射 JSON | 🔮 规划中 |
新增数据源时:写一个 adapter 产出标准 JSON,其余六步流程完全复用。
场景路由(先识别场景,再走对应流程)
| 场景 | 触发词 | 数据/产出 | 核心逻辑 |
|------|--------|----------|---------|
| adapt(数据源适配) | 最新持仓、Financial-MMDD.xlsx、截图、持仓数据 | 任意源 → 标准化 JSON | scripts/adapters/excel.py |
| compare(持仓对比) | 对比、变化、diff、执行情况 | 本次 vs 上次快照 | 类别增减 + 建议执行核对 |
| rotate(活期宝轮动) | 轮动、货基、7日年化 | 27-28只货基按年化排序 | Top5 轮入 / <1.2% 轮出 |
| bond(债基加仓) | 债基、加仓、目标多少 | 债基当前→目标缺口 | 双核心集中 + 卫兵配置 |
| ratio(比例控制) | 比例控制、资产配置、目标比例 | 四类资产目标比例 → 交互式 HTML | scripts/ratio_control.py(±5% 漂移带) |
| cost(成本基准) | 交易流水、成本、真实收益率、IRR、XIRR | 流水 JSON + 快照 → 成本/损益表 | scripts/cost_basis.py |
| project(3年预测) | 3年预测、资产规模、未来 | 36月堆叠曲线 HTML | 比例模型 + 每月充值 |
| dashboard(可视化) | 可视化、仪表盘、HTML | 全量持仓 HTML | 细化到每只基金 |
通用执行流程(六步)
第 1 步:数据源适配(必须先做,不能跳过)
将任意输入归一化为标准 JSON。Excel 源:scripts/adapters/excel.py <excel路径> <日期> → _portfolio_data.json。
⚠️ Excel 结构铁律(仅 Excel 适配器):天天基金 Excel 是纯位置解析(非标准表格),必须先 load_workbook 打印 sheetnames + 前 6 行原始值,核对后再写解析逻辑。活期宝 sheet 行结构:名称 | 7日年化 | 可用/可取/总份额 | 未付收益 | 累计收益;基金 sheet 每只基金占 6-7 行块(名称行 + 类型行 + 金额行 + 状态行 + 盈亏行 + 收益率行),状态值含「有在途交易/到期/未到期/将到期」四种,块高随状态变化(6 或 7 行),必须用「名称行含 6 位代码」作为锚点 + 状态值判断动态跳行。
第 2 步:资产分类
- 债券型 →
bond;指数型 →index;QDII →qdii;混合型 →mixed - 四类资产口径:活期宝 / 国内债基 / 美债QDII / ETF权益(指数型+纳指QDII 归入 ETF 权益)
- 提取后立即打印核对:部分之和 == 总资产,验证通过才继续。
第 3 步:对比快照
读项目 MEMORY.md(或上次 _portfolio_data.json)取上次数字,做类别增减表 + 上次建议执行核对表(✅已执行/🟡部分/⏳未执行)。
第 4 步:按场景分析
- rotate:货基按 7 日年化降序,Top5 轮入候选 + 低收益(<1.2%)轮出候选,标注金额
- bond:核心债基(嘉实汇鑫/长安泓沣)+ 卫兵债基(湘财/嘉合/易方达)当前→目标→加仓额
- ratio/project:见下方「比例控制模型」
第 5 步:生成 HTML(可视化)
模板注入模式:Python 脚本生成 HTML,图表数据必须由脚本注入(json.dumps 或 f-string),绝不手写数据数组(手写必抄错,已踩坑)。
第 6 步:验证 + 交付
A. 数据验证清单(交付前逐项核对):
- [ ] 部分之和 == 总资产:
mm_total + fund_total == grand_total;class_totals各键求和 == grand_total - [ ] 四类和 == total(比例/预测场景):模拟输出四类资产之和恒等于总资产,逐月校验
- [ ] 权重和 = 100%:四类占比(或持仓明细权重)加总为 100%(允许 cash 项)
- [ ] 数据源标注:输出开头标注数据来源与快照日期(如「数据:Financial-0809.xlsx,净值日期 08-07」)
- [ ] stale data 警告:若净值日期距快照日期 >3 天,或收益率明显异常(如货基年化 >5% 或 <0.3%),显式提示数据可能滞后
- [ ]
\ufffd扫描:html.count('\ufffd')必须为 0(零容忍) - [ ] 金额转"万"用
toFixed(1):(x/10000).toFixed(1),不要Math.round(x/10000)/100
B. 集中度检查:
- 单只基金金额 > 总资产 10% → 标记 ⚠️ 集中度风险
- 债基双核心(嘉实汇鑫/长安泓沣)合计占国内债基比,若 >60% 需提示分散
C. 输出结构模板(固定 7 段,不遗漏):
- 快照总览(类别 × 金额 × 占比表)
- 对比变化(本次 vs 上次,类别增减表)
- 执行核对(上次建议 ✅已执行/🟡部分/⏳未执行)
- 场景分析(rotate/bond/ratio 按触发场景)
- 集中度提示(如有 >10% 或 >60% 集中,单独列出)
- 行动清单(P0/P1/P2 分级,具体到金额和基金)
- 结论信号(组合状态 + 下一步核心动作 + 置信度,见下)
D. 结论信号框(结尾固定输出):
┌─ 投资结论 ─────────────────┐
│ 状态: 稳健 / 需调整 / 偏谨慎 │
│ 下一步: [核心动作一句话] │
│ 置信度: 高 / 中 / 低 │
└────────────────────────────┘
present_files打开预览;回复给核心结论表 + 行动清单(P0/P1/P2)。
比例控制模型(核心方法论,2026-08-05 确立)
用户已采纳的资产配置策略(替代固定定投):
- 目标比例(方案A):活期宝 30% / 国内债基 50% / 美债QDII 12% / ETF权益 8%(加权年化 2.46%)
- 机制:每月定额充入活期宝 → 计算四类目标额 = 总资产 × 目标比例 → 活期宝超配部分按缺口比例流向低配类
- 漂移带(v2.2 新增,±5%):某类资产实际占比偏离目标 < 5 个百分点时当月不调仓(带内不动),超带才调——避免月月微调、减少无意义操作。
scripts/ratio_control.py --band 5(默认 5,--band 0恢复逐月精确调仓) - 约束:① 月转出上限(默认约 5 万)② QDII 限购约 1 万/月(超额转债基)
- 收敛:活期宝首月 67.4% → 约第12月<40% → 第15月收敛到 30%;3年后达到目标资产规模
- 模型代码:
scripts/ratio_control.py(模拟 36 月,输出每月余额 + 建议转出额)
交易流水与成本基准(v2.2 新增)
schema:transactions.json(append-only,完整定义见 references/json-schema.md)——每笔交易含 date / fund_code / fund_name / type(buy|sell|dividend) / amount / nav / fee。只追加、不修改;从启用日起记录,历史无法回补,成本基准以流水起点为准。
计算(scripts/cost_basis.py <transactions.json> [snapshot.json],口径均为金额口径为主、份额法为辅):
- 累计投入 = Σ buy;累计回收 = Σ sell + Σ dividend
- 累计损益 = 期末现值 + 累计回收 − 累计投入;真实收益率 = 累计损益 / 累计投入
- 加权平均成本 = Σ买入净额 / Σ买入份额(仅统计带
nav的买入) - XIRR:每笔买入为负现金流、卖出/分红记为正、期末现值为最后一笔,解年化内部收益率
输出必带两条诚实声明:①成本基准从流水起点算起,不含启用前的历史交易,故非「完整历史收益率」;②快照中未记流水的基金会缺失现值,脚本会显式提示(属正常,不是 bug)。
诚实声明(每次分析必带)
输出任何分析/预测/建议时,必须包含以下三条(可直接放在结论信号框下或文末):
- 这是条件规划,不是指令:比例模型/3年预测的所有数字都是「给定假设下的条件测算」,不是交易指令;实际操作需用户确认。
- 收益是概率估算,非承诺:债基 2.5%/QDII 3.5%/ETF 5% 均为历史均值假设,不构成收益承诺;市场波动会使实际偏离。
- 降低持仓 ≠ 必然增值:轮动/搬家优化的是结构(提升预期收益、分散风险),不是保证每笔都赚钱;久期长、汇率波动都可能造成短期回撤。
失败模式编码(thesis-break gate)
明确「什么情况该暂停/停止」,而非盲目执行:
| 触发条件 | 应对动作 | |---------|---------| | 🔴 债市持续下跌(10Y 收益率 >2.0%) | 暂停债基新增买入,已持仓不动,等企稳再续 | | 🔴 人民币大幅升值(USD/CNY <6.5) | 暂停美债 QDII 追加,现有仓位暂持 | | 🟡 活期宝跌破安全线(<安全阈值 或 <25%) | 暂停搬家,优先补充活期宝流动性 | | 🟡 QDII 长期限购(连续数月买不进) | 接受 QDII 低配,超额转债基,不强求达标 | | 🟡 某只基金单日限购(极低限额) | 放弃该基金做主力,缺口转给可正常买入的同类 |
每次按比例模型执行前,先检查上表是否触发;触发即调整节奏,不机械照搬模型输出。
共享红线(全场景通用)
- 反引号坑(铁律):写含反引号(
`)的 Markdown 文件必须用 .py 脚本文件方式,禁止 bash -c 内联(反引号被 shell 解析成命令替换,会破坏文件内容、混入垃圾行)。已两次踩坑。 - 图表数据脚本生成:HTML 图表的数据数组绝不手写,一律脚本注入(手写曾把大额数字写错一个数量级,还出现过数组笔误导致曲线锯齿)。
- 金额转"万"用
toFixed(1):(x/10000).toFixed(1),不要Math.round(x/10000)/100(多除 100 导致大额显示成小一个数量级)。 - Python 列表深拷贝:模拟循环里 append 列表用
bal[:],引用复用会导致下一轮覆盖、误报偏差。 - 写完必扫 \ufffd:零容忍,任何产出文件都扫描。
- 用户画像固定:Rayzhang,偏保守,核心诉求"稳",目标年化 2.5%;货基每周轮动 Top5-6;操作风格少问多做、输出表格+emoji。
- 隐私保护(v2.1 新增):处理的是家庭财务敏感数据(持仓金额、银行账号、收入)。输出/存档前账号脱敏(如
****1234只留末 4 位);敏感数据优先本地处理,不主动上传第三方;生成的 HTML/报告含金额时,默认仅本地预览,分享前先经用户确认。
资源结构
ray-household-finance/
├── SKILL.md # 本文件(框架 + 路由 + 红线 + 诚实声明 + 失败模式)
├── references/
│ └── json-schema.md # 标准化 JSON + 交易流水 schema 完整定义(按需加载)
└── scripts/
├── adapters/
│ └── excel.py # 天天基金 Excel → 标准 JSON(当前唯一已实现)
├── extract_portfolio.py # 别名入口(向后兼容,转发到 adapters/excel.py)
├── ratio_control.py # 比例控制模型:36月模拟 + ±5%漂移带 + 建议转出额
└── cost_basis.py # 交易流水 → 成本基准 + 真实收益率 + XIRR(v2.2 新增)
实战经验
-
2026-08-28|场景:进化|经验:外部对比吸收 2 项——①交易流水第二契约(transactions.json append-only + cost_basis.py:加权平均成本/真实收益率/XIRR),补上「快照只能看现状、算不了真实收益」的架构级差距;②比例控制模型加 ±5% 漂移带(带内不动、超带才调),避免月月微调。克制吸收:跳过 sparkline(已有时效标注)和 provider fallback(边际)|来源:v2.1.1 → v2.2.0
-
2026-08-15|场景:进化|经验:对比外部 skill 吸收 2 项——①隐私保护红线(账号脱敏、敏感数据本地处理、分享前确认);②财务健康评分四维度(储蓄率/必要支出/波动/应急储备)记为未来扩展规划,待收支数据源接入后落地|来源:v2.0.0 → v2.1.0
-
2026-08-15|场景:改名|决策:ray-financial-analysis → ray-household-finance(家庭财务管理),定位从「个人基金投资组合分析」升级为「家庭财务通用管理」;当前核心是投资组合分析,未来增量扩展收支/预算/保险/储蓄/资产负债,沿用同一数据源适配架构|来源:v1.2.0 → v2.0.0(改名+定位升级,major bump)
-
2026-08-15|场景:进化|经验:对比外部 skill 吸收 5 个机制——数据验证清单、输出结构模板(7段)、集中度检查(>10%)、诚实声明(3条)、失败模式编码(thesis-break gate);JSON schema 卸载到 references/|来源:v1.1.0 → v1.2.0
-
2026-08-15|场景:架构|经验:skill 从「Excel 工具」升级为「数据源无关的持仓分析平台」——引入「标准化持仓 JSON」作为唯一契约 + 「数据源适配层」隔离输入差异(excel/screenshot/manual/api),新增数据源只写 adapter、下游六步零改动|来源:v1.0.0 → v1.1.0
-
2026-08-09|场景:parse+compare|教训:天天基金 Excel 基金 sheet 块高随状态值变化(有在途交易=6行/到期=7行),必须用"名称行含6位代码"锚点 + 状态值动态跳行,不能固定步长|来源:Financial-0804/0809 解析
-
2026-08-05|场景:ratio|教训:比例模型首次跑出"第1月建议一次性大额转出"(违反分批定投原则)+ QDII 单月转出触发限购;加"月转出上限 + QDII 月限购"约束后渐进收敛|来源:比例控制仪表盘开发
-
2026-08-05|场景:dashboard|教训:KPI 金额
Math.round(x/10000)/100把大额显示成小一个数量级(多除100);改(x/10000).toFixed(1)|来源:比例控制仪表盘 -
2026-08-05|场景:dashboard|教训:对话内嵌曲线手写数组笔误导致"波动上升"锯齿;HTML 脚本生成的数据一直正确,此后图表数据一律脚本注入|来源:3年预测仪表盘
-
2026-08-05|场景:bond|教训:某中短债基金"年度收益高"是记忆偏差(近1年跑输同类),且单日限购极低无法加仓;久期长的中长期纯债债牛猛、震荡落后,不适合保守组合做主力|来源:债基加仓讨论
-
2026-07-13|场景:plan|经验:年化目标计划三阶段(活期宝从高配逐步搬到国内债基+美债QDII);用户风险偏好保守,原更高目标过于激进已下调|来源:目标计划制定
-
2026-08-23|场景:parse|经验:天天基金导出 sheet 名可能变化("活期宝/基金" → "Sheet1/Sheet2"),适配器已改按位置取 sheet(第一个=活期宝,第二个=基金),不再依赖 sheet 名|死路:按名匹配(wb['活期宝'] 直接 KeyError)|来源:Financial-0823 解析|状态:resolved
-
2026-08-23|场景:compare|经验:旧快照 JSON 会被新数据覆盖,对比基线可从历史仪表盘 HTML 内嵌的
const FUNDS = [...]/const MM = [...]用正则提取,无需重新解析旧 Excel|死路:依赖 _portfolio_data.json 存历史(单文件被覆盖)|来源:0815 vs 0823 对比|状态:resolved -
2026-08-23|场景:monitor|经验:指数估值数据源可用性——东财 push2 估值字段接口有风控(RemoteDisconnected)、乐咕乐股 405 需登录、腾讯 proxy.finance.qq.com 只给行情不给 PE;分位数据靠每周 AI WebSearch 更新,点位走腾讯接口(稳定)|死路:东财字段探测(连发触发风控)|来源:宽基监控工具开发|状态:resolved
-
2026-08-23|场景:monitor|经验:条件触发型定投工具(宽基 PE 分位阈值 + 黄金回本线)可做成「数据 JSON + 生成脚本 + 每周日自动化巡检」三段式,AI 在自动化里承担 WebSearch 数据更新职责;看板数据一律脚本注入不手写|死路:全自动 API 拉分位(免费接口拿不到)|来源:宽基+黄金监控|状态:resolved
Scan to join WeChat group