屏幕那头的面试官——王磊口中的李工——看起来四十出头,戴着黑框眼镜,头发有些稀疏,但眼神锐利。他没有开摄像头,只有一个简单的t厂logo虚拟背景,声音透过耳机传来,清晰而沉稳。
“林晨,你好。王磊已经跟我简单沟通过,你的算法能力和项目经验给他留下了很深印象”。李工开门见山”,尤其是你那个量化投资系统,我看了他记录的要点,有几个地方想深入聊聊”。
林晨坐直身体,调整了一下麦克风位置:”李工您好,您请问”。
“先从最基础的开始”。李工的声音听不出情绪,“你说你的系统覆盖A股、基金、期货、期权、黄金、外汇多个市场。数据源怎么解决?不同市场的数据频率、格式、时区差异巨大,你的数据管道是怎么设计的”?
来了。林晨深吸一口气,这问题直指系统基建的核心。
“数据管道分三层”。他语速平稳,思路清晰,“最底层是数据采集层,针对不同市场用了不同的策略。A股和国内期货用tushare和聚宽ApI,配合自写的爬虫做补充和校验;外汇和黄金用mt5的接口,通过python的metatrader5库对接;期权数据比较复杂,用了上交所和深交所的官方数据接口,加上第三方数据商的补充”。
他顿了顿,看到屏幕上李工的头像没有动静,便继续道:“中间是数据清洗和标准化层。这里我写了一套统一的时序数据处理框架,把不同频率的数据(tick级、分钟级、日级)通过插值和重采样统一到分钟级基准上。时区问题统一转换为Utc时间戳,再根据交易时间映射到本地时间。格式差异通过定义统一的数据模型(open, high, Low, close, Volume等字段)来解决,每个数据源接入时都要实现一个适配器”。
“第三层是数据存储和更新层。原始数据存parquet格式,处理后的特征数据存Feather格式,方便快速读取。更新机制是增量+全量结合,实时数据通过消息队列触发处理,盘后做一次全量校验和修复”。
李工沉默了几秒,然后问:“数据质量怎么监控”?
“有三重监控”。林晨早已把这些问题在心里复盘过无数遍,“一是采集过程监控,记录每个ApI调用的成功率、延迟、数据完整性;二是数据本身监控,检查缺失值、异常值(比如价格跳变超过阈值)、逻辑错误(比如最高价低于最低价);三是业务层面监控,比如某个标的突然长时间没有交易数据,会触发告警。所有监控日志都接入ELK栈,有问题能快速定位”。
“嗯”。李工应了一声,听不出是满意还是不满意,“那特征工程。你说系统用了上百个特征,怎么避免过拟合?怎么处理特征之间的多重共线性”?
这个问题更深入了。林晨感觉手心微微出汗,但大脑却异常清醒。
“特征筛选是分阶段进行的”。他组织着语言,“首先在单因子测试阶段,我会计算每个特征与未来收益率的Ic(信息系数)、IR(信息比率),剔除统计意义不显着的特征。然后进入多因子组合测试,用LASSo、Ridge这类带正则化的线性模型做初步筛选,惩罚项系数通过交叉验证确定”。
“对于多重共线性,除了用VIF(方差膨胀因子)检测,更重要的是从业务逻辑上理解特征。比如动量类特征和反转类特征天然有对冲关系,我不会简单剔除其中一个,而是考虑构建复合特征,或者在不同市场状态下启用不同的特征集。另外,我用了滚动窗口的方式动态评估特征重要性,每隔一段时间重新筛选,避免特征失效导致模型退化”。
李工追问:“具体用了哪些模型?为什么选择这些模型?集成策略是什么”?
林晨知道这是关键展示环节。他调出事先准备好的几张架构图(当然只是口头描述),开始详细阐述。
“模型分三层。第一层是基础预测层,包括xGboost、LightGbm、随机森林这类树模型,主要捕捉非线性关系和特征交互;还有LStm、GRU这类时序模型,捕捉序列依赖;以及一些简单的线性模型作为基准。每个模型独立训练,预测标的未来N个时间单位的收益率方向或幅度”。
“第二层是元模型层。用第一层各个模型的预测结果作为输入特征,训练一个Stacking集成模型。这里我尝试过逻辑回归、简单神经网络和另一个xGboost作为元模型,最后发现xGboost效果最稳定。这一层的作用是学习不同基础模型在不同市场环境下的权重”。
“第三层是决策融合层。这里不完全是模型了,而是一套规则引擎。它会考虑当前市场状态(趋势市、震荡市、高波动市)、资产相关性、仓位限制、交易成本等因素,对元模型的输出进行最终调整,生成具体的交易信号:买、卖、持有、观望”。
李工突然插话:“回测怎么做的?有没有考虑幸存者偏差、前视偏差、交易成本”?
“回测框架是自己写的,基于向量化回测思想,但加入了逐笔模拟”。林晨回答得很快,“数据用了全市场历史数据,包括已经退市的股票,避免幸存者偏差。所有特征计算严格只用历史数据,绝不用未来信息,防止前视偏差。交易成本考虑了佣金、印花税、滑点——滑点模型是根据历史交易数据拟合的,不同标的、不同时间段滑点率不同”。
他补充道:“回测分样本内和样本外。样本内用于调参和模型选择,样本外用于最终验证。我还做了滚动窗口回测,把整个历史时期分成多个滚动窗口,每个窗口内部分训练集和测试集,评估模型在不同时期的稳定性。最终夏普比率在1.5到2.0之间,最大回撤控制在15%以内,年化收益在20%到35%区间——当然,这是历史回测数据,实盘运行半年,年化大约25%,最大回撤12%,基本符合预期”。
李工似乎点了点头(林晨从声音里听出了一丝微小的变化):“实盘和回测的差距怎么解释?怎么持续优化”?
“差距主要来自几方面”。林晨坦诚道,“一是市场结构变化,历史规律不一定持续;二是实盘交易的心理因素和执行力问题,虽然我尽量自动化,但有些风控规则需要人工确认;三是数据延迟和系统故障等实盘特有的问题。优化是持续的过程:每周我会做一次绩效归因,分析盈利和亏损交易的来源;每月做一次模型重校准,用最新数据微调参数;每季度做一次架构评审,考虑是否引入新特征、新模型”。
“另外”,林晨想起一个重要的点,“我建立了一个‘错误案例库’,记录每次实盘中出现预期外亏损的交易,分析原因,如果是模型问题就针对性修复,如果是市场突变就作为压力测试案例加入回测”。
长达二十多分钟的技术追问,林晨几乎没有任何卡顿。每一个问题,他都能迅速拆解,从设计思路到实现细节,从理论依据到实战反馈,条理清晰,数据翔实。这半年日夜钻研、实盘打磨积累下来的东西,此刻如泉水般自然涌出。
李工终于停顿了更长的时间。林晨能听到那头轻微的键盘敲击声,似乎是在记录什么。
“最后一个问题”。李工的声音依然平稳,但林晨隐约感觉,语气里多了一丝……兴趣?“你这个系统,从技术角度看,最核心的创新点或者最独特的价值在哪里?如果让你用一句话总结”。
林晨没有立刻回答。他闭上眼睛,半年来无数个深夜对着屏幕调试代码、分析图表、复盘交易的情景在脑中闪过。那些亏损时的焦虑,盈利时的谨慎,突破瓶颈时的兴奋,最终沉淀为一种笃定。
“最核心的价值在于”,他睁开眼,看着屏幕上那个代表李工的虚拟头像,“它不是一个黑箱魔法,而是一个可解释、可迭代、可适配的决策辅助系统。我不追求预测市场的圣杯,而是用工程化的方法,系统性地捕捉市场在某些特定状态下存在的、微弱的统计规律,并通过严格的风控让盈利概率略高于亏损概率,长期累积成优势。它是我理解市场、理解AI如何与复杂现实世界互动的一个实验场”。
说完,林晨屏住呼吸。
耳机里安静了足足五秒钟。
然后,李工的声音传来,似乎比之前快了一点:“明白了。今天的面试就到这里。后续hR会联系你”。
“谢谢李工”。林晨礼貌回应。
视频会议断开。
林晨靠在椅背上,长长地吐出一口气。后背的衬衫已经有些湿了。他回想刚才的每一个问题和回答,仔细复盘,确认没有重大疏漏。李工的问题确实刁钻,直指要害,但好在都是他亲身实践、反复思考过的东西。
他看了一眼时间,面试持续了四十五分钟。比一面还长。
手机震动了一下,是苏婉发来的微信:“怎么样?结束了吗”?
林晨回复:“刚结束,感觉……还行。李工问得很深,但我都答上来了”。
苏婉秒回:“那就好!晚上想吃什么?说好了要庆祝的”。
林晨想了想,打字:“简单点吧,有点累。买点熟食,再炒个青菜就行”。
“好。乐乐说想你了,今天特意画了幅画,等你回来看”。
看着屏幕上的字,林晨嘴角不自觉扬起。无论外面的世界如何风云变幻,家里总有一盏灯,一份简单的温暖在等着他。
他站起身,走到窗边。下午的阳光透过玻璃洒进来,落在客厅地板上,暖洋洋的。鹏城的天空难得湛蓝,远处腾讯滨海大厦的玻璃幕墙反射着耀眼的光芒。
这次面试,应该……有希望吧?
李工最后那句“后续hR会联系你”,是标准结束语,还是某种积极的暗示?他无法确定。但至少,他没有被问倒。他把自己这半年沉淀的东西,完整地、清晰地展示给了t厂AI部门的技术负责人。
这就够了。
剩下的,交给命运。
他转身走向厨房,准备烧壶水泡茶。等待水开的时候,他下意识地打开手机上的券商App,看了一眼实盘账户。
今日盈亏:+2,347.86元。
持仓市值:286,532.41元。
累计收益:+86,532.41元。
那串数字安静地躺在屏幕上,像是一种无声的证明。证明那些孤独学习的夜晚,那些反复调试的代码,那些面对市场波动时的坚守,都没有白费。
水壶发出嗡鸣,水开了。
林晨泡好茶,端着杯子回到客厅,在沙发上坐下。疲惫感渐渐涌上来,但心里却有一种奇异的踏实。
他知道,无论这次t厂的面试结果如何,他已经不再是半年前那个被裁员后茫然无措的中年码农了。
他有了自己的武器。