2. 最小距离法配对选择
任务目标
给定一个包含若干股票历史收盘价的股票池,使用最小距离法(Minimum Distance Method)计算所有可能股票对的价格距离,筛选出距离最小的前N对作为候选配对。距离定义为两只股票价格序列经标准化后,逐日价差平方和的均值。
实现思路
最小距离法的核心逻辑:对每只股票的价格序列做z-score标准化(减去均值除以标准差),使不同价格量级的股票可比;然后对每一对股票计算标准化价格差的平方和均值,即为该对的"距离"。距离越小,说明两只股票的历史相对走势越同步,越适合作为统计套利配对。
完整代码
import numpy as np
import pandas as pd
from itertools import combinations
def min_distance_pair_selection(price_df, top_n=3):
"""
最小距离法筛选配对股票
Parameters
----------
price_df : pd.DataFrame
每列为一支股票的历史收盘价,索引为日期
top_n : int
返回距离最小的前N对
Returns
-------
pd.DataFrame
包含列:pair(股票对), distance(距离值)
"""
# 1. z-score标准化每列价格
norm_df = (price_df - price_df.mean()) / price_df.std()
# 2. 计算所有股票对的距离
stocks = price_df.columns
results = []
for s1, s2 in combinations(stocks, 2):
diff = norm_df[s1] - norm_df[s2]
dist = (diff ** 2).mean()
results.append((f"{s1}-{s2}", dist))
# 3. 按距离升序排序,取前top_n
result_df = pd.DataFrame(results, columns=["pair", "distance"])
result_df = result_df.sort_values("distance").head(top_n).reset_index(drop=True)
return result_df
# ========== 最小可复现示例 ==========
if __name__ == "__main__":
# 构造5支股票、120个交易日的模拟价格数据(随机游走)
np.random.seed(42)
dates = pd.date_range("2023-01-01", periods=120, freq="D")
stocks = ["A", "B", "C", "D", "E"]
price_data = {}
for stock in stocks:
# 随机游走生成价格序列
returns = np.random.normal(0.001, 0.02, len(dates))
price = 100 * np.exp(np.cumsum(returns))
price_data[stock] = price
df = pd.DataFrame(price_data, index=dates)
# 运行最小距离法
top_pairs = min_distance_pair_selection(df, top_n=3)
print("距离最小的前3对股票:")
print(top_pairs.to_string(index=False))
运行方式
环境要求:Python 3.7+,安装 numpy 和 pandas。将上述代码保存为 min_distance.py,在终端执行:
python min_distance.py
验证方法
程序正常执行后,终端会输出一个表格,包含3行数据,每行包含"pair"(股票对名称)和"distance"(距离值)。判定通过的观察点:
- 输出恰好3对股票,且距离值按升序排列(第一行距离最小);
- 所有股票对名称均由示例中的股票代码(A-E)两两组合而成,无重复、无缺失;
- 距离值均为非负浮点数(因为平方和均值必然≥0)。
如需验证算法正确性,可手动检查:将任意两只股票的价格序列分别做z-score标准化后,逐日计算差值的平方并求平均,结果应与程序输出一致。
关键说明
本实现使用随机游走生成模拟价格数据,仅用于演示算法流程。实际使用时,将 price_df 替换为真实行情数据(每列一支股票、每行一个交易日)即可。标准化步骤是必要的——若不标准化,高价股的价差会主导距离计算,导致筛选结果偏向价格值相近的股票,而非走势同步的股票。