ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

从Two Sigma实践看AI量化投资:数据、特征、模型到生产部署的完整框架

从Two Sigma实践看AI量化投资:数据、特征、模型到生产部署的完整框架 在量化投资领域Two Sigma 是把机器学习带入主流的代表机构之一。外界谈到 Two Sigma 时通常聚焦于它的资产管理规模和数据科学家数量但真正值得技术团队学习的是它如何处理“AI 赋能投资”的完整链路数据如何整理、信号如何构造、模型如何验证、风险如何约束、工程如何部署。AI 在投资中的应用并不是“把行情数据丢给神经网络然后等模型自动选出股票”这么简单。实际操作中数据质量、特征泄漏、时间序列验证、模型漂移和交易成本每一项都可能让一个看似优秀的机器学习策略在实盘中失效。本文围绕这条主线展开适合有机器学习基础、想进入量化研究方向的工程师也适合已经在做传统量化策略、希望引入深度学习或大语言模型方法的团队。读完以后你会得到一套从数据、特征、模型到生产部署的完整技术框架以及一套可用于自查的工程化清单。1. 先理解 Two Sigma 的方法论AI 投资不是“模型选股票”这么简单1.1 从数据到决策的完整链路很多人提到 AI 投资第一反应是“算法替代人类做投资决策”。Two Sigma 在公开场合反复强调的观点更接近工程系统AI 赋能投资的本质是把“数据获取、信号研究、组合构建、风险控制、交易执行”这一整条链路系统化让机器学习在每一个环节产生可验证的增量而不是让模型直接替代全部决策。一条完整的量化研究工作流大致包含以下环节数据采集与清洗行情、财报、舆情、宏观、另类数据统一入库并解决缺失值、异常值、复权、日历对齐和未来函数问题。特征工程把原始数据转换成模型可学习的因子例如动量、波动率、流动性、基本面比率、情绪指标。模型训练使用回归、树模型、神经网络或深度学习方法学习特征到未来收益之间的非线性关系。策略回测在历史数据上验证模型效果重点是切分方式不能造成数据泄漏。风险约束与组合优化把模型的预测值转成目标仓位同时控制行业暴露、个券集中度和最大回撤。交易执行与监控把目标仓位下达到交易系统持续监控预测质量、特征分布和模型表现。Two Sigma 的公开访谈和论文中经常出现一个词research platform。它强调的是团队不是在写一个个孤立的 Python 脚本而是在搭建一个可复用、可回滚、可审计的研究平台。模型训练只是平台上的一个环节数据版本、特征版本、模型版本和实验记录都必须能被追溯。注意不要把“AI 投资”理解成端到端自动交易。更稳妥的理解是AI 模型负责提供预测信号风险模块和组合优化模块负责约束信号交易系统负责执行信号。每一层都需要独立验证。1.2 为什么传统多因子模型需要机器学习传统多因子模型的做法是先人工假设某个因子和未来收益相关例如“低估值股票长期跑赢高估值股票”然后对因子做分层回测、IC 检验、回归分析最后把多个因子加权合成一个综合分数。问题在于因子的有效性往往是非线性的市盈率在极低区间和中等区间对收益的影响并不一样。因子之间相关性高用人工权重很难找到最优组合。因子阈值和交互作用容易被忽略例如“高动量 低波动”可能比两个因子单独使用更稳定。市场状态发生变化时固定权重会失效。机器学习模型擅长处理这些问题。树模型可以自动捕捉特征之间的交互效应深度学习可以学习时间序列中的局部模式。但机器学习不是银弹它引入了一个更大的问题更容易过拟合也更容易在无意中使用未来数据。这也是 Two Sigma 这类机构特别强调研究基础设施和验证流程的原因。1.3 Two Sigma 范式对普通团队的启示Two Sigma 的规模和数据积累很难复制但它的方法论可以拆成几个可迁移的原则数据先于模型先建立统一、干净、可追溯的数据体系再谈复杂模型。验证先于上线任何信号都要经过严格的时间序列验证避免前视偏差。系统先于个人研究员写的代码要进入统一平台不能散落在个人电脑上。可解释性优先模型可以复杂但决策依据要能回溯到特征层面。这些原则对一个小型量化团队同样适用。即使只有一台 GPU 服务器和一个数据源只要数据版本管理、特征版本管理和实验记录做得好就比堆一堆效果不明显但无法解释的模型更接近生产可用。2. 数据层是 AI 投资的地基类型、清洗和版本管理2.1 投资数据的主要类别在投资研究场景中数据种类非常多不同类型的更新频率、质量、维度差异很大。通常可以分成以下几类数据类别典型字段更新频率主要问题行情数据开高低收、成交量、成交额最高频到日频复权、停牌、涨跌停、错误 Tick基本面数据财务报表、估值指标、分析师预期季度/日频公告日期错位、数据修正、口径不一致舆情数据新闻、社交媒体、公告文本分钟到日频情感标注偏差、时效性、来源权重另类数据卫星图像、支付数据、物流数据日频/月频覆盖度低、成本高、处理链路复杂宏观数据CPI、PMI、利率、汇率月频/日频发布时间延迟、统计口径调整实际落地的第一件事不是训练模型而是把所有数据源统一到一套表结构里保证每行数据都带有明确的资产标识、时间标识和版本标识。缺少主键或时间字段混乱几乎会污染后面所有环节。2.2 数据清洗的关键问题以最简单的日线行情数据为例常见问题包括停牌日缺失或成交量为 0。复权价格计算错误导致收益率突变。涨停板数据没有剔除收益序列出现大量 0 或异常。时间戳时区不一致跨市场数据对不齐。后来对历史数据修正过导致用新数据回测旧策略时产生偏差。下面是一个基本的清洗流程示例使用 pandas 实现import pandas as pd import numpy as np df pd.read_csv(daily_price.csv, parse_dates[date]) # 1. 排序并去重保证同一股票同一日期只有一条记录 df df.sort_values([symbol, date]).drop_duplicates( subset[symbol, date], keeplast ) # 2. 剔除明显异常价格 df df[(df[close] 0) (df[high] df[low])] # 3. 使用向前填充处理停牌缺失但记录是否填充 df df.sort_values([symbol, date]) df[is_suspended] df[vol].isna().astype(int) df[close] df.groupby(symbol)[close].ffill() # 4. 计算收益率时先剔除停牌日避免把停牌前后的价格差误算为真实收益 df[return] df.groupby(symbol)[close].pct_change() df.loc[df[is_suspended] 1, return] np.nan # 5. 对收益率做极值处理避免数据错误主导统计结果 lower, upper df[return].quantile([0.001, 0.999]) df[return_winsorized] df[return].clip(lower, upper)这里最关键的一步是第 4 步。很多初学者在计算收益率后直接交给模型训练忽略了股票停牌导致的伪收益率。一个停牌一周的股票复牌后价格不变前向填充会让模型误以为连续两天收益为 0这种信号会干扰模型对真实市场状态的判断。2.3 用 DVC 和 Feature Store 管理数据和特征版本模型训练需要复现复现的前提是数据和特征可追溯。在 Two Sigma 这类机构研究员不会直接读取生产数据库跑分析而是通过统一的数据版本管理工具获取数据快照。开源方案中DVCData Version Control是一个常见选择。DVC 的基本用法如下# 初始化 DVC 并与 Git 配合使用 dvc init # 添加本地数据目录 dvc add data/raw/daily_price.parquet # 生成 .dvc 文件并将数据文件加入 .gitignore git add data/raw/daily_price.parquet.dvc git commit -m add daily price data snapshot # 推送数据到远程存储 dvc remote add myremote s3://my-bucket/dvc-store dvc push之后任何人切换到新的 Git 分支或回退到旧版本时执行dvc pull就能恢复到当时的数据快照。数据版本和代码版本因此关联在一起。对于特征数据更完整的方法是引入 Feature Store。特征存储通常负责三件事特征计算、特征版本管理和服务时的一致性保障。回测时模型使用的特征必须和实盘推理时使用的特征完全一致否则模型表现会出现明显衰减。注意回测时某一个股票的市值因子如果使用了未来财务报表数据就会产生前视偏差模型在回测中表现很好实盘中却因为拿不到未来数据而失效。所有基本面因子都必须使用对应的公告日期而不是报表期末日期。3. 特征工程从原始数据到可学习信号3.1 特征的本质是“信息压缩”模型不是直接从原始 K 线中学习的。特征的目的是把长时间窗口内的信息压缩成有限的数值表达让模型更高效地发现模式。特征设计得好不好直接决定模型上限。在一个分钟级或日级量化任务中常见特征包括动量类过去 N 日收益率、移动平均线偏离度、MACD 指标。波动率类过去 N 日收益标准差、真实波动幅度均值。流动性类换手率、成交额对数、买卖价差。基本面类市盈率倒数、市净率、ROE、盈利增速。时序结构类收益的自相关系数、偏度、峰度。计算特征时只允许使用截止到 t 时刻的信息。下面是一个简单示例import pandas as pd def compute_features(df: pd.DataFrame, lookback: int 20) - pd.DataFrame: df df.sort_values([symbol, date]) # 动量因子过去 lookback 日收益 df[momentum] df.groupby(symbol)[close].pct_change(lookback) # 波动率因子过去 lookback 日收益标准差 df[volatility] df.groupby(symbol)[return].rolling(lookback).std() # 成交量变化当日成交额相对过去 5 日均值 df[volume_ratio] ( df[amount] / df.groupby(symbol)[amount].shift(1).rolling(5).mean() ) # 去除无穷值 df df.replace([float(inf), float(-inf)], np.nan) return df df compute_features(df)这段代码强调了一个容易出错的地方groupby(symbol)[return].rolling(lookback).std()计算的是同一股票在时间上的滚动统计量不会看到未来数据。很多深度学习实现里如果不注意按股票分组直接把所有股票放在一起做滚动窗口会造成跨股票泄露。3.2 横截面标准化和时序标准化的区别量化特征处理中有两种常见标准化方式横截面标准化在某个时点对所有股票的特征值做排名或 z-score。这种方式更适合横截面模型因为它强调“该股票当前在同类股票中的相对位置”。时间序列标准化对同一股票在不同时间的特征值做标准化。这种方式更适合时序模型但需要特别注意滚动窗口的使用防止使用未来统计量。一个常用的横截面处理方法如下def cs_zscore(df: pd.DataFrame, factor_col: str, date_col: str) - pd.DataFrame: df df.copy() # 按日期分组每个时点上对因子做 z-score df[f{factor_col}_cs] df.groupby(date_col)[factor_col].transform( lambda x: (x - x.mean()) / x.std() ) return df这种处理方式在模型的实时推理中也要保持相同逻辑。即生产环境中每天要用当天所有股票的因子值做标准化而不是用历史均值替代。否则线上的特征分布和回测时不一致。3.3 特征选择和特征监控当初始特征数量超过几十个之后特征之间可能高度相关。常见做法包括计算特征相关性矩阵剔除相关性过高的冗余特征。使用树模型的特征重要性分数做初步筛选。使用 SHAP 值观察特征对预测结果的贡献方向是否稳定。在线性模型中观察系数的符号是否符合业务常识。在实盘阶段特征监控非常关键。要定期检查每个特征的均值、标准差、缺失率、分位数与历史区间做对比。特征分布漂移往往先于模型表现衰减出现。4. 模型层从线性模型到树模型、深度学习与大模型4.1 如何选择模型量化投资场景中模型选择取决于三个问题任务类型是预测收益率还是预测涨跌方向训练数据量是否足够是否需要可解释性。模型类型特点适用场景线性回归/岭回归可解释性强训练快因子数量少、关系接近线性LightGBM/XGBoost能处理交互效应和缺失值训练效率高中大规模因子数据是主流基线深度神经网络能学习高阶非线性关系但需要更多数据高频或多模态数据大语言模型擅长文本理解但存在幻觉和延迟问题舆情分析、研报摘要、信息抽取强化学习适合序列决策但训练不稳定组合优化、交易执行在实际项目中不要一上来就选择最复杂的模型。先用 LightGBM 或逻辑回归建立基线确认数据链路和评估流程是可信的再逐步引入更复杂的模型。Two Sigma 的公开经验里也强调多数情况下树模型在结构化表格数据上已经足够强复杂的深度模型并没有带来想象中的优势。4.2 时间序列验证防止前视偏差和过拟合金融数据不能使用随机切分验证。随机将样本分成训练集和测试集时同一时间段内的数据会同时出现在训练集和测试集中模型实际上是在“记忆”近期模式。正确做法是按时间顺序切分。下面是一个使用 LightGBM 和按时间切分的训练示例import lightgbm as lgb from sklearn.metrics import mean_squared_error sample df.dropna(subset[label]).copy() # 按时间排序 sample sample.sort_values(date) # 前 70% 数据作为训练集后 30% 数据作为测试集 split_date sample[date].quantile(0.7) train sample[sample[date] split_date] test sample[sample[date] split_date] feature_cols [c for c in train.columns if c.startswith(feature_)] # 或者直接使用日期的字符串边界 # split_date pd.Timestamp(2023-12-31) # train sample[sample[date] split_date] # test sample[sample[date] split_date] model lgb.LGBMRegressor( n_estimators500, learning_rate0.05, num_leaves31, colsample_bytree0.8, subsample0.8, random_state42, ) model.fit( train[feature_cols], train[label], eval_set[(train[feature_cols], train[label]), (test[feature_cols], test[label])], eval_metricmse, ) test_pred model.predict(test[feature_cols]) test_mse mean_squared_error(test[label], test_pred) print(ftest mse: {test_mse:.6f})这段代码的关键点是训练集只包含早期数据测试集只包含后期数据。但这样切分后要意识到市场状态可能在测试期间发生剧烈变化单次测试结果并不稳定。更严谨的做法是使用“滚动时间窗口”或“扩展窗口”进行多次训练和验证。可以使用 Walk-Forward 验证def walk_forward_validate(df, feature_cols, n_splits5): dates df[date].sort_values().unique() split_dates [dates[i * len(dates) // n_splits] for i in range(1, n_splits)] results [] for i in range(len(split_dates) - 1): train_start dates[0] train_end split_dates[i] test_start split_dates[i] test_end split_dates[i 1] train df[(df[date] train_start) (df[date] train_end)] test df[(df[date] test_start) (df[date] test_end)] model lgb.LGBMRegressor(n_estimators200, learning_rate0.05, num_leaves31, random_state42) model.fit(train[feature_cols], train[label]) pred model.predict(test[feature_cols]) ic pd.Series(pred).corr(pd.Series(test[label])) results.append(ic) return results这里的 ICInformation Coefficient是预测值与真实收益之间的相关系数是量化模型中常用的指标。IC 越高代表预测能力越强但没有绝对标准一般需要结合策略的交易成本来判断。注意Walk-Forward 验证中的每一折都重新训练了模型这更接近真实生产中的模型更新节奏。如果每一折的结果都很不稳定说明这个信号本身不具备持续性不应该进入实盘策略。4.3 避免过拟合的实践约束机器学习模型在金融数据上非常容易过拟合常见表现是训练集上 IC 很高测试集上直接衰减到接近 0。以下是几条实用的约束方法限制模型复杂度使用较小的num_leaves或深度不要为了训练集效果无限调参。增加正则化在 LightGBM 中配置lambda_l1和lambda_l2。减少特征数量只保留有业务含义的特征特征太多会放大噪声。多次随机种子验证固定数据切分后用不同的随机种子训练多次观察结果稳定性。设置最小收益阈值如果预测值与未来收益的相关性不够高说明信号本身可能被噪声主导。5. 模型输出到组合优化预测信号怎么变成仓位5.1 从预测值到目标权重模型输出的预测收益只是第一步不能直接把预测收益最高的股票买满。组合构建要平衡预期收益、风险和交易成本。最简单的方法是使用“预测收益排名分成若干层”例如把股票按预测值从高到低分为 5 层只做多最上层、做空最下层。更系统化的方法是最小化风险调整后的组合目标函数minimize w^T Sigma w - alpha * w^T mu subject to sum(w) target_exposure |w_i| max_weight sector_exposure limits其中mu是模型输出的预测收益向量Sigma是股票收益协方差矩阵w是组合权重向量。这个优化问题可以使用cvxpy求解。import cvxpy as cp import numpy as np def optimize_portfolio(mu_hat, Sigma, risk_aversion0.5, max_weight0.05): n len(mu_hat) w cp.Variable(n) # 组合预期收益和风险 expected_return mu_hat w risk cp.quad_form(w, Sigma) # 最大化收益 - 风险惩罚 objective cp.Maximize(expected_return - risk_aversion * risk) # 约束满仓、单只股票权重上限 constraints [ cp.sum(w) 1.0, w 0, w max_weight ] problem cp.Problem(objective, constraints) problem.solve() return w.value组合优化中用到的Sigma通常不是直接计算的样本协方差而是经过压缩处理后的估计值否则在股票数量多、历史数据短的情况下协方差矩阵会非常不稳定。实际项目中可以考虑 Ledoit-Wolf 压缩估计或因子协方差模型。5.2 交易成本和执行模型每调一次仓都会产生手续费、滑点和市场冲击。一个在回测中 IC 为正的策略扣掉交易成本后可能变成亏损。因此回测时必须建模成本手续费按成交金额的固定比例计算。滑点买入时成交价比信号触发价高卖出时低。冲击成本单笔订单越大成交价越不利。常见做法是给收益率序列直接减去一个固定成本。更精细的做法是模拟订单簿但计算复杂。对日频策略来说固定比例成本已经是一个合理的起点。buy_cost 0.0005 # 万五包含佣金和滑点 sell_cost 0.0005 portfolio_returns weights_shifted * next_returns net_returns portfolio_returns - turnover * (buy_cost sell_cost)5.3 风险监控指标实盘上线后要持续监控以下指标组合最大回撤是否超过阈值。行业暴露度和市值暴露度是否在设定范围内。模型预测收益率分布是否发生漂移。实际收益与模型预测收益之间的 IC 是否衰减。换手率是否突然升高导致成本超出回测假设。发现异常时优先检查数据质量和特征分布而不是立刻修改模型参数。6. 工程系统把模型部署成稳定的生产服务6.1 训练与推理分离量化系统通常把训练流程和推理流程分开。训练流程负责在每天收盘后或定期任务中训练新模型并记录模型版本推理流程负责在盘中或每日开盘前加载最新模型并生成预测。关键要求是训练时使用的特征计算逻辑必须和推理时完全一致。模型文件通过模型注册表管理每次上线都有版本号。推理服务可以通过 REST API 或消息队列被组合优化模块调用。6.2 特征一致性回测和生产必须对得上训练推理特征不一致是量化系统最隐蔽的问题。训练时用了特征 A 的中位数去标准化推理时却用当前点的平均值去标准化模型效果就会衰减。为了避免这个问题可以做一个一致性测试import joblib def test_feature_consistency(new_data): feature_processor joblib.load(models/feature_processor.pkl) train_feature_stats joblib.load(models/feature_stats.pkl) processed feature_processor.transform(new_data) # 对比推理时的均值和方差与训练时是否接近 for col in processed.columns: train_mean train_feature_stats.loc[col, mean] infer_mean processed[col].mean() # 如果偏差超过阈值说明上线环境的特征不一致 if abs(infer_mean - train_mean) / abs(train_mean) 0.2: raise ValueError(ffeature {col} drift detected)6.3 上线后监控、回滚和人工复核生产环境要有一个监控面板或定时任务检查模型上线后实时预测值和回测期分布的差异。数据源是否正常更新是否有延迟或缺失。交易系统成交价格和模型预期价格的偏移。如果监控指标异常需要有回滚机制。模型版本管理是关键确保在出现问题时能快速切回上一个稳定的模型副本。7. 大语言模型和 AI Agent 在投资研究中的角色7.1 大模型的适用场景和幻觉风险近两年大语言模型进入金融领域后主要应用场景集中在信息处理而不是直接预测收益。常见场景包括从公告和新闻中抽取事件主体、事件类型和影响方向。对研报做摘要和观点归类。把非结构化文本转换成结构化标签再输入到下游模型。辅助研究员搜索资料、生成代码和撰写文档。大模型的幻觉问题在投资场景中尤其危险。模型可能在文本中读到一条 2020 年的公告却把它描述成当前事实也可能在计算财务指标时自行编造一个数字。因此凡是大模型输出的内容都要经过“检索增强生成”流程或人工复核不能直接进入策略信号。7.2 使用 LLM 做投研信息抽取的示例一个相对稳妥的做法是把大模型当作信息抽取器输入指定的新闻文本要求输出结构化标签然后用规则校验标签取值。{ prompt: 以下是某上市公司公告摘要。请抽取事件类型、涉及主体和情感方向。事件类型可选业绩预增、业绩预减、回购、减持、并购、增发。情感方向可选积极、消极、中性。, document: 某公司预计上半年净利润同比增长超过 50%主要原因是新产品销量大幅提升。, expected_output: { event_type: 业绩预增, sentiment: 积极 } }在实际系统中要对模型输出结果做类型校验不允许模型自由创造枚举值之外的类别。同时重要事件要保留原始文本和人工复核记录。7.3 AI Agent 的边界“AI Agent 自动完成调研、回测、生成策略报告”这类设想很让人兴奋但落到生产环境时必须给 Agent 设置明确的工具使用边界Agent 只能调用已验证的数据接口不能随意访问外部文件。Agent 生成的代码不能直接自动执行必须先经过代码审查。Agent 的策略建议要附带数据来源和推理过程便于追溯。Agent 不能修改生产环境的模型参数或交易系统的配置。现阶段AI Agent 更适合作为研究辅助工具而不是自动决策系统。其输出需要经过研究员的判断和工程化验证后才能进入流程。8. 常见问题排查链路与最佳实践清单8.1 常见坑和排查路径问题现象可能原因检查方式处理建议回测效果好实盘效果差前视偏差或特征泄漏检查因子计算是否用了未来数据检查财报使用日期用公告日期对齐因子改用 Walk-Forward 验证IC 在验证集上接近于 0过拟合到训练噪声查看特征数量、模型复杂度、随机种子稳定性减少特征、增加正则、多次训练做稳定性分析实盘交易后成本远超回测回测没有建模滑点和冲击成本对比回测成交价与实盘成交价在回测中加入固定成本必要时模拟订单簿生产特征和训练特征不一致训练和推理使用了两套代码对比特征均值和方差统一特征计算模块增加一致性测试上线后模型预测分布漂移市场状态变化或数据源更新绘制预测值分布和训练分布对比图启动监控训练新模型必要时回滚旧版本收益率序列出现大量 NaN停牌日未处理检查分组排序和 ffill 逻辑停牌日不参与收益计算8.2 模型上线前的检查清单在把 AI 模型用于投资决策之前建议逐项检查以下内容[ ] 所有因子是否使用截止到预测时点的数据基本面因子是否使用公告日期。[ ] 训练集和测试集是否按时间切分是否存在随机切分。[ ] Walk-Forward 验证中每一折的 IC 是否稳定是否出现大幅波动。[ ] 是否包含交易成本模型成本假设是否符合目前的交易规模。[ ] 训练与推理的特征计算逻辑是否统一特征标准化参数是否保存。[ ] 模型版本是否有记录是否能够回滚到上一个稳定版本。[ ] 是否设定了最大回撤、行业暴露和单票权重约束。[ ] 是否对模型预测结果设置了人工复核流程。[ ] 是否监控数据延迟、特征分布漂移和预测值分布漂移。[ ] 是否在正式部署前进行小规模模拟盘验证。8.3 对学习者和团队的实践建议如果你是刚开始接触 AI 投资的应用开发者建议按照下面的顺序推进第一步打好数据基础。选择一组公开行情数据完成清洗、复权、停牌处理和收益率计算写清楚每一步规则。第二步构造一批有业务含义的因子而不是从网上复制一堆特征。从动量、波动率、流动性这三类最简单的因子开始理解每个因子的经济含义。第三步用 LightGBM 做一个简单的横截面收益预测配合时间序列切分验证。记录训练集和测试集的 IC、准确率、波动情况。第四步加入交易成本比较扣费前后的收益差异。这一步能帮你理解成本和模型预测能力之间的平衡关系。第五步把模型预测输出到组合优化模块加入风险约束最终形成一个完整的策略流程。第六步再考虑引入深度学习和 LLM。此时你已经有了可对比的基线可以严谨地判断新模型是否真的带来增量。在生产环境中永远不要把模型训练、组合构建、交易执行放在同一个不可分割的脚本里。各环节之间用明确的接口通信保证任何一部分出错时系统能快速定位并回滚。投资 AI 应用的竞争不只在模型准确率上更在工程系统是否稳定、数据是否干净、验证是否严格。把这三件事做好即使模型本身并不前沿也可以在实际业务中稳定运行很长一段时间。
返回列表