
做量化交易这几年我最深的一个体会是市场里的钱大部分藏在“不寻常”里。价格瞬间被打穿、两个合约的价差突然拉宽、某只股票的成交额异常放大——这些偏离日常规律的现象背后往往要么是情绪失控要么是定价错误正是Alpha的来源。于是我开始把所有精力集中在一个方向上用AI辅助识别市场异常与套利机会。这里的“异常”不是指暴跌暴涨这种结果而是指统计数据上的离群点“套利机会”也不是无脑搬砖而是定价不一致被纠正前的短暂窗口。这篇文章是我自己从零搭一套“异常识别套利评估”系统的完整总结。适合正在做量化研究、准备接触市场微观结构、或者想用机器学习做交易信号的朋友。我不会只讲模型原理会把数据清洗、特征构建、模型选型、回测陷阱和实盘中的坑全部摊开来讲保证你看完能照着搭一个自己的雏形。1. 先把概念拆清楚市场异常和套利机会到底指什么1.1 市场异常不是玄学是统计上的“不寻常”很多人一听“市场异常”就想到闪崩、乌龙指、极端行情但实际做下来你会发现真正有价值的异常往往藏在日常交易数据里。比如订单簿的买卖力量突然失衡、某只股票相对行业指数的偏离度突破历史区间、两个高度相关品种的相关性短时间内断裂。用学术一点的话说在有效市场假说下价格应当遵循随机游走异常就是数据分布中那些不应该出现却真实出现的点。我习惯用一个生活化类比来理解平时小区门口超市的鸡蛋卖6元一斤突然有一天标价5元。这未必是便宜货可能是临期促销也可能是竞争对手降价还可能是收银员标错了价。只有在你知道“正常状态是什么样”的前提下才能判断5元到底是机会还是陷阱。AI的作用就是帮你从成千上万个价格、成交、挂单数据里快速筛出这些“偏离正常状态”的时刻而不是靠肉眼盯盘。1.2 套利机会的本质是“定价不一致”套利的根基是“一价定律”同一资产、同一时间、同一风险敞口价格应当一致。现实里由于流动性、交易规则、参与者的差异价格总会出现短暂的不一致。跨期套利捕捉同一品种不同月份合约的价差偏离跨市场套利捕捉同一标的不在同一个市场的价差期现套利则盯期货与现货的基差。传统手工做套利盯一两个品种还行但做不了高维度的事几十个品种、上百个合约、不断变化的相关系数。AI在这里解决的核心问题不是“预测未来涨跌”而是“现在的状态相对于历史统计规律是否不正常”。只要定价不一致达到一定阈值扣除成本后仍有利润空间就构成一笔可执行的套利机会。真正要理解的一点是异常是套利的前提但不是所有异常都适合套利。某只股票因为消息面瞬间暴涨是异常但你无法安全对冲就不构成套利。所以整个系统的设计逻辑必须分层第一层找“异常”第二层评估“是否可套利”第三层才是执行。2. 整体方案设计与技术选型逻辑2.1 一条主流程从数据到信号的五段式架构我搭的系统整体流程可以概括成五个环节数据接入与清洗拿到干净的行情快照、逐笔成交、订单簿变化。特征计算与衍生把原始数据转成有统计含义的因子比如价差Z-score、订单失衡度、波动率、成交量突变率。异常检测用无监督模型对当前状态打分分越高代表越异常。套利评估过滤对异常信号做二次筛选只有同时满足定价偏差、可对冲、成本覆盖三条规则才进入机会池。风控与执行根据敞口上限、总资金、单笔止损条件确定是否触发下单。这个架构最大的好处是每一层可以独立迭代。我一开始异常检测模型用的是简单规则后来才换成机器学习模型套利评估一开始是固定阈值后来改成动态阈值。每一层单独改动不影响整体流程调试时非常方便。2.2 为什么先识别异常、再评估套利而不是直接预测方向我一开始尝试过直接训练模型预测价格未来5分钟的涨跌效果很差。原因很现实价格预测的样本极度不平衡收益信噪比极低模型很容易学到“一直不涨”这种假规律。后来我把问题拆成两步先识别异常再评估套利效果立刻不一样。因为“异常识别”是一个相对稳定的模式识别问题而“方向预测”是一个高噪声的时间序列外推问题两者难度不在一个量级。这样做还有一个额外价值可解释性。模型告诉你“当前价差偏离度超过历史99%的区间”这个是明确可验证的。但直接预测涨跌时模型输出一个方向和一个概率你根本不知道它依据什么。做交易决策时敢不敢下重仓依赖的就是这种可解释性。2.3 模型组合无监督为主、监督为辅、规则兜底在模型组合上我的选择是无监督异常检测为主力监督模型做简单过滤最后用一套规则引擎控制风险。用无监督而不是有监督核心原因是“异常”的样本极度稀缺历史上真正明确的套利机会可能一年也就几百次不足以训练一个稳定的分类器。而无监督模型只需要“正常数据”或“无标签数据”就能工作。监督学习在实际系统里只干一件小事给异常事件打一个“是否可参与”的粗筛标签。我用历史已经发生的异常事件和对应收益做标记训练一个二分类器把明显会亏钱或流动性不足的异常过滤掉。规则引擎则完全人工设计比如最大持仓时间、最大回撤容忍度、单一标的敞口上限。这三层互相补充缺一层都不稳。3. 数据与特征工程决定成败的命门3.1 数据源的层次与字段设计做异常识别和套利分析数据至少要分三个层次。第一层是行情快照包括每笔成交的现价、成交量、买卖一档价格与挂单量第二层是订单簿深度数据至少要看买卖五档第三层是时间序列数据包括分钟级OHLCV、资金流、持仓量变化。不同套利类型依赖的数据层次不同跨期套利主要靠快照和持仓量期现套利还要额外拿现货的基差信息。我的数据表结构大概长这样字段名含义用途ts时间戳精确到毫秒所有对齐操作的基础symbol标的合约标识区分品种和到期月份price最新成交价计算收益率和偏离度bid_price_1买一价计算买卖价差ask_price_1卖一价计算买卖价差bid_vol_1买一量判断流动性ask_vol_1卖一量判断流动性turnover累计成交额计算资金流open_interest持仓量判断多空力量这些字段听起来简单实际处理起来问题很多下面细说。3.2 数据清洗的四个常见坑第一个坑是停牌和涨跌停。停牌期间价格不动但数据源会填充旧价格导致偏离度计算失真。涨跌停时挂单大量堆积订单簿失衡度会异常极端必须单独标记不能当作普通异常处理。第二个坑是复权问题。股票有分红送股不复权的价格序列会在除权日出现巨大跳空这种跳空会被模型误判为异常。我的做法是统一使用前复权价格做特征计算同时保留原始价格做套利价差判断两套数据分开存放。第三个坑是时区与交易时段。不同市场的开盘收盘时间不同如果做跨市场套利必须把所有数据对齐到同一时区。我踩过一次亏凌晨时段的数据断了一小时没处理导致开仓判断用了过期的价差。第四个坑是幸存者偏差。回测时如果用当前还在交易的品种就会忽略已经退市或下架的品种导致策略看起来收益很高。正确做法是使用历史某时点实际存在的合约池这个细节虽然简单但影响极大。3.3 特征工程把原始数值变成模型能用的“异常探测器”特征是整个系统里我花时间最多的地方。我常用的特征分成三类。第一类是统计特征比如滚动收益率均值、滚动标准差、价格与均线的偏离度、成交量相对历史的分位数。第二类是微观结构特征比如买卖价差、订单簿不平衡度、大单成交占比、买卖主动成交比例。第三类是横截面特征比如个股相对行业指数的偏离度、同品种不同月份的价差Z-score、跨市场同一标的的价格比率。举个例子计算两个高度相关合约的价差Z-score逻辑很简单先算出两合约价格比的滚动均值再除滚动标准差得到一个标准化的偏离程度。当Z-score绝对值超过阈值时说明价差异常拉大存在回归的可能。代码如下import pandas as pd import numpy as np def calc_spread_zscore(price_a, price_b, window60): # 价差定义为A/B比值的对数 spread np.log(price_a / price_b) spread_mean spread.rolling(window).mean() spread_std spread.rolling(window).std() zscore (spread - spread_mean) / spread_std return zscore注意这里的window选择不能拍脑袋。窗口太短比如5分钟会把正常波动也当异常窗口太长比如240分钟又会错过快速回归的机会。我自己常用的方法是把多种窗口的Z-score都算出来让模型自己决定哪种尺度更有效而不是手工固定一个值。4. 核心模型与算法选型我为什么用这几个模型4.1 隔离森林效率最高的表格型异常检测器隔离森林这个算法的思路非常直观随机切分特征空间异常点因为离群通常只需要很少的切分次数就能被单独隔离出来。我拿订单簿失衡度、价差Z-score、成交量变化率这几列做输入训练一个隔离森林模型输出的分数越高代表越异常。选它是看中三个优点第一速度快实时流水线毫秒级出结果第二不需要标注数据第三对高维特征不敏感。和基于距离的算法相比它在特征多的时候不会因为“维度灾难”而严重退化。代码使用非常简练from sklearn.ensemble import IsolationForest model IsolationForest( n_estimators200, contamination0.01, # 预期异常比例 random_state42 ) model.fit(features) anomaly_score model.decision_function(features)4.2 自编码器适合序列数据的重构误差法隔离森林对表格特征效果不错但遇到时间序列特征就有点乏力因为序列在时间上的相关性被忽略了。于是我又加了一个自编码器先把序列特征压缩到低维的瓶颈层再重构出来重构误差越大说明这个时间点越偏离正常模式。你可以把它理解成一种“对正常模式的压缩记忆”。模型只见过正常的数据分布所以处理正常数据时重构误差会很小一旦出现从未见过的异常模式重构误差就会飙升。我用它处理逐笔成交的连续特征。自编码器需要训练训练数据要保证里面基本是正常数据混入太多异常会导致模型把异常也学进去。我用的是历史一段时间的窗口数据先人工剔除掉明显异常的时段再做训练效果更稳定。4.3 配对交易与协整把统计套利落地的传统武器异常检测负责“找问题”但具体能不能套利还得看定价关系。配对交易就是一套很成熟的统计套利框架找两只历史相关性极高的标的当它们的价差偏离均衡水平时做多低估的、做空高估的等价格回归后平仓获利。关键是要用协整检验而不是简单相关性。相关性只能说明两序列“走势像”协整才能说明它们之间是否有长期稳定关系。我通常用ADF检验去验证价差序列的平稳性from statsmodels.tsa.stattools import adfuller def test_cointegration(spread): result adfuller(spread, autolagAIC) # 返回的p值小于0.05说明价差序列平稳存在协整关系 return result[1]如果价差不平稳套利逻辑就不成立因为价格可能永远不会回归。这一步是套利评估里最刚性的一环我会对每一对候选标先跑协整检验通过才纳入机会池。4.4 进阶方向用图神经网络捕获跨资产联动如果你想把系统做得更复杂可以考虑用图神经网络。传统方法把标的看成独立的序列但市场标的之间是有联动关系的比如股指期货和成分股、上下游产业链品种。图神经网络可以把这种关系结构显式建模节点是标的边是相关系数或因果关系然后做异常传播检测。我在实验阶段试过用图模型同时处理几十个标的相关性确实能发现一些单标的视角下看不到的异常。但它的工程复杂度高训练和调参时间成本也高不建议作为第一版系统的核心模型。先把隔离森林和配对交易跑通再考虑图模型是更务实的路径。5. 实操过程从零搭一套异常识别与套利评估系统5.1 环境与数据准备我用的环境是Python 3.10 pandas scikit-learn statsmodels数据来自某交易所的Level-2快照接口和逐笔成交接口。先把原始数据落地到本地数据库做分钟级聚合建好一张行情特征宽表。宽表每行是一个“标的×时间”组合每列是一个特征字段。这一步的核心是保证数据的时间对齐。不同接口的数据到达时间有延迟做特征计算时必须按ts排序并去重。我的习惯是保留原始数据清洗后另建一张“清洗表”不在原表上改方便复盘时追溯问题。5.2 实现异常评分与实时告警异常检测模块的实操流程分三步离线训练、在线预测、告警输出。离线训练时我取过去60个交易日的特征数据训练隔离森林模型每天收盘后增量更新一次。在线预测时每秒对当前特征打分分数超过某个百分位阈值就触发告警。阈值怎么定不能拍脑袋选0.9或0.99。我用历史回放法取过去一年的异常分数分布画分位数曲线观察不同的阈值会产生多少次误报、抓住多少次有效机会然后选一个“误报率可接受、漏报率尽量低”的平衡点。这一步和交易系统一样必须结合成本来调。告警输出到统一的消息队列包含时间、标的、异常分数、关联特征值、触发阈值。后面套利评估模块会消费这个消息队列做二次检查。5.3 套利机会评估协整残差与开仓阈值进入套利评估后第一步是检查协整关系。对每一对候选标的我用最近一段时间的价格数据算对数价差跑ADF检验。只有p值小于0.05的才对进入下一步。接着计算当前价差Z-score并设定开仓阈值。这里有一个关键参数计算过程先根据历史价差分布算出标准差然后用“理论盈利空间 交易成本”来确定最小Z-score阈值。举个例子如果历史价差标准差是2元双边交易成本是1.5元那么Z-score至少要达到0.75价差偏离才可能覆盖成本。实际使用中我会留出安全边际把开仓阈值设在2.0左右也就是偏离达到两个标准差才开仓。平仓阈值则设置在0附近当Z-score回归到零附近就平仓。止损阈值设置在固定极限比如亏损达到单笔资金的2%强制平仓防止价差回归前继续扩大。5.4 回测与绩效评估别被漂亮曲线骗了回测是整个系统里最容易自欺欺人的环节。我见过太多人把手续费设得很低滑点设成零回测曲线漂亮得不行实盘一跑就亏。我的回测框架里成本参数是强制自定义的手续费按交易所实际标准滑点按平均买卖价差的一半模拟。回测报告我会重点看六个指标累计收益率、年化波动率、夏普比率、最大回撤、胜率、换手率。夏普比率很关键但最大回撤更重要——一个回撤超过30%的套利策略就算年化有20%实盘也很难拿住。另外换手率太高会警示成本敏感度说明策略可能在靠高频摩擦吃饭容量会很有限。从结果看我在沪深300成分股和高频期货合约上测试过这套系统。期货跨期套利的效果最好信号清晰、成本低股票统计套利的效果受涨跌停和停牌影响很大必须做更严格的过滤才能用。6. 常见问题与排查技巧实录6.1 异常信号太多一天触发几千次怎么过滤这是刚上线时最常遇到的问题。隔离森林把大量正常波动识别成了异常原因通常是特征分布发生了漂移或者contamination参数设得太高。我的排查步骤是这样先把所有触发信号打印出来看它们的特征分布是否集中在某几个特征上比如成交量突然放大的时刻特别容易触发。然后针对性地增加约束条件比如加一个“偏离度必须超过10日移动平均的2倍”这个硬规则。最后才是调整模型参数。先看数据再改规则最后调模型这个顺序不会错。6.2 模型在实盘失效回测好得很实盘一直亏这个问题的根源基本是交易成本估算不准或者样本外市场状态变化。套利策略赚的是定价偏差回归的钱一旦市场处于持续单边行情中价差可能长时间不回归策略就会一直亏损。我吃过一次大亏在某个品种的跨期套利上连续亏了半个月原因是基本面发生了结构性变化近远月价差中枢整体上移了。后来我在系统里加了一个“持仓过久即强制平仓”的机制并对价差中枢做滚动更新而不是用固定历史均值才算解决了这个问题。6.3 数据泄漏回测里包含了未来信息还不自知数据泄漏是回测结果虚高的头号原因。常见场景有三种用全样本计算的特征归一化参数套用到历史回测上用未来数据去选择品种涨跌停之后的成交记录没有剔除。排查方法是做“时间切片检查”随机抽某一天打印出当天的信号和特征值人工确认特征计算时只用了当天之前的数据。还有一个笨但可靠的方法写一个函数专门检查每个特征列在时间轴上是否有前视窗口及时发现异常。6.4 交易成本吃光利润怎么办价差偏离看着诱人扣完手续费、印花税、滑点之后可能所剩无几。这个问题必须在回测前就解决而不是回测之后。我的经验是用“收益覆盖成本比值”作为过滤标准比值低于1.5的统统不开仓。同时尽量选择流动性好的标的开仓时间避开开盘和收盘那段价差波动剧烈但成交成本高的时段。6.5 风控系统怎么兜底再好的模型也需要风控兜底。我设了四道硬性限制单一标的最大持仓不超过总资金的5%套利组合总敞口不超过20%单笔最大亏损不超过账户权益的1%每日最大亏损达到2%就暂停当日交易。实盘当中最容易被忽视的是流动性风控。价差回归策略正常时还好一旦遇到极端行情你想平仓都平不出去。所以我在每个套利信号里都加了“当前买卖盘深度是否足够”这一条盘口五档挂单量不足以容纳目标交易量直接跳过。写到这里想聊聊实盘中体会最深的一点这套系统的核心价值不在于模型多先进而在于每一层都在做减法。异常检测保住了真正有价值的信号套利评估滤掉了不可执行的信号风控兜住了模型判断错误的概率。用AI辅助识别市场异常与套利机会最终比的是谁把细节做得更扎实、把成本算得更清楚、把风险管得更严。我自己还在持续迭代特征库和模型层下一步计划加入更多多维度的市场微观结构数据。如果你也在做类似方向记住一句话先跑通简单的再谈复杂的先亏得起小钱再上大仓位。