
做量化金融研究最怕的不是模型不赚钱而是跑了几个月之后连自己都说不清某个因子当初是怎么算出来的。你说你做了三个月因子挖掘手上攒了七八十个脚本每个都能跑出数字可一旦要把它们摆在一个库里统一管理问题全出来了复权方式不统一停牌处理靠记忆行业分类换过版本同一个动量因子在两个文件里能算出两个IC。这个时候才意识到因子阶段真正该收官的不是“我又试了多少个想法”而是能不能把从数据流到因子库这条链路稳稳地搭起来。我最近在整理自己的量化研究框架正好走到因子阶段收官的节点。想借着这篇文章把从数据流到因子库的思考、流程、踩坑和工程化路径完整梳理一遍。我的核心判断很简单因子阶段有没有收官不看因子的数量看数据管不管得住、因子算不算得清、结果能不能复现。这三件事全部落地手上的代码和表格才能从“临时研究”变成“长期资产”。1. 因子阶段收官先别急着数收益率很多人做量化到一定阶段会陷入一种奇怪的焦虑总觉得因子不够多模型不够复杂回测曲线不够漂亮。于是不停加参数、换窗口、试新数据。但真正让研究停下来的往往不是“找到了圣杯”而是“跑不过来了”因为每次新想法都要从拉数据、清洗、对齐开始大量时间耗在重复劳动上。1.1 单次跑通只能说明流程没断因子研究的起点通常是从一个简单想法开始。比如“过去20天涨幅高的股票未来5天会不会继续涨”然后你写几行代码拉一段行情算一个动量因子再算一下IC数字出来了还挺好看。但这一步只能说明流程没断不能说明因子有效。这里的差距在哪里在于单次跑通时你使用的可能是某一时间段、某一种股票池、某一种复权方式下的结果。换一个时间段换一套行业分类或者把停牌处理方式从“填充前值”改成“剔除样本”同一个因子的表现可能完全不同。所以单次跑通只是开始不是阶段完成。1.2 因子阶段的交付物应该是一套可复用的资产当研究积累到一定程度你需要的不是更多因子脚本而是一个能够承前启后的结构。我理解的“从数据流到因子库”就是把散落在脚本里的因子逻辑逐步抽象成一套可复用资产。这套资产至少包含四层原始数据层行情、财务、行业、指数等数据有固定的来源和版本标记。数据流层清洗、对齐、缓存、标准化让数据能直接进入因子计算。因子计算层每个因子有独立模块、命名规则、参数配置和文档说明。因子管理层因子值入库关联检验指标、快照版本和复算脚本。这四层合起来才叫因子库。单独一张因子值表或者一个因子代码文件夹都不算。1.3 先判断自己处在哪个阶段不是所有人都需要立刻搭一套复杂的因子库。如果刚开始学量化金融还没系统跑过十个以上的因子我建议先不要急着设计库表。先用 Jupyter 或脚本把单因子流程跑透理解IC、分层回测、换手率这些指标的意义再慢慢抽象。但如果你已经做了两三个月的因子测试开始觉得重复工作太多、结果追溯困难那就该进入因子库建设阶段。这个阶段的核心任务不是“多挖因子”而是“让已有因子可以被管理、被检验、被迭代”。2. 数据流不是爬数据而是把口径钉死因子计算的基础是数据。但数据流真正的难点不是“能不能下载到行情”而是“每次算出来的数据口径一不一样”。很多因子结果对不上复盘到最后都会发现是数据流的问题。2.1 最容易出错的不是行情获取而是口径对齐行情数据本身只是起点。真正让因子结果漂移的是三类口径问题复权方式价格数据分前复权、后复权、不复权。收益率类因子对复权方式不敏感但价格突破类、均线类因子非常敏感。如果在不同时间段用了不同复权方式结果根本不可比。特殊状态停牌日填充吗涨跌停日剔除吗ST股票保留吗上市不足N日的股票算吗每一种选择都会改变因子分布。代码和行业版本股票代码可能有历史变更行业分类会定期调整。如果用不同版本的代码表合并数据样本集合会不一致。这些口径问题单次跑通时很容易忽略但在因子库里会被无限放大。2.2 建立最小可运行的数据流我这里给出一个常见的数据流结构不涉及具体数据源只表达处理顺序原始数据落地将日线行情、财务数据、股票列表等原始文件按日期或市场保存为parquet或csv。标准化字段统一列名比如trade_date, stock_code, open, high, low, close, volume, amount统一代码格式。清洗去重处理重复行、异常值、停牌缺失并记录清洗规则。对齐交易日历把不同表中的数据合并到统一交易日历保证每个股票在每个交易日都有确定状态。缓存中间结果将清洗后的数据缓存为factor_input/下的文件方便因子计算复用。下面是一段示意代码不是为了直接运行而是展示处理顺序# 示例把原始日线转成因子计算层 data load_raw(daily_2024.parquet) data standardize_columns(data) data drop_duplicates([trade_date, stock_code]) data align_calendar(data, calendar) data mark_status(data) # 标记停牌、ST、涨跌停等状态 data.to_parquet(factor_input/daily_aligned.parquet)实际落地时你不需要一开始就把所有状态都做全但至少要在数据流里留出这些字段的空间否则后面补会非常痛苦。2.3 数据版本不要原地覆盖我踩过最深的坑是覆盖原始数据。某次从数据源重新下载了行情以为只是修复了几个错误报价结果没有保留旧版本。后来因子回测结果变化根本没法定论是市场变化、代码变化还是数据变化。稳妥的做法很简单原始数据按批次保存文件名带日期或批次号例如daily_raw_20250101.parquet。每次清洗过程写一个变更日志记录“什么时间从什么版本做了什么处理”。如果条件允许保存一份清洗后的数据快照作为因子计算的唯一输入。注意因子计算结果异常时第一反应别是改因子代码先确认输入数据版本有没有变。这一步能省掉大量无效排查。2.4 数据流排查链路当因子值出现明显异常我一般按这个顺序排查日期范围是不是包含了停牌日、新股上市初期、退市整理期等特殊样本。代码对齐两个表合并时代码格式是否一致有没有因为代码前缀不同导致大量空值。复权状态因子计算用的是复权价还是原始价是否与因子逻辑匹配。缺失值处理停牌缺失是填充了前值还是直接剔除前后是否一致。数据源变更最近是否更新过数据文件更新时是否记录了版本。3. 因子库的核心是让一个因子“能解释、能复算、能追踪”数据流稳定之后才轮到设计因子库本身。因子库不等于一张大宽表而是一个因子管理系统。核心要求是任何一个因子拿出来都能回答三个问题——它是什么意思它的参数是什么它是怎么算出来的3.1 因子命名必须可读参数必须显式我给因子命名时杜绝f_001这类无意义编号。一个合格的因子名最好能表达出最核心的逻辑。例如momentum_20d_skip5_exclude_stvolatility_60d_zscoreturnover_10d_ma_rank对应的参数可以单独放在配置文件中而不是散落在代码里。下面是一个 YAML 配置的示例结构factor_name: momentum_20d_skip5_exclude_st category: momentum params: window: 20 skip: 5 exclude_st: true data_requirement: price_field: close adjust: none calendar: cn_stock这样做的好处是半年后再看这个因子不需要读代码就能知道它的大致规则。更重要的是当你把因子库交给别人或换一台机器复算时参数不会丢失。3.2 把因子计算拆成原子操作很多人的因子代码是“一次性脚本”从数据读取到清洗到计算全部写在一个长文件里改一处就影响所有。更好的做法是把因子计算拆成原子操作比如收益率、对数收益率滚动均值、滚动标准差、滚动最大回撤横截面 rank、zscore行业市值中性化条件筛选剔除ST、剔除停牌、剔除上市不足N日每个原子操作单独一个函数参数显式传入。写新因子时就是组合这些操作而不是复制粘贴整段代码。这样能显著减少“同名不同逻辑”的因子混乱。3.3 因子库的表结构设计因子库不一定要用很重的系统。早期可以用文件系统加配置文件规模上来后再换数据库。我建议至少包含四类内容内容作用建议字段因子注册表记录因子定义和参数factor_name, category, params, owner, status, created_time因子值表存储计算结果trade_date, stock_code, factor_name, value, update_time快照版本表记录计算时的数据版本和代码版本factor_name, data_version, code_version, compute_time检验指标表记录因子评估结果factor_name, ic_mean, icir, layering_return, turnover, sample_period这个结构不复杂但足以支撑“因子值是谁、在哪、哪版、什么参数”的追溯。3.4 因子入库的验收检查表一个因子要进入因子库至少要过一遍检查。我常用下面的验收表检查项通过标准缺失率正常样本中缺失值比例不超过一定阈值值域因子值分布合理没有肉眼可见的极端异常覆盖区间覆盖足够长的历史周期最好包含不同市场状态相关性与已有因子相关性不高避免重复信息可复算用同一份数据和同一份代码能复现相同结果文档命名、参数、数据需求、计算逻辑都已记录注意入库不等于确认有效。入库只是意味着这个因子可以被管理、被比较、被进一步检验。真正决定是否使用它要看后面的检验和实盘观察。4. 因子检验做对了才敢把它放进库因子入库之后紧接着的问题是怎么判断它“值不值得继续跟踪”。很多初学者会盯着一个指标猛看比如 IC 均值觉得数值高就是好因子。实际上因子检验需要多维度判断。4.1 IC、分层回测和换手率需要组合看简单解释三个常用指标IC因子值与未来收益的相关系数。IC均值看整体预测力ICIRIC 均值 / IC 标准差看稳定性。分层回测按因子值从低到高分成若干组观察各组未来收益是否单调变化。多空收益是最高组与最低组的差。换手率按因子调仓时持仓组合需要变化的比例。换手过高交易成本会吃掉收益。只看 IC 均值是不够的。一个因子可能 IC 均值很高但 IC 正负波动剧烈也可能分层收益只在某一段区间明显其他区间完全失效。所以要组合看。4.2 因子迭代闭环因子研究不是一次性的“提出 - 验证 - 结束”而是一个迭代闭环提出想法记录为什么想到这个因子。编写计算用标准化原子操作搭建因子模块。生成因子值接入数据流计算完整历史区间。检验评估计算 IC、分层、换手等指标。入库或淘汰同时记录结论包括淘汰原因。定期复检每月或每季度重新计算因子表现观察衰减。这个闭环里最重要的一步可能不是“入库”而是“记录淘汰原因”。否则半年后很容易重复测试同一个无效因子白白浪费时间。4.3 因子衰减和复检没有哪个因子能永远有效。市场风格切换、参与者变化、套利拥挤都会让因子衰减。所以因子库要支持“复检”。我一般会给每个因子标记创建日期和最近检验日期。设置定期复检任务至少月度更新 IC 等指标。当因子连续一段时间表现低于阈值时将其标记为“失效候选”而不是直接删除。保留历史数据便于日后用新方法重新评估。因子失效是正常现象。关键是失效的因子也要能追溯到它的生命周期知道它曾经在什么条件下有效。4.4 常见偏差前视偏差和幸存者偏差因子检验里最常见的两类偏差前视偏差在历史回测中用了当时不可能拿到的信息。比如用当日收盘后才知道的全市场收益分布去计算当天开盘时的因子值。这类偏差会让回测结果虚高。幸存者偏差股票池只保留当前仍在交易的股票把已退市或长期停牌的股票剔除历史回测结果会系统性地偏乐观。避免方法是严格区分信息时点尽量用 T 日及之前的数据计算 T 日因子股票池构建时考虑历史成分并明确记录筛选规则。提醒参数扫描也是常见过度优化来源。窗口参数、阈值参数一多总能在历史上挑出好看的组合但样本外大概率衰减。不要用终版因子在全部历史上反复微调。5. 五个工程化检查点把研究脚本变成长期资产最后一个阶段是工程化。很多量化研究在个人阶段都死于“能跑但不能长期用”。从数据流到因子库如果只停留在概念上不落到工程化检查后面还是会乱。5.1 可重复运行同一份代码、同一份数据必须跑出完全相同的结果。听起来简单实际会遇到不少问题依赖库版本不一致某些数值运算结果不同。随机种子未固定涉及抽样或初始化的部分无法复现。浮点精度在不同平台上有细微差异。建议在因子库根目录写一个README记录 Python 版本、核心依赖库版本、运行方式。必要时用虚拟环境或容器固定环境。5.2 增量更新因子计算如果每天全量重算数据量上来后非常低效。更常见的做法是增量更新查询每个因子已计算到哪个交易日。只计算新增长交易日的数据。如果因子使用了滚动窗口需要保留足够长的历史前置数据不能只取新增一天。示例latest_date get_latest_factor_date(factor_name) new_dates get_new_trade_dates(latest_date, today) if new_dates: compute_factor(factor_name, new_dates)增量更新的前提是因子计算函数对“只输入新增日期”是安全的。对于需要回溯窗口的因子要额外传入前置数据。5.3 日志和异常处理因子计算任务要有日志。每个任务记录开始时间、结束时间、成功与否、处理了多少条数据、是否有警告。失败时不要写半截结果而是先报错人工处理。排查问题时先看日志再看输入文件然后看依赖版本。很多看似代码问题的情况最后都是数据文件没更新或权限不对。5.4 权限和数据安全行情数据通常有授权限制原始数据文件不要随手同步到公共网盘。即使是个人研究也建议数据目录和代码目录分离。敏感数据文件设置只读权限。因子库的配置文件不要包含敏感账户信息。如果需要多人协作做好角色和权限区分。安全边界不是“等出事再补”而是从第一天就要有。5.5 长期维护因子库是一个需要长期养护的系统。数据源格式可能变化股票池规则可能调整市场结构也会变化。我建议每季度做一次因子库盘点哪些因子仍在正常更新。哪些因子已经连续失效。哪些因子需要因数据源变更而重新计算。哪些文档已经过时。这个过程不复杂但能防止因子库慢慢变成“垃圾场”。5.6 最后说一句因子库的终点不是库本身把数据流到因子库这一整套做下来我发现最有价值的反而不是那些因子值而是过程中建立起来的秩序。那些清洗规则、命名习惯、版本记录、检验逻辑会在未来每一个研究项目中反复使用。如果你现在正处在一个“因子很多、脚本很乱”的阶段我的建议是先停一下。不要急着挖新因子花一两天把数据流从头到尾捋一遍给现有因子补上命名、参数和文档选三五个核心因子走一遍入库流程。做完这一步你的因子阶段才算真正收官。量化金融里市场会变因子会衰减但一套能自我解释、能复算、能追踪数据来源的研究基础设施是真正能穿越周期的。从数据流到因子库不是把表格填满而是让自己对每一个数字都有底气。