一句话回答: 配对交易就是"赌两只相关股票的价差会回归"。用 AlphaFeed 的 klines.batch 一次取两只票的复权日线,用最小二乘算对冲比率、构造对数价差、标准化成 z-score:z 太高做空价差、太低做多价差、回归到 0 附近平仓。几十行即可回测。但要先说清一个硬伤——A 股个股做空受限,配对交易在 A 股落地并不容易。
为什么会有这个问题 / 传统做法的痛点
配对交易(统计套利)是经典的市场中性策略:找两只走势高度相关的票(如同业两家银行),当它们的价差偏离历史均值时反向下注,赌它回归。它对方向不敏感、理论上能对冲大盘风险,因此很受量化爱好者欢迎。
难点在:① 要同时、对齐地拿到两只票的复权价;② 要把"价差"标准化成可比的信号(z-score);③ 回测不能有未来函数。AlphaFeed 的批量接口解决取数与对齐,剩下的用 numpy 就能算。
分步骤解决(每步配可运行代码)
第 1 步:批量取两只票的复权日线并对齐
import numpy as np, pandas as pd
from alphafeed import AlphaFeed
def load_pair(a, b, count=250):
af = AlphaFeed() # 读取 ALPHAFEED_API_KEY
bt = af.klines.batch([a, b], period="1d", count=count,
adjust="forward", to_dataframe=True) # {symbol: DataFrame}
pa = bt[a].sort_values("trade_date").set_index("trade_date")["close"]
pb = bt[b].sort_values("trade_date").set_index("trade_date")["close"]
return pd.concat([pa.rename("a"), pb.rename("b")], axis=1).dropna() # 按交易日对齐
df = load_pair("601398.SH", "601939.SH", count=250) # 工商银行 / 建设银行
第 2 步:算对冲比率、对数价差与 z-score
def spread_z(df, win=60):
la, lb = np.log(df["a"]), np.log(df["b"])
beta = float(np.polyfit(lb, la, 1)[0]) # 对冲比率(最小二乘斜率)
spread = la - beta * lb # 对数价差
z = (spread - spread.rolling(win).mean()) / spread.rolling(win).std()
out = df.copy(); out["spread"] = spread; out["z"] = z
return out, beta
out, beta = spread_z(df, win=60)
print(f"对冲比率 beta={beta:.3f} 最新 z={out['z'].iloc[-1]:.2f}")
第 3 步:z-score 均值回归回测(严格无未来函数)
def backtest_pairs(out, entry=2.0, exit=0.5):
z = out["z"].values
pos, positions = 0, []
for zi in z:
if np.isnan(zi):
positions.append(0); continue
if pos == 0:
if zi > entry: pos = -1 # 价差偏高 → 做空价差(卖A买B)
elif zi < -entry: pos = 1 # 价差偏低 → 做多价差(买A卖B)
elif abs(zi) < exit:
pos = 0 # 回归到均值附近 → 平仓
positions.append(pos)
out = out.copy()
out["pos"] = pd.Series(positions, index=out.index).shift(1).fillna(0) # 信号次日生效
out["pnl"] = out["pos"] * out["spread"].diff() # 价差日收益
trades = int((out["pos"].diff().abs() > 0).sum())
return out, round(float(out["pnl"].sum()), 4), trades
_, pnl, trades = backtest_pairs(out)
print(f"价差累计收益(对数单位)={pnl} 交易次数={trades}")
真实跑通(601398.SH / 601939.SH,近 250 日):beta=0.347、最新 z=1.14、价差累计收益约 +0.028(对数单位)、7 次交易。收益很小——这正说明这段时间两者价差并没有提供多少可套利的偏离,符合"高相关但未必值得交易"的常态。
参数与字段说明
| 参数 | 含义 | 备注 |
|---|---|---|
klines.batch |
批量日线 | 返回{symbol: DataFrame},按 trade_date 对齐 |
beta |
对冲比率 | 全样本 OLS 斜率,教学用;实盘应滚动估计 |
win |
z-score 窗口 | 60 日;决定"均值/波动"的参考期 |
entry/exit |
开/平仓阈值 | 常用开 2.0、平 0.5(个标准差) |
pos.shift(1) |
信号次日生效 | 避免未来函数 |
关键坑与注意事项
- A 股做空是硬伤:配对交易要求"一多一空"。A 股个股融券标的有限、成本高、常无券可融,散户很难真正做空个股。落地更现实的路径是:用可融券标的、股指期货、或两只 ETF 做价差,或只做"价差偏低时买入被低估的一方"这类单边变体。本文回测是方法演示,不代表 A 股可直接照搬。
- 相关 ≠ 协整:两只票相关不代表价差会回归。严谨做法要做协整检验(如 ADF 检验,需
statsmodels)并定期复检;相关性会漂移甚至断裂(基本面变化、重组)。 - 对冲比率会变:
beta用全样本 OLS 只是教学,实盘应滚动窗口估计,且注意滚动 beta 本身带来的不稳定。 - 成本未计:示例只算价差收益,未计佣金、印花税、融券利息与滑点;高频开平会显著侵蚀这类微利策略。
- 无未来函数:已用
pos.shift(1),即"今天的 z 决定明天的持仓"。别用当日 z 当日成交。
常见问题(FAQ)
Q:配对交易能对冲大盘风险吗?
A:理论上多空对冲后对大盘中性,但前提是价差真的均值回归、且对冲比率稳定。一旦协整关系断裂,两腿可能同向亏损,并非无风险。
Q:怎么选配对?
A:先从同行业、业务相近的票里找高相关对(如两家银行/两家白酒),再做协整检验筛掉"只是相关"的对。不要纯靠相关系数拍板。
Q:A 股不能做空,这策略还有意义吗?
A:有认知与研究价值;落地要换载体——可融券标的、ETF 对、或期货,或做成"低估买入 + 到均值卖出"的单边版本。务必先解决"另一条腿怎么空"。
Q:需要付费吗?
A:两只票的历史批量可用免费额度体验;大规模筛选配对、全市场批量需 Starter 及以上,详见官网定价页。
小结
配对交易的骨架很简单:批量取复权价 → 算对冲比率与对数价差 → 标准化成 z-score → 均值回归回测。AlphaFeed 的 klines.batch 让取数与对齐变得轻松。但真正决定它能否落地的,是那些诚实的前提:协整而非仅相关、滚动对冲比率、交易成本,以及 A 股个股做空的现实限制。先把这些想清楚,再谈能不能赚。
参考
- AlphaFeed Python SDK 文档:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart

