躺平挖 alpha,听起来像句玩笑话,其实是把力气花在刀刃上的一种务实选择。我自己的体会是,做投资研究这件事,绝大多数精力消耗都集中在数据整理、重复查询、格式调整这些毫无技术含量的环节上,真正需要人做判断的时间反而不多。这个系列写到第三篇,前面聊过怎么把信息源收拢、怎么搭建基础的数据底子,这篇重点说透一件事:日常工作流怎么优化,才能让你从每天机械性地产出报表、刷新行情、人工比对的状态里跳出来,把时间留给真正产生 alpha 的地方——决策本身。
这篇文章适合已经在做量化研究、或者有一两年手动投研经验的朋友。如果你刚起步也没关系,我会把每一步背后的逻辑讲清楚,你不需要照着抄,只需要理解我为什么这么安排,然后按自己的情况裁剪。
1. 先想清楚:躺平式挖 alpha 优化的到底是什么
很多人一听"躺平"就觉得是少干活或者不干活,其实不是。躺平挖 alpha 的核心不是降低投入,而是消除无效投入。我研究生时期跟着导师做项目,他有一句话我一直记着:"你每天打开行情软件的次数,和你赚不赚钱几乎没有关系;但你每天花在整理数据上的时间,和你赚不赚钱有很大关系。"当时不太理解,做了几年才慢慢品出味道。
1.1 真正的瓶颈不在盯盘,在重复劳动
我做了一个很简单的记录:连续两周,每天记录自己从早上九点到下午六点的时间去向。结果让我有点意外。一天真正花在"看策略、看持仓、思考风险"上的时间平均不到四十分钟,剩下五个多小时都耗在下面这些事情上:
- 打开四五个数据源,分别下载不同格式的行情文件和财务数据
- 把下载好的文件手动清洗、对齐、合并到一个总表里
- 刷新之前的筛选结果,看看有没有新增的符合条件的标的
- 手动跑一遍例行检查,确认持仓没有异常波动
- 把各种结果整理成不同格式的报表,发给合作伙伴或者存档
这些东西没有一样需要真正的智力投入,但每一件都在消耗注意力和耐心。更麻烦的是,一旦某个环节出了错——比如某个数据源格式改了、某个文件没下载完整——你还得花额外时间去排查。日积月累,这些琐事就像地板上的头发,每天不多,但攒一周就让人不舒服。
1.2 把工作流拆成三段来看
我习惯把投研的工作流拆成三段:数据层、信号层、决策层。
数据层管的是"信息进来",包括行情数据、财务数据、公告、行业动态,以及任何你可能用到的另类数据。信号层管的是"从信息里提炼",包括因子计算、筛选条件、评分排序、策略信号生成。决策层管的是"人真正介入的地方",包括仓位调整、风险控制、交易执行、复盘总结。
这三段对自动化的敏感度完全不一样。数据层是最适合自动化的,因为它的规则最固定、重复度最高。信号层可以部分自动化,但需要设置好逻辑边界,比如什么情况下允许策略自主筛选,什么情况下必须人工复核。决策层几乎无法自动化,也不应该自动化——你在这上面花再多时间都是值得的。
想明白这一点之后,我的优化思路就清晰了:把数据层和信号层的重复劳动压到最低,把省下来的时间和精力全部灌给决策层。这个思路,就是躺平挖 alpha 的全部秘密。
2. 数据管线自动化:把眼睛从行情软件上解放出来
数据层是整个工作流的地基,也是我这次优化的重点。每天早上打开电脑,第一件事不是看昨夜外盘、不是刷新闻,而是先把数据管线跑一遍。整个流程大概三到五分钟,全部自动完成。
2.1 数据源选型的三条原则
数据源这件事,我踩过的坑不算少。早期我同时用好几个免费数据源,以为多几个来源互相印证就不会出错,结果发现每个来源的字段定义、复权方式、停牌处理都不一样,对齐起来反而更费劲。后来我想明白了一个道理:数据源不是越多越好,而是越可预期越好。
我现在选数据源只认三条原则:
第一,更新节奏稳定。宁可晚十五分钟拿到完整数据,也不要一个数据源今天准点、明天拖两小时。稳定意味着你的调度逻辑可以写得简单,简单意味着不容易出错。
第二,字段语义清楚。有些数据源喜欢把"不复权"标成"s"、"前复权"标成"qfq",有些干脆不标。我拿到数据的第一步永远是校验字段,而不是直接丢进模型。
第三,容错机制明确。数据源挂了怎么办、接口限流怎么办、字段为空怎么办,这些都要在选型阶段就想清楚,而不是等到出问题再救火。
我主用三个数据源:行情数据走一个本地数据库,财务数据走一个结构化接口,公告信息走文本抓取。三者在功能上几乎没有重叠,各自只负责自己擅长的一块,这样即使某一环出问题,也不至于让整个系统瘫痪。
2.2 增量更新与入库的工程设计
数据管线的核心不是"全量拉取",而是"增量更新"。每天全量拉一次所有标的历史行情,既慢又浪费带宽,而且容易出现数据快照不一致的问题——比如你上午九点拉了A股一部分、下午两点拉了另一部分,两批数据的市场状态都不一样,后面用起来会有很多隐含的坑。
我的做法是分三层处理:
历史底仓一次性建立。第一次建库时,把有记录以来的全部历史数据拉下来,做一次完整的清洗和校验。这个步骤慢一点没关系,反正只做一次。跑完之后记录一个截止日期,作为后续增量的起点。
每日增量定时拉取。每天收盘后跑一次增量更新,只拉最新一个交易日的行情数据。增量数据进来之后先落到临时表,做完整性和边界校验,比如检查成交量是否为零、最高价是否大于最低价、涨跌停状态是否合理。校验通过才合并进主表,校验不通过就发警告通知。
定期全量对账。每周做一次抽样对账,拿主表和权威数据源的最新快照做交叉验证,确保增量过程中没有累积误差。我统计过,加了这一层对账之后,数据异常被发现的平均时间从两周缩短到了两天以内。
2.3 时间调度要留足缓冲
调度设计上有一个经常被人忽略的点:收盘时间不等于数据全量就绪时间。A股下午三点收盘,但盘后数据、融资融券余额、北向资金流向这些数据往往要到傍晚甚至晚上才齐。我第一版脚本设的是下午三点十分跑增量,结果连续三天报错,每次都是因为数据源还没更新。
后来我把调度时间改成了晚上七点半,用一个定时任务触发。跑完自动生成一份"数据质量日报",内容包括当天更新了多少条记录、有没有异常字段、数据时间跨度是否正常。早上起来扫一眼日报,就知道昨晚的活干得顺不顺。把错误留在夜里发生,而不是留到早上正式工作时段发生,这是我这轮优化体会最深的一点。
提示:调度任务一定要设计失败重试和最大重试次数的上限。我见过有人把重试次数设成无限,结果数据源挂了,脚本每五分钟重试一次,重试了整整一夜,第二天邮箱里堆了上百封报警邮件。别问我是怎么知道的。
3. 信号筛选与 alpha 池的日常维护
数据管线自动化之后,下一步就是信号层。这部分的核心任务是把"哪些标的值得关注"这个判断,从人工一小时一次刷新,变成一套可以每天自动跑、自动输出结果的固定流程。
3.1 两层筛选:先粗筛,再细筛
我的信号筛选是两层结构。
第一层叫粗筛,目的是把全市场四五千只标的快速缩小到几百只。粗筛条件通常是硬性的、低误杀率的,比如流动性和财务门槛。举个例子,我会要求标的日均成交额不低于某个阈值、总市值不低于某个阈值、财报数据完整且最近一期没有缺失,这些条件每一条都很粗,但合在一起能过滤掉大部分噪音。
第二层叫细筛,目的是在粗筛结果的基础上做相对排序。细筛一般是因子打分,我目前用五个维度:估值、动量、质量、波动率、资金流。每个维度算出一个标准分,然后加权求和得到一个总分,最后按总分排序取前若干名。这个总分就是 alpha 池的入场券。
两层筛选的好处是逻辑清晰、调参方便。想放宽池子的时候,先动粗筛;想让池子更聚焦的时候,先动细筛和权重。两者互不干扰,调试起来很快。
3.2 因子计算的三个细节
因子计算听起来简单,实际跑起来全是细节。我整理了自己踩过最多坑的三个点:
第一个是截面标准化。因子值在不同时间段、不同市场环境下可能会整体偏移。如果不做截面标准化,直接用历史阈值判断高估低估,很容易误判。我现在每期计算因子时都会做截面标准化,也就是先算当期全体样本的均值方差,再把每个样本的值转成相对位置。
第二个是极值处理。有些因子天生就有长尾,比如单日暴涨的标的会把动量因子的分布拉到离谱。不处理极值,一个异常样本就能带偏整个排序。我用的是分位数缩尾,把超出上下百分位之外的值拉回到边界值,保留相对排序信息,同时避免极端值过度影响。
第三个是缺失值处理。这个尤其重要。A股很多公司数据披露是不完整的,尤其是一些次新股或者业绩预告未出的标的。缺一个值就直接丢弃整行,会把大批标的误杀;用零填充,又会给模型注入一个错误信号。我现在采用的方法是:先看缺失比例,如果某个字段缺失超过三成,直接放弃这个字段;如果是个别样本缺失,用同行业同市值区间的均值填充,同时打一个标记,方便后面追溯。
3.3 alpha 池怎么日常维护
alpha 池不是建好就一劳永逸的,它需要一套日常维护机制。我的做法是每天收盘后自动跑一遍筛选逻辑,输出三份东西:新增入池名单、出池名单、池内排序变化名单。早上起来只需要看这三份名单,就知道今天的关切点应该放在哪里。
新增入池的标的需要特别留意,因为大多数策略的入场信号都始于"首次进入关注范围"。出池的标的如果还在持仓里,就要检查是不是需要调仓。排序变化名单用来感知市场风格的切换——如果池子里的标的整体从价值风格漂移到动量风格,那大概率是市场风格在变,仓位结构也需要跟着调整。
日常维护的核心不是"频繁调",而是"规律看"。我给自己定下的频率是:每天看名单,每周做一次深度复核,每月做一次因子有效性回顾。这个节奏跑了大半年,效果比之前每天五个小时手动刷新好得多。
4. 回测流程的标准化:让每次验证都可复现
信号筛选只是给出"关注什么",真正决定能不能用这个信号去交易的是回测。回测这步我曾经走过一段弯路:一开始为了方便,回测脚本里写死了很多参数,比如起始日期写死、股票池写死、佣金比例写死。结果就是每次改一个条件,整个流程要手动重跑一遍,还得用笔记记着这次改了哪些参数、上次用的什么版本。混乱程度到了什么地步呢,有一段时间我自己都不确定某张结果表是用哪个版本的脚本跑出来的。
4.1 回测版本管理:像管理代码一样管理策略
后来我把回测流程整个标准化了,核心思路就一句话:把每一次回测当成一次代码提交来对待。
具体来说,每个策略配一个独立的目录,里面包含三件东西:
- 策略逻辑文件:描述了信号生成的完整规则,包括因子定义、权重、进出场条件
- 参数配置文件:和策略逻辑分离,所有可调的参数都放在这个文件里,改参数不用动逻辑文件
- 回测结果文件:记录这次回测的各项指标,包括收益、回撤、夏普比率、换手率、胜率等
每次回测跑完,自动生成一个带时间戳的日志条目,记录当前策略逻辑文件的哈希值、参数配置的哈希值、数据快照的日期范围。这样无论什么时候回看,都能精确知道这张结果表是在什么条件下生成的。
这套做法的价值在复盘时体现得最明显。以前复盘发现某个策略效果变差了,我得想半天"当时是用哪些参数跑的";现在直接查日志,数据快照是什么日期、参数用的哪一版,一目了然。排查的效率提升了一个数量级。
4.2 回测边界条件:避免自欺欺人
回测过程中最危险的不是计算错,而是边界条件被无意识地设错了。几个我遇到过的问题:
未来函数问题。这是最臭名昭著的一类错误。比如用当日收盘后才能拿到的数据,却在当日开盘的信号里使用。我在很早的版本里犯过这个错,当时拿到的回测收益曲线漂亮得不像话,我差点就准备实盘了。后来仔细排查发现,一个资金流字段我用的是盘后数据,而信号应该用盘前可得的数据。修正之后,收益曲线立刻回到了正常水平。回测跑完之后,第一件事永远是把关键因子的时序数据图上画出来,肉眼看一眼有没有未来数据的痕迹。
手续费和滑点。回测里不设手续费,等于在无视交易成本。尤其现在换手率稍高的策略,交易成本几乎能吃掉全部超额收益。我现在回测统一用双边万几的手续费加固定滑点,滑点按标的的流动性区分。虽然这样会让回测结果难看一点,但至少结果是可实现的。
涨跌停约束。涨跌停对成交的影响比很多人想象的更大。一个信号标的如果当天一字涨停,你根本买不进;回测里如果不管这个约束直接按收盘价成交,收益就会虚高。我的流程里加入了可交易的判断逻辑:一字板不成交,非一字板按实际可成交价处理。
4.3 参数敏感性分析要常态化
很多策略的问题不在"有没有效",而在"参数稍微一改就失效",这种策略在样本外大概率也会失效。我目前对每个核心策略都会做一次参数敏感性分析:把主要参数在合理范围内做网格扫描,看绩效指标的分布形态。
如果绩效在参数空间里呈现出一个平缓的高原,说明策略逻辑本身有稳健性,参数误差不会带来灾难性变化。如果绩效在参数空间里只有一个孤立的山尖,那就说明策略是被参数硬凑出来的。后一种策略即使回测再漂亮也不值得实盘,因为数据稍微有点变化,它就会从山顶摔下来。
5. 日常监控与告警:不盯盘,但要盯该盯的东西
说完回测,再说说实盘阶段的工作流优化。很多人对量化交易有一个误解,觉得全自动跑起来之后就可以彻底不管了。我的观点是:可以不管行情,但不能不管系统。这两件事差别很大。
5.1 告警规则怎么设才不烦人
告警规则的设计直接决定你会不会"狼来了"效应。一开始我把阈值设得太敏感,系统每天发几十条通知,第二天我就麻了,看到通知根本不点开。后来我把告警分成了三级:
第一级是普通信息级。比如某只持仓标的换手率突然放大、某只候选标的新增了公告。这些消息只需要记录,不需要立即处理,汇总到每日报告里就行。
第二级是提醒级。比如持仓标的盘中触及止损线、模拟盘信号和实盘持仓出现明显偏差。这些需要当天查看,但不需要半夜爬起来处理。
第三级是紧急级。比如数据管线连续失败三次、系统检测到账户权益异常变动、实盘信号和计划信号出现不一致。这些会直接推送通知到我手机,并触发熔断机制的调用。
设置告警规则有一个原则:宁可漏报也不要误报。因为漏报顶多是错过一个机会,误报则会让你慢慢不再信任这套系统,最后连真正紧急的告警都被忽略了。
5.2 每日报告与周度复盘模板
为了让日常监控"看一眼就能决策",我给自己设计了两个固定模板:日报和周报。
日报包含五个区块:数据质量摘要、alpha 池变动、持仓与目标仓位对比、当日信号触发情况、异常告警汇总。整个日报被渲染成纯文本表格,早上花两分钟看完就可以关掉。
周报比日报深一层,包含四块:本周策略绩效回顾、因子表现与风格切换、调仓记录与执行偏差、下周关注事件与风险清单。每周五收盘后自动生成,周六上午花四十分钟做一次完整复盘。复盘时我会把日报里标记过但没处理的事项逐一过一遍,决定哪些升级处理、哪些关闭归档。
这个模板我用了很久,最大的感受是:复盘效率提升之后,策略迭代的速度也变快了。以前复盘要花半天翻各种零散记录,现在所有信息都在同一份标准文档里,对比变得异常容易。
5.3 异常情况的处理流程:预案比反应重要
市场有异常、系统有异常,这些都不是"会不会发生"的问题,而是"什么时候发生"的问题。我给自己定了一套简单的预案流程:
开盘前检查清单。每天早上数据管线跑完后,核对几个关键指标:今晚新增数据是否覆盖完整交易日、关键因子的最新值是否在正常区间、持仓标的是否有重大公告。只要有一项异常,就手动排查完再继续。
盘中熔断条件。当持仓组合的当日回撤超过某一比例,或者单一标的的波动超过历史极端水平,系统自动进入只减不增的模式。这个条件用一句大白话说就是:市场乱的时候,先保住命,再考虑赚钱。
盘后复盘触发。任何一次触发熔断或者紧急告警之后,我都强制要求自己写一份复盘记录,哪怕是三句话:发生了什么、为什么触发、下次怎么预防。这套规则让我在后来的多次极端行情里都保持了冷静,没有因为情绪化交易造成更大损失。
6. 常见问题排查与避坑实录
这套工作流跑下来,我积累了一大堆真实踩坑经验。挑几个高频问题写下来,给各位做速查。
6.1 增量更新后数据对不上怎么办
问题表现是:今天的行情数据和昨天的历史数据合并后,某些标的前后价格出现明显的断档。排查思路是:
- 先检查是不是复权方式不一致。昨天的数据是前复权,今天的数据是不复权,两者直接拼接必然出问题。这种情况把全库统一成同一种复权口径即可。
- 再检查增量更新的起始日期设置。如果昨天的底仓只更新到某个日期,而增量脚本的起始日期比它晚一天,中间就会空一天。
- 最后检查数据源的除权除息标记。配股分红日附近,价格会自然跳空,如果不做处理就会被当成异常值。
整个排查过程我已经集成到一个诊断脚本里,每次数据异常,先跑诊断脚本,十分钟内定位问题。
6.2 因子突然大面积失效怎么回事
因子失效分两种情况。一种是市场风格切换导致的暂时性失效,比如动量因子在震荡市里表现不佳,但拉长时间看仍有效。另一种是数据口径变化导致的系统性偏移,比如某数据源改了指标定义,或者财报科目做了调整。
区分两者最有效的方法是看失效的范围:如果只有一两个因子同时失效,大概率是风格问题;如果十几个因子同时普遍失效,赶紧检查数据源。我遇到过整整一周因子值全部失真,最后发现是财务数据的货币单位从"元"变成了"千元",一个单位错误让所有依赖财务数据的因子全面崩溃。
6.3 回测绩效很好但模拟盘跟不上
这个问题最常见的根源是回测用了不切实际的假设,比如按收盘价无限成交、不计算冲击成本、信号生成与实际下单之间存在不可忽略的延迟。解决办法是把回测改成"按下单时点之后的下一个周期可成交价"来计算,同时引入成交量的百分位作为成交可行性判断。
另外一个容易忽略的点是信号更新频率。回测里按分钟级信号生成的频率,实盘里如果策略只按日级频率执行,就必然产生偏差。回测和实盘的时间粒度必须对齐,不能一个按分钟、一个按天。
6.4 告警太多导致系统被忽视
前面说过,告警设计要宁少勿多。如果你发现告警通知已经变成了"每天固定打卡"式的存在,建议做一次大清理。我的办法是做一个"告警日志价值度"评估:每周五检查这一周所有告警,标记哪些告警是有价值的(帮你发现了真正的问题),哪些是噪音。连续三周都是噪音的告警规则,直接删除或者提高阈值。
清理完告警之后,有一个正面副作用:因为告警数量变少,每一条进来都会引起足够重视,系统的可信度反而提升了。
7. 这套优化做完之后,我的实际体感
最后说一点切身的感受。这套工作流优化前前后后花了大概三周的时间,大部分工作量集中在数据管线重构和回测流程标准化上。改完之后,我在工作上的日常节奏发生了非常明显的变化。
以前每天上午基本是在"开软件、导数据、做表格、发文件"中度过的,等这些都忙完,已经十一点多了,才勉强挤出半小时看策略。现在的节奏是早上八点半前收到数据质量日报和 alpha 池变动名单,九点前完成当日操作计划,剩下的时间全部用来做真正的投研工作:思考当前市场环境下策略逻辑是否依然成立、看看有没有值得纳入体系的新信号、做深度的组合风险分析。
如果要给一点建议,我认为最重要的不是工具选得有多高级,而是先把自己的时间账算明白。花一周时间记录一下你每天的工作时间都去哪了,把那些低认知密度、高重复度的环节找出来,优先解决它们。工具只是手段,省出时间去思考,才是躺平挖 alpha 真正的内核。
这套系统现在还在持续迭代。数据源偶尔还会换、因子池子偶尔还会调,不过骨架已经比较稳定了——数据自动化采集、信号分层筛选、回测标准化、监控分等级,四条线各司其职。下一步我打算把文本类的信息源也做进数据管线,把公告、研报、新闻的情感信号自动化起来,等跑一段时间再写一篇复盘。如果你也在这个方向摸索,欢迎留言交流各自的细节。