Python 自动化统计套利全流程:手把手示例与避坑指南

·

统计套利(statistical arbitrage,简称 “统套”)是一种利用证券历史价格之间的统计关系寻找价差、低风险获利的市场中性策略。传统手工回测动辄几天,实盘切换更是手忙脚乱,而 Python 自动化 可以在几分钟内屏蔽人为误差、全天候追踪价差信号。本指南用完整代码片段与场景化示例,帮你从 0 到 1 搭起一套可复用框架。

注意:本文仅为技术分享,不构成任何投资建议。实操前须充分回测、风控和合规审查。

1. 统套策略核心关键词


2. 第一步:高质量数据抓取

若无干净数据,策略再精妙也会翻车。以下两种主流方案可并行使用:

  1. 免费源
    yfinance:快速拉取美股日频 20 年历史 OHLC。
    pandas-datareader:穿透 FRED、IEX、Stooq 等接口获取宏观指标。
  2. 付费或机构级
    • 交易所授权 Level-2 Tick Data
    • 通过 RESTful API 每日增量更新

示例代码(yfinance + 多线程加速):

import yfinance as yf
import pandas as pd
from concurrent.futures import ThreadPoolExecutor

tickers = ['AAPL', 'MSFT', 'GOOG']
start = '2018-01-01'
def fetch(t):
    return yf.download(t, start=start, progress=False)['Adj Close']

with ThreadPoolExecutor() as ex:
    prices = pd.concat(ex.map(fetch, tickers), axis=1, keys=tickers)
prices.to_parquet('prices.parquet')    # 压缩存储

通关口令:将 prices.parquet 重采样成小时或周频,可减少噪声并节省算力。


3. 第二步:协整检验,锁定价差序列

协整≠相关,只有价差具有均值回归属性的币种或股票对才能参与统套。流程如下:

  1. 取 1000 行以上历史价,利用 Engle-Granger 方法做两只证券的协整检验
    coint 函数 p-value < 0.05 视为有效
  2. 计算对冲比率 β:在 OLS 回归 price_A ~ price_B 中取回归系数
  3. 构造价差项:
    spread = price_A − β * price_B

代码片段(基于 statsmodels):

from statsmodels.tsa.stattools import coint
import statsmodels.api as sm

A = prices['AAPL'].dropna()
B = prices['MSFT'].dropna()
score, pvalue, _ = coint(A, B)
if pvalue < 0.05:
    model = sm.OLS(A, sm.add_constant(B)).fit()
    beta = model.params[1]
    spread = A - beta * B

4. 第三步:Z-score 信号与阈值调参

4.1 Z-score 计算

span = 60
mean = spread.rolling(span).mean()
std  = spread.rolling(span).std()
zscore = (spread - mean) / std

4.2 经典双阈值

z-score动作
< -2价差低估,做多 spread
> +2价差高估,做空 spread
0±0.5平仓

👉 15 分钟教你自己滚动优化阈值,胜率暴涨 8%

经验:在高波动季(财报、议息会议)把 span 调短至 20 根 K,可捕捉短线闹情绪信号。


5. 第四步:委托与仓位管理自动化

ib-insyncccxt 等库连接经纪商 API,实现毫秒级挂撤单。重点函数:

  1. 成交后同步仓位表
  2. 发行 trailing stop 防极端行情
  3. 每日收盘前,优先保证净敞口 0%(市场中性)

6. 第五步:回测框架 = 实盘缩时模型

backtrader 可无缝复用前面价差公式:

class StatArb(bt.Strategy):
    params = dict(z_entry=2.0, z_exit=0.5, window=60)

    def next(self):
        if self.zscore < -self.p.z_entry:
            self.buy_spread()
        elif self.zscore > self.p.z_entry:
            self.sell_spread()
        elif abs(self.zscore) < self.p.z_exit:
            self.close_spread()

跑完 5 年历史数据后:

👉 一键下载完整回测报告与最优参数表


7. 实战避坑指南

雷区原因解决方案
幸存者偏差历史上被退市证券不在数据库里用存活列表 + delisted 档案双重回测
期货合约换月跳空价格断层毁掉协整系数换月前对价差重新β校准
成交滑点高频调仓导致磨损设定 limit 单或 Envelope 1tick

8. 场景演练:50ETF vs 300ETF 日内套利

两条 ETF 同属大盘,高相关性(R≈0.92)。2022/03/15 某个开盘 30 分钟内:

把该场景写进脚本后,配合 Job Scheduler(如 Airflow)即可触发每日回放,自动推送微信或 Webhook 提醒。


9. FAQ:频繁被问到的 5 个问题

Q1:协整检验通不过就一定没机会吗?
A:不是的。可尝试延长时间窗口或改用 卡尔曼滤波 动态 β,价差也会收敛。

Q2:多品种组合如何提升夏普?
A:在同类别资产池里(能源、芯片等)生成所有两两组合,用 k-means 聚类 Steady 组,再跑 meta-selection 过滤噪声组。

Q3:Python 速度瓶颈怎么办?
A:将 z-score 计算移入 numba JIT;复杂循环写成向量化;实盘可转向 Cython 或 rust 编写的桥接。

Q4:回测时已考虑手续费,实盘为何总差一点?
A:滑点和 Volume Impact 没纳入,金字塔加减仓时盘口深度衰减会放大成本。

Q5:指数基金禁止日内反向交易怎么办?
A:用场内 ETF + 期货对冲 规避反向限制,风控设置持仓警报即可。


10. 小结与下一步

把整套代码打包成 Docker Image,周末 2 小时即可复刻并开始全自动统计套利之旅。祝你交易顺利,也欢迎围观后续「Python 量化笔记」分享更多实战套路。