有些写着:deprecated(因为绩效衰减,已被淘汰的因子)。
有些写着:rged(因为与其他因子相关性过高,被合并的因子)。
有些写着:deleted(被删除的因子)。
还有一批,令人触目惊心地写着:unknown(未知状态,连研究员自己都不知道这东西还在不在跑)。
江临的目光在deleted和unknown这两个词上停留了很久,思绪一下子发散开来。
在任何一个量化机构,乃至任何一个科研系统里,成功的东西,总会有人记得。
它们会被写进PPT,会被挂在年报里,会被用来向投资人吹嘘。
但是,失败的东西,常常最先被删掉。
研究员为了掩盖自己几个月毫无建树的尴尬,或者为了让代码库看起来干净,会毫不尤豫地按下Delete键。
而一个没有失败记录的研究系统,最容易把幸存者当成真理。
在金融市场里,这叫幸存者偏差。
当你只看到那些成功的策略时,你会觉得市场充满规律。
江临深吸了一口气,熟练地打开终端,新建项目文档夹。。
第一行:旧因子库首先不是宝库,而是失败记录的墓地。
第二行:本项目不找神因子,不预测未来,只找“研究流程如何骗过自己”。
第三行:所有结论必须严格绑定四个维度:数据版本、样本池版本、因子版本、回测配置版本。脱离版本谈绩效,一律视为学术造假。
写完这三行,他才正式开始第一轮代码层面的扫描。
最初的审计脚本逻辑并不复杂。
江临用Python配合Pandas和Dask,写了几个守卫器。
唯一性检查: 检查因子编号是否唯一,版本号是否连续,每个因子是否严格绑定了当时所用的清洗数据版本。
样本池漂移: 每个回测结果是否绑定了确定的样本池定义?
失败记录完整性: 失败因子有没有保留详细的删除原因和失效日期的环境切片?
同源性检查: 同名或近似同名因子是否重复出现?
摩擦成本检查: 交易成本假设有没有在不同版本里发生人为的漂移?
回车,运行。
十五分钟后,第一轮扫描结果出来了。很难看,触目惊心的难看。
四百三十七个因子里,有八十多个没有完整的数据版本号约束。这意味着如果现在重跑回测,根本不知道当初是用什么数据跑出来的。。
十三个因子名称完全不同,但备注里的数学逻辑高度相似。
还有几个因子,名字看起来象是三个截然不同的方向。。
说明这根本就是同一类想法,在绩效压力和流程失控里被反复复制、微调参数、改名重跑,试图碰出一个更好看的夏普比率,最后在历史里留下了三具极其相似的影子。
这就是纯粹的数据挖掘灾难。
江临面无表情,继续跑第二轮:因子输出版本敏感性测试。
第三轮:样本池时间串行漂移测试。
第四轮:失败因子记录完整性穿透。
随着任务越来越重,工作站脚下的机箱风扇开始持续低鸣,发出沉闷的嗡嗡声。
江临瞥了一眼副屏上的系统监控。
硬盘读写:正常。
内存占用:正常。
CPU 占用率,却
程序并没有卡死,终端里的进度条还在走。
但它比江临预期的慢,慢得非常不合理。
对于现实世界里的大多数数据科学家或者量化研究员来说,遇到这个情况,第一反应绝对是,机器不够强。
“老板,我们要买更好的 CPU,换 AMD 的线程撕裂者。”
“要加更大的内存,把数据全塞进内存里。”
“上AWS云服务器,开个 124 核的实例并行跑。”
用硬件的暴力去掩盖软件的低效,这是和平年代,资源充沛环境下的通病。
但这不是江临的第一反应。
在他的脑海深处,那个属于【废土世界】的倒计时始终存在。
在资源枯竭的废土里,永远没有再买一台的选项。
在那里,机器慢,不能先要资源,必须先问。为什么慢?是什么在吃掉算力?
打开Python的性能分析工具,将刚才那段跑得极慢的代码用cProfile 重新包起来,然后接入SnakeViz进行可视化分析。
二十分钟后,一份详细的调用栈火焰图出现在屏幕上。