用户故事:单资产级别收益归因表格
创建日期: 2025-01-11
更新日期: 2025-01-11
状态: 待开发
优先级: P1
依赖: 真实收益追踪功能(已完成)
1. 用户故事
作为个人投资者,
我希望在收益分析页面看到每个资产的真实收益明细,包括每期收益变化,
以便我能清楚地知道哪些资产在真正赚钱,哪些在亏钱,以及收益是如何随时间变化的。
2. 背景与问题
用户场景
- 用户每月盘点一次资产
- 每次盘点时既有新资金投入,也有市场涨跌导致的收益变化
- 用户想知道:
- 单期收益:这个月我的某个资产赚了还是亏了?
- 累计收益:我买的这个资产从开始到现在一共赚了多少?
- 对比分析:哪个资产表现好,哪个差?
当前状态
目前收益分析页只支持"两点比较"模式:
- 选择起始快照和终止快照
- 计算累计收益
缺失的能力:
- 无法看到每期(每月)的收益变化
- 无法追踪单个资产的收益历史
用户痛点
| 问题 | 影响 |
|---|---|
| 只有累计收益,没有分期明细 | 不知道某个月是赚是亏 |
| 类别级别的收益会相互抵消 | 无法识别表现差的个别资产 |
| 没有收益趋势 | 无法判断资产表现是在改善还是恶化 |
3. 功能需求
3.1 功能一:资产收益对比表(横向对比)
展示选定时间段内,所有资产的收益对比。
核心字段:
| 字段 | 说明 |
|---|---|
| 资产名称 | 资产标识 |
| 期初市值 | 起始快照时的市值 |
| 期末市值 | 终止快照时的市值 |
| 账面变动 | 期末 - 期初 |
| 累计流入 | 期间所有快照的 net_inflow 之和 |
| 真实收益 | 账面变动 - 累计流入 |
| 真实收益率 | 真实收益 / 平均资本基础 |
⚠️ 注意:当选择跨多个快照的时间段时,需要累加中间所有快照的 net_inflow。
UI 设计(桌面端):
┌─────────────────────────────────────────────────────────────────────────┐
│ 📊 资产收益对比 [按类别筛选 ▾] │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┬────────┬────────┬────────┬────────┬────────┬───────┐ │
│ │ 资产 │ 期初 │ 期末 │ 账面 │ 流入 │ 真实收益│ 收益率│ │
│ ├───────────────┼────────┼────────┼────────┼────────┼────────┼───────┤ │
│ │ 🟢 沪深300ETF │ ¥10,000│ ¥15,000│ +¥5,000│ ¥3,000 │ +¥2,000│ +17.4%│ │
│ │ 🟢 余额宝 │ ¥50,000│ ¥50,100│ +¥100 │ ¥0 │ +¥100 │ +0.2% │ │
│ │ ⚪ 朝朝宝 │ ¥20,000│ ¥45,700│+¥25,700│ ¥25,700│ ¥0 │ 0% │ │
│ │ 🔴 中证500ETF │ ¥10,000│ ¥13,000│ +¥3,000│ ¥5,000 │ -¥2,000│ -16.0%│ │
│ └───────────────┴────────┴────────┴────────┴────────┴────────┴───────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3.2 功能二:收益时间序列表(纵向追踪)⭐ 核心需求
展示单个资产在每个盘点周期的收益变化。
用户场景:用户想知道"我的沪深300ETF每个月赚了多少"。
核心字段:
| 字段 | 说明 |
|---|---|
| 盘点日期 | 快照日期 |
| 期末市值 | 该快照时的市值 |
| 本期投入 | 该快照的 net_inflow |
| 本期收益 | (本期市值 - 上期市值) - 本期投入 |
| 累计投入 | 历史 net_inflow 之和 |
| 累计收益 | 从第一期到当前的真实收益累计 |
UI 设计:
┌─────────────────────────────────────────────────────────────────────────┐
│ 📈 沪深300ETF 收益历史 [← 返回] │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┬────────┬────────┬────────┬────────┬────────┐ │
│ │ 盘点日期 │ 期末市值│ 本期投入│ 本期收益│ 累计投入│ 累计收益│ │
│ ├──────────┼────────┼────────┼────────┼────────┼────────┤ │
│ │ 2025-01 │ ¥10,000│ ¥10,000│ - │ ¥10,000│ - │ ← 首次建仓 │
│ │ 2025-02 │ ¥14,000│ ¥3,000 │ +¥1,000│ ¥13,000│ +¥1,000│ │
│ │ 2025-03 │ ¥17,500│ ¥2,000 │ +¥1,500│ ¥15,000│ +¥2,500│ │
│ │ 2025-04 │ ¥16,000│ ¥0 │ -¥1,500│ ¥15,000│ +¥1,000│ ← 本月亏损 │
│ │ 2025-05 │ ¥20,000│ ¥1,000 │ +¥3,000│ ¥16,000│ +¥4,000│ │
│ └──────────┴────────┴────────┴────────┴────────┴────────┘ │
│ │
│ 📊 统计摘要 │
│ ├─ 累计投入: ¥16,000 │
│ ├─ 当前市值: ¥20,000 │
│ ├─ 累计收益: +¥4,000 (+25.0%) │
│ └─ 盈利月份: 3/4 (75%) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
移动端适配:使用可滚动的卡片时间线
┌─────────────────────────────┐
│ 📈 沪深300ETF │
│ 累计收益: +¥4,000 (+25.0%) │
├─────────────────────────────┤
│ │
│ ○ 2025-05 │
│ │ 市值 ¥20,000 │
│ │ 投入 ¥1,000 │
│ │ 本期 🟢 +¥3,000 │
│ │ │
│ ○ 2025-04 │
│ │ 市值 ¥16,000 │
│ │ 投入 ¥0 │
│ │ 本期 🔴 -¥1,500 │
│ │ │
│ ○ 2025-03 │
│ │ ... │
│ │
└─────────────────────────────┘
3.3 交互流程
收益分析页
│
├── 总览卡片(账面变动 / 真实收益)
│
├── 类别归因表格(已有)
│
└── 资产收益对比表(新增 - 3.1)
│
└── 点击某个资产行
│
└── 展开/跳转到 → 收益时间序列表(新增 - 3.2)
4. 数据模型
4.1 复用已有结构
#![allow(unused)] fn main() { /// 单个资产的真实收益(两点比较) pub struct AssetTrueReturn { pub asset_id: Uuid, pub asset_name: String, pub category: Category, pub start_value: Decimal, pub end_value: Decimal, pub book_return: Decimal, pub net_inflow: Decimal, // 注意:跨多期时需要累加 pub true_return: Decimal, pub true_rate: Decimal, } }
4.2 新增:收益时间序列结构
#![allow(unused)] fn main() { /// 单个资产的收益时间序列 pub struct AssetReturnSeries { pub asset_id: Uuid, pub asset_name: String, pub category: Category, pub periods: Vec<PeriodReturn>, pub total_inflow: Decimal, // 累计投入 pub total_return: Decimal, // 累计收益 pub total_rate: Decimal, // 累计收益率 pub winning_periods: usize, // 盈利期数 pub total_periods: usize, // 总期数 } /// 单期收益 pub struct PeriodReturn { pub snapshot_date: NaiveDate, pub end_value: Decimal, // 期末市值 pub period_inflow: Decimal, // 本期投入 pub period_return: Decimal, // 本期收益 pub cumulative_inflow: Decimal, // 累计投入 pub cumulative_return: Decimal, // 累计收益 } }
5. 计算逻辑
5.1 资产收益对比(跨多期)
#![allow(unused)] fn main() { fn calculate_asset_returns_multi_period( snapshots: &[Snapshot], // 按时间排序,包含起始和终止之间的所有快照 asset_id: Uuid, ) -> AssetTrueReturn { let start = snapshots.first(); let end = snapshots.last(); // 关键:累加中间所有快照的 net_inflow let total_inflow: Decimal = snapshots.iter() .skip(1) // 跳过起始快照 .filter_map(|s| s.items.iter().find(|i| i.asset_id == asset_id)) .map(|i| i.net_inflow) .sum(); // ... 计算真实收益 } }
5.2 收益时间序列
#![allow(unused)] fn main() { fn calculate_asset_return_series( snapshots: &[Snapshot], // 按时间正序 asset_id: Uuid, ) -> AssetReturnSeries { let mut periods = Vec::new(); let mut cumulative_inflow = Decimal::ZERO; let mut cumulative_return = Decimal::ZERO; let mut prev_value = Decimal::ZERO; for (i, snapshot) in snapshots.iter().enumerate() { if let Some(item) = snapshot.items.iter().find(|i| i.asset_id == asset_id) { let period_inflow = item.net_inflow; let period_return = if i == 0 { Decimal::ZERO // 首期无收益计算 } else { item.value - prev_value - period_inflow }; cumulative_inflow += period_inflow; cumulative_return += period_return; periods.push(PeriodReturn { snapshot_date: snapshot.snapshot_date, end_value: item.value, period_inflow, period_return, cumulative_inflow, cumulative_return, }); prev_value = item.value; } } // ... 构建 AssetReturnSeries } }
6. 验收标准
6.1 资产收益对比表
- 展示所有资产的期初、期末、账面变动、累计流入、真实收益、收益率
- 正确累加跨多期的 net_inflow
- 支持按真实收益排序
- 支持按类别筛选
- 正确处理新增/删除资产
6.2 收益时间序列表
- 点击资产可查看该资产的收益历史
- 展示每期的本期收益和累计收益
- 显示统计摘要(累计收益、盈利月份比例)
- 移动端有良好的时间线展示体验
- 首期(首次建仓)正确标记,不计算收益
7. 工作量估算
| 任务 | 估算 |
|---|---|
| 数据模型新增(AssetReturnSeries, PeriodReturn) | 0.25 天 |
| 计算逻辑(多期累加、时间序列) | 0.5 天 |
| 资产收益对比表组件 | 0.5 天 |
| 收益时间序列表组件 | 0.75 天 |
| 移动端适配 | 0.5 天 |
| 集成与交互 | 0.25 天 |
| 测试与优化 | 0.25 天 |
| 总计 | 3 天 |
8. 技术风险
| 风险 | 缓解措施 |
|---|---|
| 资产 ID 跨快照不一致 | 严格按 asset_id 匹配,不依赖 asset_name |
| 首期资产没有期初值 | 首期特殊处理,不计算收益 |
| 资产中途删除又重新添加 | 按 asset_id 追踪,中间缺失期视为断档 |
9. 后续扩展
- 收益趋势折线图(可视化每期收益变化)
- 与大盘指数对比(相对收益)
- 导出收益报表(Excel/PDF)