把一份 Excel 数据库复刻成一个能跑的东西
一、一张没人敢动的表
研究员的电脑里通常躺着几张这样的表。打开是一排子表,第一张写口径说明,第二张是取数区,再往下是历史数据,最后一张是模型输出。需要的东西都在里面,但它已经很久没人动过——不是不好用,是没人敢改。改一条公式要顺着引用一路看下去,改一个阈值不知道会影响哪几个结论。
这类表最值钱的地方,恰恰是它最不方便的地方:口径是活的。什么时候换过基准、哪一年把窗口从三年改成五年、某个格子的数字是从别处抄来的,全都留在公式和批注里,没写进任何文档。研究员可能会忘,公式不会忘。
所以当我想把一张表变成一个可以被调用、被核对的东西时,第一件要做的事不是重写,而是考古。
二、先解剖,不要先写
最早的冲动是照着自己的记忆写一套代码,算出来差不多就行。这条路试过一次就放弃了:结果跟表里差一点,而我说不清差在哪里。
后来反过来做。先用只读的方式把工作簿拆开,抽出每一个公式、每一个坐标、每一段批注、以及引用关系,落到一份结构化的中间文件里。这一步不允许猜测,脚本只读文件,读到什么是什么。接着把这份文件压成一份人能读的解剖报告:哪张子表是输入、哪张是公式、公式分成几组、跨表引用指向哪里。
拿到报告之后再动手,性质就变了。之前是「我大概记得是怎么算的」,现在是「第几行第几列的公式引用了哪几个格子」。考古的纪律是:能落到公式和值层上的,就不靠回忆。
三、数据、逻辑、判断
解剖报告摆出来,一张表其实会自然而然地裂成三层。
最下面一层是数据。取数区那张子表里,一个期限一行、一列一种曲线,这些数字不是算出来的,是从别处搬来的。它们的口径属于取数,不属于模型。
中间一层是逻辑。把上面的数字变成结论的那些公式:做差、取分位、算周度变化。这一层是确定的,给定输入就只有一个答案。
最上面一层是判断。阈值定在哪里、什么幅度算异常、什么情况必须先停下来问一句。这一层在表里通常只占几个格子,却是整张表真正属于作者本人的部分。
有意思的是,另一条路上做出来的一套工具,最后也收敛到同一种切法:输入一层,计算一层,阈值另存成一份规则文件,三者分开放。两条路的出发点并不一样,切出来的边界却一样,说明这不是某种实现偏好,而是这件事本来就这么长。
拆开的好处不在整齐。改一条公式不动阈值,调一个阈值不用回头动公式——这句话听着平淡,但如果三层是焊在一起的,你能改的就只有整张表,而那等于不能改。
四、不能猜的四件事
考古过程中最容易犯的错,是把「看起来像」当成「就是」。有四件事必须在动手之前问清楚,问的是写表的人,不是我自己的直觉。
一是分位数的历史窗口:近三年还是近五年,含不含当期,按月滚动还是逐日。这一项几乎每张含分位的表都会命中,而且窗口差一年,结论就可能从偏紧翻到中性。
二是基准:绝对利差对的是国债还是国开债,哪个期限段。表格里往往只写「利差」两个字。
三是时间锚点:周度变化是本周五比上周五,还是比上周最后一个交易日;碰到节假日怎么处理。
四是曲线口径:行权收益率还是到期收益率。这一条最隐蔽,公式里看不出来,只能看表头或问人。
这四件都不是技术问题,是口径问题。写代码的人永远猜不出来,也不该猜——猜错的结果不是报错,是算出一个看起来很正常、实际上不是你要的数字。
五、对账这件事
复刻完不算完成,对账通过才算。
做法很朴素:把表里已经算好的真值抽出来,与复刻程序跑出来的结果逐点比。为此要先准备好真值,最稳的是让 Excel 自己重算一遍并存成副本,这样真值就是公式在原始环境里的产物,而不是我读缓存读出来的东西。
对账跑下来,利差和周度变化两类对得干干净净,问题出在历史分位上,差在小数点后第三位。原因是那个分位函数有个控制有效位数的参数,默认给的是三位,表格里显示的也是三位,而我的复刻端用了全精度。这个差异本身不重要,重要的是它暴露了一件事:显示精度和计算结果是两回事,对账必须比到比显示更深的地方。
把参数显式调到全精度再跑,两边对到小数点后十二位。到这一步我才可以说迁移完成了,因为这不是「我觉得对了」,是一个可以重跑的检查通过了。
六、几个反复出现的小坑
第一类是手工覆盖。同一列公式中间,总会有一两个格子是硬填的数字。最常见的例子是「上周五的值」:它不是算出来的,是上周五收盘后有人手工贴进去的。程序在编译时必须把这种格子识别成输入而不是计算,否则每天都会重算一遍,跟人工维护的那个值打架。识别方法也简单,整列都是公式,只有它是常数,那就问一句。
第二类是插件公式链。取数区很多时候不是静态数值,而是一串数据插件的公式,打开表格时才去拉数。这一层不能硬塞进复刻程序里。正确的做法是先把它落成确定的值,或者接上自己的数据源,让复刻程序只面对一张干净的输入表。
第三类是幽灵依赖。一条口径用到了某个输入,但这个输入没有写进输入清单,程序换到别人机器上就跑不起来,而报错的地方通常离真正的原因很远。规则只有一条:没有写成契约的输入,等于不存在。
七、从哪张表开始
不要挑最重要的那张表,挑最小的那张。
最小的表通常三五张子表、一条公式、两三个阈值。它足够小,可以在一个下午走完解剖、复刻、对账三步;也足够真,能让你在第一次对账失败时,真正看清问题出在口径而不是代码。
一张表跑通之后,第二步不是去做更复杂的表,而是把三层分开放的做法固定下来。表会越来越多,公式会越来越多,唯一不会膨胀的是那几条真正属于你自己的判断——它们通常只有十几行。
把一张表复刻成能跑的东西,尽头不是让机器学会算,是让那些原本只存在于公式和记忆里的口径,第一次变成一句可以被追问的话。
文中观点仅为个人实践观察,不构成任何投资建议。