清晨六点半,宝安区老老旧小区的书房窗帘缝隙透进微光。
林晨比闹钟早醒了十分钟。他习惯性地先摸过手机,解锁,点开券商App——这个动作已经成为他失业以来每日清晨的固定仪式。
账户总资产:87,432.51元。
他的手指在屏幕上停顿了两秒,又仔细看了一眼昨日收益:+2,186.33元。
这是“启明智投一号”系统运行最近一周以来,单日收益再次突破两千元。林晨靠在床头,深深吸了一口气,又缓缓吐出。屏幕上跳动的数字不再是冰冷的数据,而是某种实实在在的证明——证明他过去三个月在AI和量化领域投入的数百个小时没有白费,证明那条通过技术实现财务自主的道路,并非虚幻的空中楼阁。
但他很快冷静下来。最近A股震荡,昨天创业板指数涨了1.8%,系统抓住了一波小行情而已。量化交易最忌讳的就是把短期波动当成能力。他关掉App,起身洗漱。
上午的学习计划是精读一篇关于transformer模型在时间序列预测中应用的论文。但九点钟刚过,Github的邮件通知就跳了出来——他的开源项目“quant-data-utils”仓库收到了一个新的Issue。
林晨点开链接。
Issue标题是:“使用tuShare数据源时,获取日线数据报错‘KeyError: ‘price’’”。
提交者Id:StockquantNewbie。
问题描述写得很详细,附上了代码片段和完整的报错信息,最后还客气地加了一句:“我是量化新手,正在学习您的工具库,这个问题困扰了我两天,如果是我用法不对还请指教”。
林晨仔细看了代码。问题其实不复杂:这位新手直接调用了工具库里的get_daily_data函数,但没注意到tuShare的免费接口最近调整了返回数据的字段名,原来的price字段改成了close。工具库里的数据清洗模块还没来得及适配这个变动。
他想了想,没有直接回复代码修改方案,而是先敲了一行回复:“感谢使用和反馈!这个问题是由于数据源ApI变动导致的。请先尝试以下临时解决方案——”
他给出了两行修改代码的建议,可以暂时绕过这个问题。
然后他继续写道:“我今天会发布一个v0.2.1版本,在数据清洗模块中添加对最新tuShare接口的适配。另外,建议您在调用时始终检查返回数据的列名,这是处理外部数据源的好习惯。欢迎继续提问”。
点击提交回复。
几分钟后,Issue页面下出现了新的评论:“太感谢了!临时方案有效!原来是这样,我明白了。期待新版本”!
林晨看着那句“我明白了”,嘴角不自觉上扬。这种通过代码帮助到具体某个人的感觉,比单纯看到Star数字增长更实在。他关掉Issue页面,立刻开始在本地代码库中修改数据清洗模块,测试,然后提交更新,打上v0.2.1的标签,推送到Github。
做完这些,他才重新回到论文上。但注意力已经有些分散了。
干脆,他打开了项目仓库的主页。Star数:73。Fork数:21。比昨天又涨了几个。他点开Insights标签,查看流量数据——过去一周有来自美国、新加坡、甚至德国的访问。一个小小的数据工具库,正在被世界不同角落的开发者看到。
中午简单煮了碗面条,林晨一边吃一边刷着Github的通知。除了那个Issue,他还收到了两条新的“watch”(关注)通知,以及一条来自用户“quant-lover”的私信。
私信内容是英文的:“hi, I found your quant-data-utils project very clean and practical. Im working on a crypto quantitative strategy and wondering if you have plan to add support for crypto exchanges like binance or coinbase? If not, I might be able to contribute a module.”
(你好,我发现你的quant-data-utils项目非常简洁实用。我正在研究加密货币量化策略,想知道你是否有计划添加对币安或coinbase等交易所的支持?如果没有,也许我可以贡献一个模块。)
林晨读完,放下筷子。加密数字货币……这确实是当前量化投资的热门领域,但他自己之前主要精力放在A股和传统期货,对这块研究不深。他斟酌了一下措辞,用英文回复:“thank you for your interest! currently the project focuses on traditional financial markets (A-shares, futures). Support for crypto exchanges is a great idea and definitely within the roadmap. Im not very familiar with crypto ApIs, so a contribution would be highly appreciated. You can open an issue first to discuss the design, or directly create a pull request. Looking forward to it!”
(感谢你的关注!目前项目专注于传统金融市场(A股、期货)。支持加密货币交易所是个很好的想法,也符合路线图规划。我对加密货币ApI不太熟悉,所以非常欢迎贡献。你可以先开一个Issue讨论设计,或者直接创建一个pull Request。期待你的贡献!)
回复完,他感觉有点奇妙。一个在鹏城出租屋里失业的中年码农,正在和可能身处世界任何地方的开发者,用英文讨论着一个开源项目的特性扩展。这种连接感,冲淡了独自学习的孤独。
下午,他继续研究论文,同时分心关注着Github。果然,“fintech-dev”——那位提交了第一个pR的贡献者——又出现了。这次他提交了一个新的pR,优化了项目REAdmE文档中的安装说明,添加了更清晰的pip安装步骤和常见错误排查。
林晨点开代码变更查看,改动虽小但很贴心。他点了合并,并在pR评论区留言:“Nice improvement, thanks again!”(很好的改进,再次感谢!)
几乎同时,他收到了“fintech-dev”的私信,这次是中文:“维护者你好,看到你合并了pR。我注意到你项目里用了pytorch做简单的特征工程,最近我在尝试用Graph Neural Network(图神经网络)建模股票关联性,如果你有兴趣,我们可以交流一下”。
Graph Neural Network(图神经网络)?林晨心里一动。这是深度学习里相对前沿的领域,用于建模关系数据。用GNN来挖掘股票之间的隐藏关联,构建更复杂的因子——这个想法很有吸引力,也超出了他目前的知识范畴。
他立刻回复:“非常有兴趣!GNN我还没深入学过,但一直想了解在量化中的应用。你方便分享一些学习资料或者简单的思路吗?或者,我们可以约个时间线上聊聊”?
对方回复很快:“我整理一下资料,晚点发你Github邮箱。线上聊也可以,我平时晚上九点后有空”。
“好,那我等你邮件”。
结束对话,林晨靠在椅背上,望着电脑屏幕。窗外传来远处马路隐约的车流声,屋内只有主机风扇的低鸣。但此刻,他感觉这个小房间不再封闭。通过网线和代码,它连接着一个活跃的、专业的技术社区。这里有遇到问题的新手,有提出建议的同好,有默默贡献代码的伙伴,还有愿意分享前沿知识的探索者。
这种被需要、被认可、被连接的感觉,与他之前在跨境电商公司里日复一日写业务代码、应对产品经理需求变更的感受截然不同。在那里,代码是工具,是任务,是KpI的一部分。而在这里,代码是作品,是桥梁,是对话的语言。
他忽然想起知乎上“算法手艺人”说过的话:“开源不只是把代码扔出去,而是打开一扇门,让同道中人走进来”。
门,似乎真的打开了。
傍晚,苏婉接乐乐放学回来。小家伙一进门就嚷嚷:“爸爸!我今天算术得了小红花”!
林晨抱起儿子转了一圈:“真棒!晚上让妈妈给你加个鸡腿”。
吃饭时,苏婉看着林晨时不时瞥向手机屏幕的样子,轻声问:“今天学习还顺利吗?看你好像有心事”。
林晨放下筷子,笑了笑:“不是心事,是……有点新鲜事”。他把今天Github上收到Issue、和国外开发者交流、还有“fintech-dev”提出讨论GNN的事情简单说了说。
苏婉听得很认真,末了点点头:“挺好的。感觉你最近状态比刚失业那会儿好多了,没那么焦虑了”。
“嗯,找到点节奏了”。林晨给乐乐夹了块排骨,“而且‘启明智投一号’昨天表现不错,赚了两千多”。
苏婉眼睛微微一亮:“真的?那……能稳定吗”?
“不敢说稳定”。林晨摇头,“市场千变万化,系统还需要更多考验。但至少证明这条路能走通,这很重要”。
夜里十点,乐乐睡了。林晨坐在电脑前,收到了“fintech-dev”发来的资料压缩包和一个在线会议链接。他点开资料,里面是几篇关于GNN在金融领域应用的论文pdF,还有一个简单的示例代码项目。
他正浏览着,电脑右下角又弹出一封新邮件通知。发件人邮箱后缀是“@talent-hunter.”,标题是:“Regarding your Github project - quant-data-utils”(关于您的Github项目 - quant-data-utils)。
林晨的心跳,莫名快了一拍。