我的资产散在四个地方:汇丰香港的美元账户、ZA Bank 的定投、嘉信的零碎持仓、支付宝的基金。以前每笔都要手抄进 Ghostfolio,抄到第三个月开始出错——份额对不上、股息漏记、手续费想不起来记多少。
先试”正规接口”,四条路全堵
第一反应是找 API。花了一个下午查官方文档,结论很干脆:
- 汇丰香港、ZA Bank:开放接口只对持牌第三方服务商(TPP)开放,个人拿不到凭据;
- 支付宝:开放平台的资金接口属于”商家转账”产品线,要经营主体资质,而且只返回余额三个数,没有基金持仓;
- 招商证券:只有券商版的量化终端,门槛几十万;
- 嘉信:Trader API 个人可以申请,但国际账户注册不了开发者应用。
所以只剩一条路:解析对账单。好在两家的月结单都是电子版、有文本层,而且出单日固定——汇丰每月 22 日,ZA 每月最后一天。
结单里其实什么都有
每家给我两种结单,一开始我只用了投资那张:
- 汇丰:
投资服务综合结单(持仓、交易、股息净额)+HSBC One 户口结单(存款、定期、投资市值,还带一个”净头寸”合计) - ZA:
投资月结单(持仓、交易、股息)+综合月结单(港元活期、外币、钱罐的每一笔流水)
后来发现第二张才是关键。ZA 的综合结单里有这么一行:
03 Sep | Regular-Invest Platform Fee Refund 定投平台费费用返还 | QQQM | <小额>
定投扣的那笔小额平台费,第二天以现金形式还回来了。我之前一律把它记成手续费,等于每个月虚增了一笔支出。而同样是买股票,手动买入的那笔从来不返还——这条规则写在结单里,但只写在综合结单里。
一个”空白输出”的教训
解析用 PyMuPDF。中途我想用 pdftotext 快速验证,拿到的是空白,差点得出”这两份是扫描版、得 OCR”的结论。实际是那台机器上根本没装 poppler——命令不存在,输出为空,而我把它当成了”文件里没有文字”。
这类错误很难自查:空白既可能是”没内容”,也可能是”工具没跑”。后来我给所有探测脚本都加了一句”工具存在性检查”,宁可报错也不要空。
版式的坑比逻辑多
真正花时间的不是对账逻辑,是 PDF 的文本层:
- ZA 的标的名称会折行,
Invesco纳斯达克100和ETF分成两行。取值逻辑遇到不认识的行就停,于是整条持仓被静默跳过。 - 交易描述里的
BUY本身长得像股票代码,被当成 ticker 抓走,结果所有交易的标的都成了 “BUY”。 - 最坑的是分组标题的位置。结单里外币段(Foreign-Currency Savings)的标题在文本层里被排到了港元流水的中间。我按标题切分组算余额,算出来的数是某个中间时刻的港股活期余额,不是外币余额。
最后放弃按分组推算,改用结单自己给的权威口径:Deposit Summary → Closing Balance 本期结余。它已经把三个账户折算成港元等值加总好了。
校验不过就中止
上面那次取错数,我第一版脚本只是打印了一行警告,然后照写不误——结果把一个中间时刻的余额当成了期末余额,差了两个数量级。
后来改成硬规则:分项加总的和必须等于结单上「本期结余」,差一分钱就 raise 退出,不写库。外币原币余额还要用港币等值反推汇率做合理性检查——汇率落在常识区间之外,就说明取错了数。写错一个数比少记十笔更麻烦,因为账本一旦不可信,后面所有分析都白做。
对账结果
跑完全部九份结单,结论是:
- 汇丰完全对得上:两个标的的份额、几笔交易、两笔股息,净额与结单分毫不差;
- ZA 漏了二十几笔:全是碎股定投(不足一股、单笔个位数金额那种),当时嫌小没记,累积起来竟是七个标的;
- 税率不一样:ZA 预扣 30%,汇丰按税务居民协定只扣 10%。同样一笔美股股息,两家到手差两成。
补记之后,持仓份额与结单逐个对上,交易笔数两边一致。
最后交给自己动的部分
现在每个月有两件事自动发生:1 号提醒我下 ZA 的结单,23 号提醒我下汇丰的,提醒里附带”当前最新是哪一份”,一眼看出自己落后多久。我把文件放进对应目录,第二天早上脚本自己解析、对账、补记,把结果推给我;没有新文件就安静着。
这件事的收益不是省下抄写的那几分钟。是账本终于可信——问它一句”我这半年到底赚了多少”,它答的数字有出处。