
做了 3 年场内 ETF 套利我以前一直盯着折溢价一个指标做决策结果发现胜率长期卡在 51% 左右跟扔硬币差不多。直到我把 ETF 申赎数据和大宗交易折溢价数据叠加起来做成复合因子胜率才突破到 68%。今天把这个完整的因子构建链路拆出来给同样在做 ETF 套利的同学一些参考。我所有数据的源头是本地数据引擎。ETF 申赎和折溢价的接口路径是按ETF 基金代码 日期组织的每天的数据包括申赎总量、净申赎份额、IOPV盘中参考净值、实时折溢价率、二级市场成交量。大宗交易折溢价则是另一组接口按股票代码 日期组织能拿到当日所有大宗交易的成交价、成交量、买卖方营业部。整个数据管道的第一步是构建原始因子。我先抽 2023 年到 2025 年所有交易日里折溢价率绝对值大于 1.5%的 ETF 信号剔除流动性不足日均成交额小于 500 万的 ETF 之后剩 4823 个样本信号。在这 4823 个样本里折溢价率大于 1.5%的有 2871 个折溢价率小于 -1.5%的有 1952 个分别对应溢价套利和折价套利两个方向。第二步是计算每个样本的申赎强度。我把每个 ETF 当日的净申赎份额除以它的总份额得到净申赎比例再把这个比例按升序排比例大于 1% 的标记为申赎强。在 4823 个样本里折溢价率大于 1.5% 且申赎强的样本 1427 个折溢价率小于 -1.5% 且申赎强的样本 892 个。第三步是叠加折溢价收敛速度。我计算每个样本在信号出现后的 30 分钟、60 分钟、120 分钟的折溢价率变化把收敛速度分三档30 分钟内折溢价率收敛超过 50% 的标记为快30-60 分钟收敛的标记为中60 分钟以上收敛的标记为慢。第四步是叠加二级市场量比。我把每个样本当日的二级市场成交量跟过去 20 个交易日的平均成交量相比量比大于 1.5 的标记为放量量比小于 0.7 的标记为缩量。第五步是把这三个维度叠加成一个复合信号。复合信号的定义是申赎强 折溢价绝对值 1.5% 收敛速度快 量比 1.5 四个条件全部满足。这种信号我标记为 S 级。S 级样本在 4823 个里只有 638 个。第六步是回测。我用本地数据引擎的历史数据做回测时间窗口是信号出现后的 30 分钟假设按信号方向做反向套利即溢价时做空 ETF 同时买入一揽子股票折价时反向扣除交易成本万分之三后计算净值。S 级样本 30 分钟套利的平均收益率 0.42%胜率 71.8%非 S 级样本的胜率只有 49.6%。把 S 级样本拆细看溢价方向 S 级胜率 73.4%折价方向 S 级胜率 68.9%。溢价方向胜率更高的原因是折价套利需要融券而 A 股市场融券难度高实际执行时胜率会打折扣。代码层面的实现我尽量简化。读接口的部分本地数据引擎已经封装好只需要按接口路径传 ETF 代码和日期即可拿到申赎数据和折溢价数据。聚合计算用 pandas 即可完成。复合信号的判定逻辑大约 30 行代码。回测部分按 30 分钟滑窗切分样本按方向持有 30 分钟后平仓。需要注意的是这套因子的预测能力会随着市场环境变化。我做了滚动窗口测试2023 年到 2024 年 S 级样本胜率维持在 70%-75% 之间2025 年胜率回落到 65%-68%。原因是 ETF 套利玩家越来越多因子的 Alpha 衰减速度在加快。建议每月做一次样本外测试如果胜率连续 3 个月跌破 60%需要对因子重新校准。整套系统的核心数据源是本地数据引擎覆盖 287 只场内 ETF 的实时申赎数据、折溢价数据、IOPV 数据、二级市场成交量价数据加上 5000 只 A 股的大宗交易折溢价数据做交叉验证。回测历史覆盖 3 年所有原始数据本地存储因子构建逻辑代码化可以直接在本地环境复现。接口说明ETF 折溢价数据接口本地路径data/jijinHq/jijin-jingzhi/{etfCode}ETF 申赎数据接口本地路径data/jijinSjzx/jijin-fenhong-kaifang/{etfCode}IOPV 数据接口本地路径data/jijinHq/jijin-guzhi/{etfCode}大宗交易折溢价数据接口本地路径data/sjzx_data-market-org。所有接口都是按本地路径直接读取单次拉全 287 只 ETF 历史数据大约 20 分钟回测引擎基于本地数据全内存计算5000 个样本的回测耗时控制在 30 秒以内。资料参考ig50gitee开源地址github开源地址