上一篇文章里,我写了 StockTracker 的 Agent Runtime:它不是把所有持仓都塞进上下文,而是先判断用户问题,再按需读取本地持仓、交易记录、行情、技术指标和新闻。
写完那篇之后,我反而更强烈地意识到另一件事:AI 分析是否靠谱,首先不取决于模型多聪明,而取决于底下那本账有没有算清楚。
如果一个投资工具连真实成本、卖出盈亏、分红、手续费和今日盈亏都算不明白,那 Agent 做得再精巧,也只是把不可靠的数据包装成更流畅的文字。
所以这篇想写的是 StockTracker 里更底层的一层:我如何处理个人投资记录里的事实账本和收益口径。
行情是表层,账本才是底座
很多投资工具最容易做出来的是行情展示。
给一个股票代码,调接口拿到当前价、涨跌幅、K 线和一些估值字段,再画几张图,视觉上已经很像一个投资工具了。
但真正用起来之后,问题很快会变成:
- 我这只股票真实成本是多少?
- 多次买入之后,卖出一部分到底赚了多少?
- 分红应该算收益,还是摊低成本?
- 手续费和印花税有没有算进去?
- 今天是休市日,为什么我的“今日盈亏”还在变?
这些问题不像行情那么显眼,但它们决定了用户对工具的信任。
如果成本是错的,后面的仓位分析、交易复盘、AI 建议都会跟着偏。AI 可以解释趋势,可以整理新闻,可以提醒风险,但它不能替系统“脑补”一本正确的账。
所以我后来越来越把 StockTracker 看成两层:
上层:AI 分析、投研对话、组合复盘、风险解释下层:交易事实、成本口径、手续费规则、行情有效性
上层体验可以慢慢迭代,但下层如果不稳,整个系统就会失去支点。
交易记录应该是事实账本
StockTracker 里,交易记录只表示已经发生的事实:
- 买入
- 卖出
- 分红或现金收益
- 成交日期
- 成交价格
- 成交数量
- 手续费和税费
- 备注
它不记录“我当时为什么买”,也不强迫用户提前填写交易计划。
这个选择看起来很朴素,但对后面的 AI 复盘很重要。
因为一旦把交易记录当成事实账本,Agent 在回答时就不能乱推断用户当时的意图。它可以说“这笔交易发生后仓位增加了”,可以说“从结果看这笔卖出实现了多少收益”,但不能说“你当时是因为某个技术信号买入”,除非用户自己在备注里写了。
这让系统的边界更清楚:
事实:系统能直接读取和计算解释:AI 可以基于事实组织语言动机:没有记录就不能擅自推断
我觉得这对投资工具尤其重要。因为投资复盘最容易出现的一种幻觉,不是模型幻觉,而是人自己的事后合理化。
如果系统也跟着事后补故事,那复盘就会变成文学创作。
FIFO 和摊薄成本回答的是两个问题
做收益计算时,我遇到的第一个关键取舍是:卖出盈亏和当前成本不能混成一个口径。
举个简化例子:
第 1 次买入:100 股,成本 10 元第 2 次买入:100 股,成本 12 元后来卖出:50 股,成交 13 元
如果要回答“这次卖出赚了多少”,我采用 FIFO。
也就是先买入的先卖出。这 50 股来自第一批 10 元成本的买入,所以这笔卖出的成本基础是 500 元,卖出收入是 650 元,已实现盈亏是 150 元。
这是一个交易批次问题。
但如果要回答“当前持仓成本是多少”,很多券商展示的不是剩余 FIFO 批次成本,而是摊薄后的持仓成本。
还是这个例子。卖出 50 股之后,剩下 150 股。如果只看 FIFO 库存,剩余成本是:
50 股 * 10 元 + 100 股 * 12 元 = 1700 元
平均成本是 11.33 元。
但券商常见的摊薄口径会把卖出收入从总投入里扣掉:
原始投入 2200 元 - 卖出收入 650 元 = 1550 元
剩余 150 股,摊薄成本是 10.33 元。
这两个数字看起来矛盾,但它们回答的不是同一个问题:
- FIFO 适合回答“这笔卖出对应哪一批成本,单笔实现了多少盈亏”
- 摊薄成本适合回答“当前仓位相对历史现金流之后,还剩多少成本压力”
所以 StockTracker 里固定做了这个区分:卖出明细按 FIFO 匹配成本批次,当前持仓成本按券商常见的摊薄口径展示。
这个决定让代码稍微复杂了一点,但换来的是解释上的稳定性。用户问“这笔卖出赚了吗”和问“我现在成本是多少”,系统不会拿同一套数字硬答两个问题。
分红不是简单加一笔收益
第二个容易算乱的是分红。
很多时候我们会直觉地把分红当成“赚到的钱”。这没错,但如果当前还持有这只股票,分红同时也会影响持仓成本。
比如:
买入 100 股,总成本 1005 元收到现金分红 80 元仍然持有 100 股
这时我更希望系统展示的当前成本是:
1005 元 - 80 元 = 925 元平均成本 = 9.25 元
而不是一边把 80 元算成已实现收益,一边又保持成本 10.05 元不变。
否则后面再计算总盈亏时,很容易把同一笔分红重复计算。
StockTracker 的处理方式是:现金收益优先摊低仍持有批次的成本;如果分红金额已经超过剩余成本,超出的部分才进入已实现盈亏。清仓之后再重新建仓,旧一轮持仓的分红也不会污染新一轮成本。
这个口径不一定适合所有人,但它有一个好处:系统能解释清楚。
我越来越觉得个人投资工具里,“完全符合所有券商和税务场景”不是第一目标。第一目标应该是:口径固定、边界明确、数字可追溯。
手续费不是表单附属品
一开始看,手续费像是交易表单上的几个字段。
但真正做进去后会发现,它其实是产品逻辑的一部分。
因为不同市场的费用结构不一样:
- A 股普通股票有佣金、卖出印花税、过户费
- A 股 ETF 和基金不应该照普通股票收印花税
- 港股有印花税和结算费
- 美股可能是零佣金
- 加密资产更接近交易所手续费模型
如果这些都让用户手填,系统当然最灵活,但也最容易出错。
所以 StockTracker 里保留了用户可配置费率,同时按市场提供默认费用规则。新增交易时,系统会根据市场、买卖方向和标的类型自动计算费用,用户仍然可以按实际成交结果调整。
这也是我做这个项目时很喜欢的一个原则:默认值要尽量接近真实世界,但不要假装自己掌握了所有真实世界。
投资记录不像记账软件里的普通消费。少算一笔印花税,单笔看可能没什么;但如果系统要长期复盘交易质量,费用就会持续影响结果。
而 AI 以后总结“你的交易是否过于频繁”“手续费对收益拖累有多大”时,前提也是这些费用从一开始就被认真记录了。
今日盈亏要尊重交易日
还有一个很容易被忽略的小问题:今日盈亏。
最简单的算法是:
当前持仓数量 * 今日涨跌额
但这里有一个坑:你拿到的行情,真的是今天的吗?
如果今天是周末、节假日,或者某个数据源只返回了上一个交易日的行情,系统还把它算成“今日盈亏”,用户就会看到一个很奇怪的结果:明明市场没开盘,今天怎么又赚了或亏了。
所以 StockTracker 里没有只看报价字段,而是额外判断:
- 当前市场今天是否交易
- 行情时间是否属于当前市场日期
- A 股和基金是否遇到节假日
- 美股日期要按纽约时间判断
- 加密资产则默认 24 小时交易
如果市场休市,或者行情是旧的,今日盈亏就应该归零,并明确提示“最近行情不计入今日盈亏”。
这个细节在 UI 上只是一行小字,但对信任感很重要。
因为投资工具最怕的不是没有数据,而是把旧数据伪装成新数据。
AI 应该解释账,而不是替你造账
当这些底层口径稳定之后,AI 才有发挥空间。
比如用户问:
帮我复盘一下成都银行这几笔交易有没有问题。
Agent 可以读取这只股票的持仓摘要、最近交易、FIFO 卖出明细、当前行情和技术指标,然后组织回答:
- 哪些是已发生交易事实
- 哪些是成本和收益计算结果
- 哪些是基于当前行情的事后观察
- 哪些数据不足,不能下结论
这和让模型直接看一堆交易记录然后自由发挥,是完全不同的体验。
我希望 StockTracker 里的 AI 更像一个解释层,而不是事实来源。
它可以把冷冰冰的账本翻译成更容易理解的复盘语言,可以指出仓位集中、频繁交易、成本摊薄、分红贡献、行情位置这些问题,但它不能绕过系统已经定义好的计算口径。
这也是我为什么会在上一篇文章里强调按需取数。按需取数的前提是:每一种数据都先被系统整理成可信的结构。
否则所谓 Agent,只是换了一种方式把混乱传给模型。
写在最后
做 StockTracker 这个项目,让我对“AI 投资助手”这件事的理解变得更保守了。
我当然希望它能分析新闻、理解持仓、复盘交易,也能在用户问问题时给出有帮助的结构化回答。
但越往里做,越觉得真正重要的不是让 AI 显得更像投资顾问,而是先把几个朴素的问题处理好:
- 交易事实是否完整
- 成本口径是否一致
- 卖出盈亏是否可追溯
- 分红和手续费是否被正确纳入
- 行情是否真的有效
- AI 回答能不能回到这些事实
这些事情没有模型演示那么惊艳,也不太适合做成产品宣传语。
但它们决定了一个本地优先投资工具能不能长期使用。
对我来说,StockTracker 的 AI 能力不是建立在“模型知道更多”之上,而是建立在“系统先把自己的账算清楚”之上。
账算清楚之后,AI 才有资格开始分析。