最初的构思:把一个人的财务当成一个市场
PFEx 这个名字来自 Personal Financial Exchange。第一行代码之前,我先定下的是一整套设定:账户是标的,余额是股价,净资产是大盘,还有一整页我决定不做的事。
我做这个应用之前,先有的是一个名字,需求就写在名字里。
正式名 个交所,补充说明"个人金融交易所",英文 PFEx / Personal Financial Exchange,构词法和上交所、深交所是一路。Slogan 是"一个人,也有大盘。",气质我只用一句话定下:数据穿西装,文案穿拖鞋。
我想回答的问题不一样
记一笔的应用回答的是"钱花哪了",给你一张流水列表加一个饼图。我想让它回答的是另一个问题:
我的钱,现在整体是涨还是跌?谁在涨?谁在拖后腿?钱从哪来,流向哪去?
这个问题饼图答不了。而证券市场上刚好有一套不用学就看懂的语言:K 线、成交量、均线、回撤、龙虎榜。所以我的第一步,是把个人财务按这套语言重新说一遍。
| 现实里的财务 | 个交所世界 |
|---|---|
| 消费账户 | 标的 / 个股 |
| 账户余额 | 股价 |
| 每笔收支 | 成交 |
| 总净资产 | 大盘 |
| 外部收入 / 支出 | 买入(利好)/ 卖出(利空) |
| 内部转账 | 调仓 |
| 借入 / 还款 | 融资 / 空头回补 |
| 余额校准 | 审计调整 |
| 按月循环的周期预算 | ETF |
| 一次性专项预算 | LOF |
| 信息不全的待处理队列 | 预埋单 |
| 按周期自动记账的规则 | 预约委托 |
| 用户自己的账本主体 | 营业部 |
这张表不是给界面贴的金句,我是照着它去写数据模型的。TransactionType 里就七种,我让每一种单独交代三件事:动不动总净资产、动哪个账户、计不计成交量。校准算审计调整,所以不改成交量;调仓不产生盈亏,所以总净资产不变。口径写死在枚举里,界面就不用再解释一遍。
整套设定是在代码之前完成的。仓库的第一个提交(10 月 8 日)不是一版能跑通记账的最小 Demo,它一次带进来 464 个文件,路由、数据表和引擎文件都在里面。
口径比功能先定
账户 K 线就是余额 K 线,开盘收盘我先给了明确算法:开盘是当天第一笔交易之后的余额,收盘是最后一笔之后的,最高最低取当天余额极值,成交量是当天交易额绝对值之和,但排除校准与内部转账。均线取 MA5、MA20。
大盘就是总净资产,把所有账户余额加起来,负余额直接以负数计入,大盘 K 线是这条序列的 K 线,口径同上。
这里我劝过自己一次:要不要基期、要不要指数化。最后还是放弃了自造点数,也放弃了做两套价格。定下来的写法是"余额大就大,真实就好"。涨跌幅用 今收 / 昨收 - 1,基准小于等于 0 时不显示百分率,只显示涨跌额,因为那时百分比本身没有意义。
最锋利的一笔:账户状态
账户像股票一样挂牌:N(新上市,创建 7 天内)、正常、ST(特别处理)、*ST(退市风险警示)、停牌(连续 30 天无流水)、退市(已归档)。
难点在阈值。月初发工资余额高,月底交房租余额低,这是正常周期;如果拿初始余额或历史最高当基准,每个月都会误报一次风险。所以基准我做成了动态的:取前 3 个月月末余额绝对值的平均值,账户不满 3 个月才用初始余额,负余额账户用同一套口径看负债比例。
再配两条纪律:每日试算,但只在月末正式落盘并写状态时间线,月中波动不改状态;摘帽带迟滞,正余额的 ST 要回升到 80% 以上才算正常,*ST 先降回 ST 一级,不能一步摘干净。
分类角色让结构可算
每个分类有且只有一个角色,五个角色是主力、散户、游资、北向、融资。主力是工资房贷这种大额低频,决定趋势;散户是餐饮交通购物这种小额高频,制造波动;游资是报销红包退款这种不可预测的短期异动;北向是外部注入;融资是信用卡花呗这类杠杆资金。
有了这层,"谁在拉涨、谁在砸盘"才成为可以计算的东西,龙虎榜和角色资金分布四象限(主力/散户 × 买入/卖出)才成立。限制一个分类只有一个角色,是为了不让汇总重复计入。
人格与幽默都有边界
营业部人格由真实记账行为实时归纳,16 种平行存在、无优劣等级,四轴是活跃度、分散度、用途、管控,每种人格有 4 字母代码和一句运行准则,并且带迟滞,单月波动不改写人格。它是行为画像,不是投资评级,更不是操盘建议。
文案那半边另有一条原则。挑句子的函数是确定性的:从若干候选里挑一句,同一条件下永远同一句,界面不会每次刷新都抖。非目标也写得同样硬:不拿用户的穷、负债、亏损开玩笑。
一页纸的非目标
构思阶段列出"不做什么"和列出"做什么"一样重要,这些后来基本没被推翻:
- 不做真实证券交易,不做投资建议,不做社交排行榜;
- 不做银行自动同步,不做短信解析与无障碍读取;通知栏自动记账试过,因为识别不可靠已经整条停用,现在连监听服务都不注册;纯手动记账是选择,不是没做到;
- 不搞账户指数化、累计净贡献、两套价格、基期概念;
- 不鼓励天天盯盘,鼓励定期复盘;
- 不做开放式闲聊 AI,AI 对话限于"调阅本地账目加草案改账"这种有界形态。
隐私底座第一天就在
第一份提交里没有"先裸奔再加密"这一步。整库加密走 PRAGMA key,密钥存系统 Keystore;备份是 AES-256-GCM 的封装容器,随机 nonce;四语种在文案层一次到位;核心功能完全离线可用;AI 默认不上传,未确认不烧额度,可选脱敏。这些不是上架前补的合规动作,是定义的一部分。
构思改过三轮
PRD 现在标的是 v4.0 现状对齐版,写明"以现有实现为准重写",取代历史两份拼接稿:v3.2 动态基准版、v3.3 账户交易版。也就是说前面那套动态基准的账户状态先立,账户作为可交易标的这层后立,最后合并成一份对齐稿。
快照子系统后来的删除,是同一条逻辑走到最后的结果:月末收盘和账户余额既然都能从流水推出来,预计算就只是推导的副本,副本迟早和口径打架。
小结
- 先定名字和口径,再定界面。名字定了隐喻,隐喻定了枚举,枚举定了引擎。
- 一套借来的语言(K 线、龙虎榜、ST)要成立,边界必须写清楚:它只做比喻,不做投资评级,不做交易。
- 非目标清单是最有用的一份文档,它挡住的坑比它带来的功能多。
- 本地优先、整库加密、四语、离线可用这些底座,第一天就位比后补便宜得多。